aboutsummaryrefslogtreecommitdiff
path: root/2020/17a.hs
blob: d888379de9b0570210dcb2cce7b9e9dea68a3b28 (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
60
61
62
63
64
module Day17A where

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

-- Types
type Coord = (Int, Int, Int);
type ActiveMap = Map.Map Coord Bool

-- Add two coords
addCoord :: Coord -> Coord -> Coord
addCoord (x, y, z) (x', y', z') = (x + x', y + y', z + z')

-- The range of cubes that need to be simulated.
consideredRange :: ActiveMap -> (Coord, Coord)
consideredRange m = (addCoord (Map.foldrWithKey (compCoord min) (0, 0, 0) m) (-1, -1, -1),
                     addCoord (Map.foldrWithKey (compCoord max) (0, 0, 0) m) (1, 1, 1))
    where compCoord f (x', y', z') _ (x, y, z) = (f x' x, f y' y, f z' z)

-- The neighbours of the given cube
neighbours :: Coord -> [Coord]
neighbours (x, y, z) = [(x', y', z') | x' <- [x-1..x+1],
                                       y' <- [y-1..y+1],
                                       z' <- [z-1..z+1],
                                       x' /= x || y' /= y || z' /= z]

-- Simulate the cube at the given coord
simulateCube :: ActiveMap -> Coord -> Bool
simulateCube m c | s && n `elem` [2..3] = True
                 | n == 3 = True
                 | otherwise = False
      where s = Map.findWithDefault False c m
            n = length $ filter (== True) $ map (\x -> Map.findWithDefault False x m) (neighbours c)

-- Run one cycle of simulation
runCycle :: ActiveMap -> ActiveMap
runCycle m = foldr (\(k, v) m' -> Map.insert k v m') m changes -- Run all changes simultaneously
      where ((lx, ly, lz), (hx, hy, hz)) = consideredRange m
            changes = [((x, y, z), simulateCube m (x, y, z)) | x <- [lx..hx], y <- [ly..hy], z <- [lz..hz]]

-- Parse the input
parseInput :: String -> ActiveMap
parseInput xs = foldr (\c m -> Map.insert c True m) Map.empty coords
      where ls = zip (lines xs) [0..]
            coords = concatMap (\(hs, y) -> [(x, y, 0) | ('#', x) <- zip hs [0..]]) ls

-- Read and parse given filename
parseFromFile :: String -> IO ActiveMap
parseFromFile s = do 
                   contents <- readFile s;
                   return $ parseInput contents;

-- runghc 17a.hs inputs/day17
main :: IO ()
main = do 
        args <- getArgs;
        i <- parseFromFile (head args);

        let final = foldr (\_ m -> runCycle m) i [1..6];

        printf "Answer = %d\n" (Map.size $ Map.filter (== True) final) :: IO ();

        return ();