Can someone explain why these at their core identical scripts are working differently?

So, I’m making this game where players are in rounds of 4 and there will be a line of players to get in if the squares are full, so basically I created a rough system of how I wanted it work and I’ve tested almost every scenario and it’s working exactly how it should

local queue = {}
local squares = {}

local function getLengthOfDictionary(dict)
   local count = 0
   for _ in pairs(dict) do
      count = count + 1
   end
   return count
end

local function GetHighestAvailableSquare()
   -- Set of all possible squares
   local allSquares = {1, 2, 3, 4}
   
   -- Get list of occupied squares
   local occupiedSquares = {}
   for _, squareNum in pairs(squares) do
      table.insert(occupiedSquares, squareNum)
   end

   -- Find highest available square
   for i = #allSquares, 1, -1 do
      local currentSquare = allSquares[i]
      local isOccupied = false
      
      for _, occupiedSquare in ipairs(occupiedSquares) do
         if occupiedSquare == currentSquare then
            isOccupied = true
            break
         end
      end
      
      if not isOccupied then
         return currentSquare
      end
   end
   
   return nil -- Return nil if no squares are available
end

local function addPlayerToSquare(player, squareNum)
   squares[player] = squareNum
end

local function addPlayerToQueue(player)
   table.insert(queue, player)
end

local function handlePlayerOut(player)
   -- Remove the player from the squares
   print(player .. " got out")
   local playerWhoGotOutSquare = squares[player]
   squares[player] = nil

   -- If there is no players in the squares then fill them from highest to lowest
   if getLengthOfDictionary(squares) == 0 then
      while #queue > 0 do
         local nextPlayer = table.remove(queue, 1)
         local highestAvailableSquare = GetHighestAvailableSquare()
         addPlayerToSquare(nextPlayer, highestAvailableSquare)
      end
      local highestAvailableSquare = GetHighestAvailableSquare()
      if highestAvailableSquare then
         addPlayerToSquare(player, highestAvailableSquare)
      else
         addPlayerToQueue(player)
      end
   else
       --[[
      
      
         If there are players in the squares then
         1. Move those players + 1 square
         2. Process the queue
         3. Proccess the player that got out
         
         
      ]]

      -- Move all players in the squares + 1 square

      for player, squareNum in pairs(squares) do
         if squareNum > playerWhoGotOutSquare then
            continue
         end
         squares[player] = squareNum + 1
      end

      -- Process the queue
      while #queue > 0 do
         local nextPlayer = table.remove(queue, 1)
         local highestAvailableSquare = GetHighestAvailableSquare()
         if highestAvailableSquare then
            print("Adding " .. nextPlayer .. " to square " .. highestAvailableSquare)
            addPlayerToSquare(nextPlayer, highestAvailableSquare)
         else
            addPlayerToQueue(nextPlayer)
            break
         end
      end

      -- Process the player that got out
      local highestAvailableSquare = GetHighestAvailableSquare()
      if highestAvailableSquare then
         addPlayerToSquare(player, highestAvailableSquare)
      else
         addPlayerToQueue(player)
      end
   end

   print(squares)
   print(queue)
end


addPlayerToSquare("Player1", 2)
addPlayerToSquare("Player2", 4)
addPlayerToSquare("Player3", 3)

handlePlayerOut("Player3")

In essence, when a player gets out, I remove them from the squares table by assigning their key to nil, and then I check whether or not theres players that need to be shifted, if there arent then I grab players from the queue and put them at the highest available position, if there is then I shift those players from the square they are at + 1, after every player has been shifted now I can handle the players waiting in the queue and assign them the highestAvailableSquare if there is one, and if there isnt then I’ll reinsert them into the queue, after ive processed all the players from the queue, then its time to finally handle the player that got out, so I again get the highestAvailableSquare if there is one and I put the player who got out there, but if there isnt one available then I would enqueue them

The example scenario at the bottom is when Player1 → Square 2
Player2 → Square 4
Player3 → Square 3

Which means the highestavailablesquare would be 1

so then we call the handle player out function on player 3, so what this effectively should do is shift the players into these new square positions

Player1 → Square 3
Player2 → Square 4
Player3 → Square 2

So player 1 would take Player3’s previous squares place, and Player 2 would stay in Square 4 because theres no need to move, and Player3 would go to the highestavailablesquare which in this case would be Square2, leaving Square1 empty

And this is all working fine in great in this script, there is many other scenarios ive tested and they all put the players at the correct positions and handle everything perfectly

But the problem arises in my second script… where I have the exact same logic but for some reason shifting isnt working how it should

local function handlePlayerOut(player, playerWhoGotOutSquareBackup)
   Replicator._Set("RoundInProgress", false)
   CurrentTimer:StopTimer()

   serverBall:Destroy()
   actualBall:Destroy()

   local squares = Replicator.Get("SquaresOccupied")
   squares[player] = nil

   local playerWhoGotOutSquare = tonumber(playerWhoGotOutSquareBackup)

   print(player.. " from Square "..playerWhoGotOutSquare.." has got out!")

   if GetLengthOfDictionary(squares) == 0 then
      while #Line.queue > 0 do
         local nextPlayer = Line:Dequeue()
         local highestAvailableSquare = GetHighestAvailableSquare()
         squares[nextPlayer] = highestAvailableSquare
         local character = game.Players:FindFirstChild(nextPlayer).Character
         character:PivotTo(CFrame.lookAt(Area[tostring(highestAvailableSquare)].Position, Vector3.new(centerOfAllSquares.X, Area[tostring(highestAvailableSquare)].Position.Y, centerOfAllSquares.Z)))
      end
      local highestAvailableSquare = GetHighestAvailableSquare()
      if highestAvailableSquare then
         squares[player] = highestAvailableSquare
         local character = game.Players:FindFirstChild(player).Character
         character:PivotTo(CFrame.lookAt(Area[tostring(highestAvailableSquare)].Position, Vector3.new(centerOfAllSquares.X, Area[tostring(highestAvailableSquare)].Position.Y, centerOfAllSquares.Z)))
      else
         addPlayerToQueue(game.Players:FindFirstChild(player))
      end
   else
      for plr, squareNum in pairs(squares) do
         if squareNum > playerWhoGotOutSquare then
            continue
         end
         squares[plr] = squareNum + 1
         local character = game.Players:FindFirstChild(plr).Character
         character:PivotTo(CFrame.lookAt(Area[tostring(squareNum + 1)].Position, Vector3.new(centerOfAllSquares.X, Area[tostring(squareNum + 1)].Position.Y, centerOfAllSquares.Z)))
      end

      while #Line.queue > 0 do
         local nextPlayer = table.remove(Line.queue, 1)
         local highestAvailableSquare = GetHighestAvailableSquare()
         if highestAvailableSquare then
            print("Moving "..nextPlayer.." to square "..highestAvailableSquare)
            squares[nextPlayer] = highestAvailableSquare
            local character = game.Players:FindFirstChild(nextPlayer).Character
            character:PivotTo(CFrame.lookAt(Area[tostring(highestAvailableSquare)].Position, Vector3.new(centerOfAllSquares.X, Area[tostring(highestAvailableSquare)].Position.Y, centerOfAllSquares.Z)))
         else
            print("Adding "..nextPlayer.." to the queue, no squares available")
            addPlayerToQueue(nextPlayer)
            break
         end
      end

      local highestAvailableSquare = GetHighestAvailableSquare()
      if highestAvailableSquare then
         print("Moving who got out to square "..highestAvailableSquare)
         squares[player] = highestAvailableSquare
         local character = game.Players:FindFirstChild(player).Character
         character:PivotTo(CFrame.lookAt(Area[tostring(highestAvailableSquare)].Position, Vector3.new(centerOfAllSquares.X, Area[tostring(highestAvailableSquare)].Position.Y, centerOfAllSquares.Z)))
      else
         print("Adding playe who got out to the queue, no squares available")
         addPlayerToQueue(game.Players:FindFirstChild(player))
      end
   end

   Replicator._Set("NumberOfHitsOnBall", 0)
   Replicator._Set("SquaresOccupied", squares)
   Replicator._Set("RoundInProgress", true)
   Replicator._Set("LastSquareHit", tostring(4))

   print(Replicator.Get("SquaresOccupied"))
end

Major Note

It works perfectly when handling 2 players in a square or when one player is in square 4 and the other one is inside of the the line/queue, but when I get to 3 players, when I get the player that was in square 3 out like in the test scenario earlier its shifting everyone but its moving the person who was in square 3 to square 4, which a player is already in, and the person who was behind the person who shifted to square 4 is now in square 3…

Visual Testing Screensots (chronological)

1. Game starts with Player 1 in Square 4 (highest), Player 2 inside of the queue

2. Player 1 hits the ball out of bounds moves to the highestAvailableSquare AFTER Player 2, Player 2 moves to the HighestAvailableSquare (4)

3. Player 3 has arrived to the battlefield, Player 2 and Player 1 are still in there same squares

4. Player 2 hits the ball out of bounds, this shifts Player 3 to Square 3, and Player 1 to Square 4, and finally it shifts Player 2 to the highestAvailableSquare which in this case would be 2

5. Player 1, is about to get Player 3 out

6. Diaster (I also got Player1 out by accident so it shifted everyone and put them last)

2 Likes

Alright so, I scrapped all that code and I just went as basic as possible because they way I wanted this to work was super specific so I had to make the code super specific, it ended up working!

If you’re having problems or bugs just remember try to create the most basic version without all that clutter first!

1 Like