I am making an automatic 1v1 arena where players can enter by stepping onto one of the platforms. There are two regions on the platforms, one for each opponent. If both regions are occupied by a player, the match starts and the player who survives wins. I ran into a problem late into scripting, though. If a player steps into an occupied region and the player who was in that region steps out, then the arena thinks that the player who just stepped out is still in the region. And if that player goes to the other region, they can start a 1v1 with themselves.

I intend that the first player who entered a region should be replaced by the second player in the region when the first player steps out. I tried fixing this myself but ran into a dead-end shortly. The following script is my last attempt at fixing this, which only made it a bit worse by making it possible to steal someone's place in a region.

Note: The PlayerMoved bindable event (script.Parent.PlayerMoved:Fire()) should be fired whenever a player enters or leaves a region.

local arena = script.Parent
local display = arena.Display.SurfaceGui.Frame
local player1 = arena.Player1
local player2 = arena.Player2
local gamestate = "Idle"
local debounce = false

local RegionPart1 = workspace.AutoArena:WaitForChild("RegionPart1")
local RegionPart2 = workspace.AutoArena:WaitForChild("RegionPart2")
local Region1 = Region3.new(RegionPart1.Position - (RegionPart1.Size/2),RegionPart1.Position + (RegionPart1.Size/2))
RegionPart1:Destroy()
local Region2 = Region3.new(RegionPart2.Position - (RegionPart2.Size/2),RegionPart2.Position + (RegionPart2.Size/2))
RegionPart2:Destroy()

spawn(function()
	while wait(0.5) do
		if not (arena.GameReady.Value or debounce) then
			local region1parts = workspace:FindPartsInRegion3(Region1,workspace.AutoArena.Button1,math.huge)
			local region2parts = workspace:FindPartsInRegion3(Region2,workspace.AutoArena.Button2,math.huge)
			local currentplayer1 = nil
			local currentplayer2 = nil
			for i, part in pairs(region1parts) do
				if game.Players:FindFirstChild(part.Parent.Name) ~= nil then
					if game.Players[part.Parent.Name].Character == part.Parent then
						currentplayer1 = game.Players[part.Parent.Name].Name
						if player1.Value ~= game.Players[currentplayer1] then break end
					end
				end
			end
			for i, part in pairs(region2parts) do
				if game.Players:FindFirstChild(part.Parent.Name) ~= nil then
					if game.Players[part.Parent.Name].Character == part.Parent then
						currentplayer2 = game.Players[part.Parent.Name].Name
						if player2.Value ~= game.Players[currentplayer2] then break end
					end
				end
			end
			if player1.Value == nil then
				if currentplayer1 ~= nil then
					player1.Value = game.Players[currentplayer1]
					print(player1.Value.Name.." entered")
					script.Parent.PlayerMoved:Fire()
				end
			end
			if player1.Value ~= nil then
				if player1.Value ~= game.Players[currentplayer1] then
					print(player1.Value.Name.." left")
					player1.Value = nil
					script.Parent.PlayerMoved:Fire()
				end
			end
			if player2.Value == nil then
				if currentplayer2 ~= nil then
					player2.Value = game.Players[currentplayer2]
					print(player2.Value.Name.." entered")
					script.Parent.PlayerMoved:Fire()
				end
			end
			if player2.Value ~= nil then 
				if player2.Value ~= game.Players[currentplayer2] then
					print(player2.Value.Name.." left")
					player2.Value = nil
					script.Parent.PlayerMoved:Fire()
				end
			end
		end
	end
end)