aboutsummaryrefslogtreecommitdiffstats
path: root/day14/main.hs
blob: 46974d1a9eb96421b99a9ca9543e1192d948f8c4 (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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE LambdaCase #-}

module Main where

import Data.Function (on)
import qualified Data.List as L
import Data.Map.Strict (Map, (!))
import qualified Data.Map.Strict as M
import Data.Text (pack, replace, unpack)
import Data.Vector.Unboxed (Vector)
import qualified Data.Vector.Unboxed as V
import Debug.Trace (traceShow)
import Utils

recur1 :: Vector Char -> Map (Char, Char) Char -> Int -> Vector Char
recur1 initial rules n
  | n == 0 = initial
  | otherwise =
    let pairs = V.zip initial (V.tail initial)
        inserted = pairs $> V.concatMap (\p@(a, _) -> V.fromList [a, rules ! p])
        result = V.snoc inserted (V.last initial)
     in recur1 result rules (n - 1)

e1 initial rules =
  let polymer = recur1 (V.fromList initial) rules 10
      lengthPairs = polymer $> V.map (\c -> (c, V.length $ V.filter (== c) polymer))
      (mc, mcN) = lengthPairs $> V.maximumBy (compare `on` snd)
      (lc, lcN) = lengthPairs $> V.minimumBy (compare `on` snd)
   in mcN - lcN

type CPair = (Char, Char)

type PairFreqMap = Map CPair Integer

type CFreqMap = Map Char Integer

type RuleMap = Map CPair Char

type Maps = (PairFreqMap, CFreqMap, RuleMap)

recur2 :: Maps -> Int -> CFreqMap
recur2 maps@(pairFreq, cFreq, rules) n
  | n == 0 = cFreq
  | otherwise =
    let pairs = M.keys pairFreq
        (pairFreq', cFreq') =
          L.foldl'
            ( \(accPairFreq, accCFreq) pair@(a, b) ->
                let c = rules ! pair
                    totalPairFreq = pairFreq ! pair
                    pairFreq' =
                      accPairFreq
                        $> M.insertWith (+) (a, c) totalPairFreq
                        .> M.insertWith (+) (c, b) totalPairFreq
                        .> M.adjust (\v -> v - totalPairFreq) pair
                    cFreq' = M.insertWith (+) c totalPairFreq accCFreq
                 in (pairFreq', cFreq')
            )
            (pairFreq, cFreq)
            pairs
     in recur2 (pairFreq', cFreq', rules) (n - 1)

e2 initial rules =
  let pairs = zip initial (tail initial)
      pairFreqMap = L.foldl' (\acc p -> M.insertWith (+) p 1 acc) M.empty pairs
      cFreqMap = L.foldl' (\acc c -> M.insertWith (+) c 1 acc) M.empty initial
      resultCFreqMap = recur2 (pairFreqMap, cFreqMap, rules) 40
      mcN = L.maximum (M.elems resultCFreqMap)
      lcN = L.minimum (M.elems resultCFreqMap)
   in mcN - lcN

main :: IO ()
main =
  do
    contents <- getContents

    let input = contents $> lines
    let initial = head input
    let rules' =
          tail (tail input)
            $> map (pack .> replace (pack " -> ") (pack "") .> unpack)
            .> map (\[x, y, z] -> ((x, y), z))

    let rules = M.fromList rules'
    e1 initial rules $> print
    e2 initial rules $> print