Team Power Matchmaking "Power"

EDIT: Updated Module

I was making a team matchmaking system, easier said than done by a lot. Spend many hours on and with 190 lines I made it a module.

This is my first module and “complex system” but I want to see if I can make any improvements. The current system works off random and limited in what it can do, I already have a solution in mind to make it ALOT more efficient and less limited. I don’t know how to achieve this solution, so random it is for now.

This module takes a table of players and all of their “Power” to find the most optimal and fair teams.

Here it is: Matchmaking Module Place.rbxl (30.8 KB)

Code (190 Lines) Get full instructions in Download

local module = {}
module.BestMatch = function(Plrs,Values)
	local x = 0--#Values
	for i,v in pairs(Values) do
		x +=1
	end

	--Makes sure number is even
	if x % 2 == 0 then--Donot Touch or computer itself will crash

------------------------------
--Phase 1, Generate all Possible Combinations
----------------------------
		
		--Factorial
		local function factorial(n)
			if (n == 0) then
				return 1
			else
				return n * factorial(n - 1)
			end
		end
		--
		--Combinations
		local Comination1 = factorial(x)
		local Combination2 = factorial(x/2)
		local Combination3 = factorial( (x)-(x/2) )
		local formula = (Comination1) / (Combination2*Combination3)

		local DifferentCombinations = {}

		local NumTable = {}
		for i = 1,x,1 do
			table.insert(NumTable,#NumTable+1,i)
		end

		local function shallowCopy(original)
			local copy = {}
			for key, value in pairs(original) do
				copy[key] = value
			end
			return copy
		end

		---Create a Random order of x Numbers
		local function getrandomorder()
			local output = {}
			local tempnum = shallowCopy(NumTable)
			while #output < x do
				local num = math.random(1,#tempnum)
				local newnum = tempnum[num]
				table.insert(output,1,newnum)
				table.remove(tempnum,table.find(tempnum,tempnum[num]))
			end--while #output

			--Seperate Tables
			local output1 = {}
			local output2 = {}
			for i = 1, x,2 do
				table.insert(output1,1,output[i])
				table.insert(output2,1,output[i+1])
			end
			table.sort(output1)
			table.sort(output2)

			return {output1,output2}
		end--getrandomorder

		--Creates a table of all the possible combinations

		local function CompareTables(tabA, tabB)
			local Same = true
			local keysA = {}
			local keysB = {}

			local function getResult()
				if Same then return "Equal" end
				return "Different"
			end

			for k, v in pairs(tabA) do
				keysA[k] = v
			end
			for k, v in pairs(tabB) do
				keysB[k] = v
			end
			for  k, v in pairs(keysA) do
				if keysB[k] ==  nil then
					local result = getResult()
					return result
				elseif keysB[k] ~= v then
					Same = false
				end
			end
			for  k, v in pairs(keysB) do
				if keysA[k] ==  nil then
					local result = getResult()
					return result
				elseif keysA[k] ~= v then
					Same = false
				end
			end
			local result = getResult()
			return result
		end

		while #DifferentCombinations < (formula / 2) do
			wait()
			--Check if order is already used
			local order = getrandomorder()
			local result
			local deb = false
			for q,z in pairs(DifferentCombinations) do
				if deb == false then
					result = CompareTables(z[1],order[1])
					if result == "Different" then
						if CompareTables(z[1],order[2]) == "Equal" then
							if CompareTables(z[2],order[1]) == "Equal" then
								result = "Equal"
								deb = true
							end
						end
					end
					if result == "Equal" then
						deb = true
					end
				end		
			end

			if result == "Different" or #DifferentCombinations == 0 then
				table.insert(DifferentCombinations,1,order)	
			end
		end

		------------------------------
		--Phase 2, Swap Numbers for players and find best combination
		----------------------------

		---Create Second Table with the Values
		local PlayerValuesCombValues = {}
		for i,v in pairs(DifferentCombinations) do
			local insertedtable = {}
			local Power = 0
			for t,s in pairs(v) do
				Power = 0
				for l,q in pairs(s) do
					Power += Values[q] 
				end
				table.insert(insertedtable,Power)
			end
			table.insert(insertedtable,3,{v[1],v[2]})
			table.insert(PlayerValuesCombValues,i,insertedtable)
		end

		--See What Combination is best
		local LowestGap = math.huge
		local LowestTable = {}
		for i,v in pairs(PlayerValuesCombValues) do
			local Gap = v[1] - v[2]
			if Gap < 0 then--Make Gap a Positive Num
				Gap = Gap*(-1)
			end
			if Gap < LowestGap then
				LowestGap = Gap
				LowestTable = shallowCopy(v)
			end 
		end

		---Finalize Best Combo
		local BestTable = {}
		for i,v in pairs(LowestTable[3]) do
			local temptbl = {}
			for q,e in pairs(v) do
				table.insert(temptbl,Plrs[e])
			end
			table.insert(BestTable,temptbl)
			temptbl = {}
		end

		return BestTable , LowestGap
	else
		return warn("Sent #Players were Odd.")
	end
end--if even == true

return module

If anyone is wondering, I currently randomly generate all the possible teams with numbers than replace it with the player’s power than find the best match. My solution to this would have all the different possible teams/combinations premade so I don’t need to continuously use random to find these combinations every time

1 Like

think your method might be best, just brute force it.
if you have issues on PC’s freezing, just add some waits to split the load
one of the best balancers I know is in forged alliance

maybe there are some ideas there you can use?

1 Like