Skip to content

Instantly share code, notes, and snippets.

@mattgreen
Created March 18, 2016 15:38
Show Gist options
  • Save mattgreen/fc37f35ab11bd93a2981 to your computer and use it in GitHub Desktop.
Save mattgreen/fc37f35ab11bd93a2981 to your computer and use it in GitHub Desktop.
import Control.Monad (guard)
import Data.List (foldl', sort)
-- Types
data Player = Player Name Rating
deriving (Eq, Show)
type Name = String
type Rating = Integer
instance Ord Player where
(Player _ r1) `compare` (Player _ r2) = r1 `compare` r2
type Team = [Player]
-- Sorts players by MMR in decreasing order, pairing them with their
-- closest rated player. The pairs are then split between the teams.
-- To avoid the first team being stacked using this method, we alternate
-- which team the first player in a pairing is assigned to.
balance :: [Player] -> Maybe (Team, Team)
balance players = do
guard (evenLength players)
return $ foldl' assign ([], []) pairings
where
pairings = pair . reverse . sort $ players
evenLength x = (length x) `rem` 2 == 0
assign (t1, t2) (p1, p2) =
if evenLength t1
then (p1:t1, p2:t2)
else (p2:t1, p1:t2)
pair (p1:p2:ps) = (p1,p2) : pair ps
pair _ = []
teamMmrAverage :: Team -> Integer
teamMmrAverage team = sum mmrs `div` count
where
count = fromIntegral . length $ team
mmrs = map (\(Player _ mmr) -> mmr) team
stats :: (Team, Team) -> (Integer, Integer)
stats (t1, t2) = (teamMmrAverage t1, teamMmrAverage t2)
-- Sample data
players :: [Player]
players = [Player "a" 400, Player "b" 500, Player "c" 600, Player "d" 700, Player "e" 800, Player "f" 900, Player "g" 1000, Player "h" 1100, Player "i" 1200, Player "j" 1300]
betterPool = [ Player "avg" 2000
, Player "avg2" 2100
, Player "avg3" 2150
, Player "good1" 3300
, Player "good2" 3200
, Player "lessgood" 1500
, Player "gettingbetter" 1700
, Player "great" 3500
, Player "avg4" 2400
, Player "avg5" 2200 ]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment