clean up day 1, v1 is too embarassing
Haldean Brown
4 years ago

0 | 0 | import qualified Data.Set as S |

1 | 1 | import System.Environment |

2 | 2 | |

3 | -- simple loading and parsing functions | |

3 | 4 | toint :: String -> Integer |

4 | 5 | toint ('+':val) = read val |

5 | 6 | toint ('-':val) = - (read val) |

6 | 7 | toint val = read val :: Integer |

7 | ||

8 | 8 | loadlist :: String -> [Integer] |

9 | 9 | loadlist = map toint . filter (not . null) . lines |

10 | 10 | |

11 | -- challenge 1: just sum the list | |

12 | main1 :: IO () | |

13 | main1 = fmap (sum . loadlist) (readFile "input.txt") >>= print | |

14 | ||

15 | -- this turns a list of integers into an infinite list of pairs of (set of sums | |

16 | -- seen so far, current running sum). the list is made infinite by cycling the | |

17 | -- input list | |

11 | 18 | dofold :: [Integer] -> [(S.Set Integer, Integer)] |

12 | dofold lst1 = | |

13 | let lst = cycle lst1 in | |

14 | scanl (\(seenfreqs, lastfreq) offset -> let newfreq = lastfreq + offset in (S.insert newfreq seenfreqs, newfreq)) (S.empty, 0) lst | |

19 | dofold lst = | |

20 | let scanfunc = \(seenfreqs, lastfreq) offset -> let newfreq = lastfreq + offset in (S.insert newfreq seenfreqs, newfreq) | |

21 | in scanl scanfunc (S.empty, 0) (cycle lst) | |

15 | 22 | |

23 | -- this finds the first frequency to appear twice by pairing up the frequencies | |

24 | -- seen after frame i with the frequency at frame i + 1. If the frequency in a | |

25 | -- pair also exists in the set of the pair, it means that it had been seen in | |

26 | -- frame i, so it's a duplicate. The first element in our infinite list that | |

27 | -- satisfies that is our answer. | |

16 | 28 | finddup :: [Integer] -> Integer |

17 | 29 | finddup lst1 = let folded = dofold lst1 in |

18 | 30 | snd $ head $ dropWhile (\(seenfreq, newfreq) -> not $ S.member newfreq seenfreq) $ zip (map fst folded) (drop 1 $ map snd folded) |

19 | 31 | |

20 | main1 :: IO () | |

21 | main1 = fmap (sum . loadlist) (readFile "input.txt") >>= print | |

22 | ||

23 | 32 | main2 :: IO () |

24 | 33 | main2 = fmap (finddup . loadlist) (readFile "input.txt") >>= print |

25 | 34 | |

35 | -- runs the first or second challenge depending on the command line argument | |

26 | 36 | main :: IO () |

27 | 37 | main = fmap head getArgs >>= \a -> if a == "1" then main1 else main2 |