module Graph where
import Data
import qualified Data.Map as M
import Control.Arrow (second, (***))
import Data.Maybe
import Data.Ord
import Data.List
import Debug.Trace
transHull :: [GameSum] -> [Edge]
transHull = foldr insert [] . map fst . sortBy (comparing snd)
where insert (p1,p2) graph
| reachable graph p2 p1 = graph -- Do not build cycles
| reachable graph p1 p2 = graph -- No useful edge
| otherwise = (p1,p2) : removeObs (p1,p2) graph
-- | Removes any edge pointing towards p2 that can also reach p1
removeObs (p1,p2) graph = filter go graph
where go (p1', p2') = not $ p2' == p2 && reachable graph p1' p1
|| p1' == p1 && reachable graph p2 p2'
-- | Tests whether a player is reachable. Stupid algorithm, breaks when there
-- are cycles
reachable :: [Edge] -> Player -> Player -> Bool
reachable g p1 p2 = go p1
where go p = any (\(_,p') -> p2 == p' || go p') $ filter ((==) p . fst) g
sumGames :: [Game] -> [GameSum]
sumGames = mapMaybe flipRight . M.toList . M.map sumUp .
M.fromListWith (\(a,b) (a',b') -> (a ++ a', b `max` b')) .
zipWith (\n (a,b) -> (a,([b],n))) [1,2..] .
map sortName
where sumUp :: ([Result],Integer) -> (Integer, Integer, Integer)
sumUp (ress,o) = ( sum (map gameCount ress)
, sum (map (uncurry (-)) ress)
, o
)
flipRight ((p1,p2),c@(c1,c2,c3)) =
if c1 == 0 && c2 == 0
then Nothing
else if c >= (0,0,0)
then Just ((p1,p2),c)
else Just ((p2,p1),(-c1,-c2,c3))
sortName x@((p1,p2),(c1,c2)) | p1 <= p2 = x
| otherwise = ((p2,p1),(c2,c1))
gameCount (a,b) | a > b = 1
| a < b = -1
| otherwise = 0
countGames :: [Game] -> [(Player, Integer)]
countGames = M.toList . M.fromListWith (+) . concat . map (\((p1,p2),_) -> [(p1,1),(p2,1)])