summaryrefslogtreecommitdiff
path: root/scheduling/Main.hs
blob: 18f8ae5761f65ca4279cf2072b3e3853299744f5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import Control.Monad (forM_)
import Data.Function (on)
import Data.List (sortBy, unfoldr)
import System.Random (RandomGen, randoms, getStdGen, split)
import Data.HashSet (HashSet, fromList, member)

data Player = Player { name :: String
                     , rank :: Int
                     , matchLimit :: Int
                     } deriving (Show, Eq)

players :: [Player]
players = [ Player "orbekk" (-1) 4
          , Player "ltsang" (-4) 4
          , Player "sebh" 2 4
          , Player "fringd" (-1) 4
          , Player "sheyrax" (-2) 2
          ]

shuffle :: (RandomGen g) => g -> [a] -> [a]
shuffle g xs = map snd $ sortBy (compare `on` fst) (zip rs xs)
  where rs = randoms g :: [Int]

matchOnce :: [String] -> [String] -> [(String, String)]
matchOnce (p:ps) (q:qs)
  | p == q    = matchOnce (p:ps) qs
  | otherwise = (p, q) : matchOnce (filter (/=q) ps) (filter (/=p) qs)
matchOnce _ _ = []

subtractMatches :: [(String, String)] -> [Player] -> [Player]
subtractMatches matches players = fmap subtractMatch players
  where matchPlayers :: HashSet String
        matchPlayers = fromList (map fst matches ++ map snd matches)
        subtractMatch p
            | (name p) `member` matchPlayers =
                  p { matchLimit = matchLimit p - 1 }
            | otherwise = p

matchPlayers :: (RandomGen g) => g -> [Player] -> [(String, String)]
matchPlayers _ [] = []
matchPlayers _ [p] = []
matchPlayers g players = matches ++ matchPlayers g3 nextPlayers
  where matches = matchOnce (shuffle g1 playerNames) (shuffle g2 playerNames)
        playerNames = fmap name players
        (g', g1) = split g
        (g2, g3) = split g'
        nextPlayers =
            filter ((>0) . matchLimit) (subtractMatches matches players)

iterativeMatchPlayers :: (RandomGen g) => g -> [Player] -> [[(String, String)]]
iterativeMatchPlayers g players = unfoldr f (g, players)
  where f (g, players) = Just (matchPlayers g1 players, (g2, players))
        (g1, g2) = split g

main = do
  g <- getStdGen
  let matches = iterativeMatchPlayers g players !! 1010
  forM_ matches $ \(p, q) ->
    putStrLn $ p ++ " vs. " ++ q