aboutsummaryrefslogtreecommitdiff
path: root/2020/15b.hs
blob: 1efe53e8c41b8f0bbf98187839823a16d1bc03d8 (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
module Main where

import System.Environment (getArgs)
import Text.Printf
import qualified Data.IntMap.Strict as Map

-- This does the same thing as 15a, it's just done in a more memory-optimised way.

-- Parse a string, with one number per line
parseInput :: String -> [Int]
parseInput = map read . lines

-- Parse a file given the path
-- Returns list of instructions
parseFromFile :: String -> IO [Int]
parseFromFile s = do 
                   contents <- readFile s;
                   return $ parseInput contents;

-- Generate a map from the list of initial numbers
mapFromInitial :: [Int] -> Map.IntMap Int
mapFromInitial xs = foldr (\(i,x) m -> Map.insert x i m) Map.empty (zip [0..] xs)

-- Run till the given turn, this time using a map to store last occurences.
-- This means we don't get the full 'log', just the final turn.
-- map, prev, current index, stopping len
runTillTurn :: Map.IntMap Int -> Int -> Int -> Int -> Int
runTillTurn occ prev i n | i >= n = prev
                           | otherwise = runTillTurn occ' curr (i + 1) n
                            where curr = case Map.lookup prev occ of 
                                    Nothing -> 0
                                    Just x -> (i - 1) - x
                                  occ' = Map.insert prev (i - 1) occ

-- runghc 15b.hs inputs/day15
main :: IO ()
main = do 
        args <- getArgs;
        ns <- parseFromFile (head args);
        let x = runTillTurn (mapFromInitial ns) (last ns) (length ns) 30000000;

        printf "Answer = %d\n" x :: IO ();

        return ();