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…