Any changes to the logic of this tournament system?

Hello! I am working on a sword fighting tournament game where 2 players are randomly picked to fight until there is a winner. This system is meant to work with any of players, and also accounts for byes. Keep in mind I have removed a lot of code that is unrelated to the logic, such as how I deal with the winner of the tournament, as well as setting the Status attribute of players. I have also left out FightService as it also doesn’t deal much with the tournament logic.

local Players = game:GetService('Players')

local FightService = require(script.Parent.FightService)

local TournamentService = {
        Bracket = {}
}

function TournamentService:GenerateRound(Contestants)
	local Round = {}

	for _ = 1, math.ceil(#Contestants / 2) do
        local ContestantCount = #Contestants

		if ContestantCount > 1 then
			local Fighter1 = Contestants[math.random(ContestantCount)]
			local Fighter2 = Contestants[math.random(ContestantCount)]

			while Fighter2 == Fighter1 do
				Fighter2 = Contestants[math.random(ContestantCount)]

				task.wait()
			end

			table.insert(Round, {
				Fighter1,
				Fighter2
			})

			table.remove(Contestants, table.find(Contestants, Fighter1))
			table.remove(Contestants, table.find(Contestants, Fighter2))
		elseif ContestantCount == 1 then
			Round.Bye = {Contestants[1]}
		end
	end

	table.insert(self.Bracket, Round)

	return Round
end

function TournamentService:TournamentLoop()
	local Contestants = table.clone(self.Contestants)
	
	while #Contestants > 1 do
		local Winners = {}
		local Round = self:GenerateRound(Contestants)

		for _, Fighters in Round do
			local Winner = FightService:StartFight(Fighters)
			
			if Winner then
				table.insert(Winners, Winner)
			end
		end
		
		Contestants = Winners
	end
end

function TournamentService:StartTournament()
	self.Contestants = Players:GetPlayers()
	
	self:TournamentLoop()
end

function TournamentService:EndTournament()
    self.Contestants = nil

	table.clear(self.Bracket)
end

function TournamentService:RemovePlayer(Player)
	local Round = self.Bracket[self.RoundIndex]
	
	for FightIndex, Fight in Round do
		for Index, Fighter in Fight do
			if Player ~= Fighter then
				continue
			end

			table.remove(Fight, Index)

			if not next(Fight) then
				if type(FightIndex) == 'number' then
					table.remove(Round, FightIndex)
				else
					Round[FightIndex] = nil
				end

				return
			end

			local Fighter = Fight[1]

			if Fighter and Fighter:GetAttribute('Status') ~= 'Fighting' then
				if Round.Bye then
					table.insert(Fight, Round.Bye[1])

					Round.Bye = nil
				else
					Round.Bye = {Fighter}

					table.remove(Round, FightIndex)
				end
			end
		end
	end
end

return TournamentService
local Players = game:GetService('Players')

local TournamentService = require(script.Parent.Services.TournamentService)

local function CheckPlayerCount()
	return #Players:GetPlayers() >= 3
end

local function StartTournament()
	TournamentService:StartTournament()
	TournamentService:EndTournament()
end

while true do
	if not CheckPlayerCount() then
		Players.PlayerAdded:Wait()

		if not CheckPlayerCount() then
			continue
		end
	end

	StartTournament()
end

the logic seems pretty sound to me, I like the idea of putting the contenstants inside of a 2d table

the modularization is pretty good.

I dont see any problems! good job!

Thank you, I was gonna do type checking but I’ve never done it before and was very overwhelmed so I decided not to.

type checking is up to personal preference, I personally only use it if it can increase clarity and readability