Skip to content

Instantly share code, notes, and snippets.

@naota
Created July 26, 2010 17:42
Show Gist options
  • Save naota/490902 to your computer and use it in GitHub Desktop.
Save naota/490902 to your computer and use it in GitHub Desktop.
data Racer = Racer { name :: String
, score :: Int
, wins :: [Int]
} deriving (Show)
main :: IO ()
main = interact func
scores :: [Int]
scores = [25, 18, 15, 12, 10, 8, 6, 4, 2, 1]
func :: String -> String
func s = onechamp racerdata ++ "\n" ++ anotherchamp racerdata ++ "\n"
where racedata = convert s
racerdata = fromRaceData racedata []
(!!!) :: [Int] -> Int -> Int
lst !!! n = if (length lst) <= n then 0 else (lst !! n)
onechamp :: [Racer] -> String
onechamp rd = name . check 0 $ candicates 0 [] rd
where candicates _ cs [] = cs
candicates hi cs (r:rs) = if score r > hi
then candicates (score r) [r] rs
else if score r == hi
then candicates hi (r:cs) rs
else candicates hi cs rs
check _ [] = error ""
check _ (r:[]) = r
check n (r:rs) = let up = filter (\x -> (wins r)!!!n < (wins x)!!!n) rs
in if null up
then check (n+1) $ r:(filter (\x -> (wins r)!!!n == (wins x)!!!n) rs)
else check n up
anotherchamp :: [Racer] -> String
anotherchamp rd = name $ check 1 $ checkPoint $ candicates 0 [] rd
where candicates _ cs [] = cs
candicates hi cs (r:rs) = if (wins r)!!!0 > hi
then candicates ((wins r)!!!0) [r] rs
else if (wins r)!!!0 == hi
then candicates hi (r:cs) rs
else candicates hi cs rs
check _ [] = error ""
check _ (r:[]) = r
check n (r:rs) = let up = filter (\x -> (wins r)!!!n < (wins x)!!!n) rs
in if null up
then check (n+1) $ r:(filter (\x -> (wins r)!!!n == (wins x)!!!n) rs)
else check n up
checkPoint [] = error ""
checkPoint (r:[]) = [r]
checkPoint (r:rs) = let up = filter (\x -> (score r) < (score x)) rs
in if null up
then r:(filter (\x -> (score r) == (score x)) rs)
else checkPoint up
fromRaceData :: [[String]] -> [Racer] -> [Racer]
fromRaceData [] racer = racer
fromRaceData (r:rs) racer = fromRaceData rs $ f (zip [0..] r) racer
where f [] nowr = nowr
f ((n, na):rest) nowr = let rc = getOrNew na racer
newwin = plusWins n $ wins rc
newsc = score rc + scores !!! n
in f rest $ update na (rc {score = newsc, wins = newwin}) nowr
getOrNew :: String -> [Racer] -> Racer
getOrNew na rs = let lst = filter (\r -> name r == na) rs
in if null lst
then Racer {name=na,score=0,wins=[]}
else head lst
update :: String -> Racer -> [Racer] -> [Racer]
update na new rs = new:filter (\r -> name r /= na) rs
convert :: String -> [[String]]
convert s = convert' n (tail ls)
where ls = lines s
n = read $ head ls :: Int
convert' 0 _ = []
convert' n' ls' = [take m (tail ls')] ++ convert' (n'-1) (drop m (tail ls'))
where m = (read $ head ls')::Int
plusWins :: Int -> [Int] -> [Int]
plusWins 0 [] = [1]
plusWins n [] = 0:plusWins (n-1) []
plusWins 0 (x:xs) = (x+1):xs
plusWins n (x:xs) = x:plusWins (n-1) xs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment