~rootmos/AoC

96820dae48da51ce26d76e9df87ed94d042eb7cf — Gustav Behm 1 year, 3 months ago e34d519
Add solution to AoC 2022 #16a
3 files changed, 189 insertions(+), 0 deletions(-)

A 2022/16.example
A 2022/16.hs
A 2022/16.input
A 2022/16.example => 2022/16.example +10 -0
@@ 0,0 1,10 @@
Valve AA has flow rate=0; tunnels lead to valves DD, II, BB
Valve BB has flow rate=13; tunnels lead to valves CC, AA
Valve CC has flow rate=2; tunnels lead to valves DD, BB
Valve DD has flow rate=20; tunnels lead to valves CC, AA, EE
Valve EE has flow rate=3; tunnels lead to valves FF, DD
Valve FF has flow rate=0; tunnels lead to valves EE, GG
Valve GG has flow rate=0; tunnels lead to valves FF, HH
Valve HH has flow rate=22; tunnel leads to valve GG
Valve II has flow rate=0; tunnels lead to valves AA, JJ
Valve JJ has flow rate=21; tunnel leads to valve II

A 2022/16.hs => 2022/16.hs +125 -0
@@ 0,0 1,125 @@
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE NoImplicitPrelude #-}
module Main where

import Qulude
import Qulude.Dijkstra

import Data.Array ( (!), (//) )
import qualified Data.Array as Array
import qualified Data.Either as Either
import qualified Data.List as List
--import Data.Array ( (!) )
import qualified Data.Map as Map
import qualified Data.Maybe as Maybe
import qualified Data.Sequence as Seq
import qualified Data.Set as Set

type Name = String

indexed :: [a] -> [(Int, a)]
indexed = go 0
  where go _ [] = []
        go i (x:xs) = (i,x):go (succ i) xs

data Survey = Survey { names :: Array Int Name
                     , rates :: Array Int Int
                     , tunnels :: Array Int [Int]
                     }
  deriving (Show, Eq)

parser :: Parser Survey
parser = mk <$> many valve
  where name = many1 upper
        valve = do
          string "Valve "
          v <- name
          string " has flow rate="
          r <- int
          (try $ string "; tunnel leads to valve ") <|> (string "; tunnels lead to valves ")
          ds <- name `sepBy` string ", "
          newline
          return $ (v, r, ds)

mk vs = Survey ns rs ts
  where is = indexed vs
        n = length is
        ns = Array.array (0,pred n) $ flip fmap is $ \(i, (n, _, _)) -> (i,n)
        rs = Array.array (0,pred n) $ flip fmap is $ \(i, (_, r, ds)) -> (i,r)
        ts = Array.array (0,pred n) $ flip fmap is $ \(i, (_, _, ds)) -> (i, g 0 <$> ds)
        g i d | d == ns ! i = i
        g i d | otherwise = g (succ i) d

data Action = Noop | Move Int | Open
  deriving ( Show, Eq )

data St = St { loc :: Int
             , pressure :: Int
             , valves :: Array Int Bool
             , time :: Int
             }
  deriving ( Show, Eq )

initSt s = St { loc = 0
              , pressure = 0
              , valves = Array.listArray (Array.bounds $ names s) $ repeat False
              , time = 0
              }

ix (Survey { names }) = Array.indices names

releasePressure s@(Survey { rates }) (St { valves }) t = sum $ fmap f (ix s)
  where f i | valves ! i = t * (rates ! i)
        f i | otherwise = 0

nextValves s@(Survey { rates }) (St { loc, valves }) = catMaybes $ fmap f (ix s)
  where f i | i == loc = Nothing
        f i | otherwise  = if (valves ! i) || (rates ! i /= 0) then Just i else Nothing

move s ds i st = st { time = time st + d
                    , loc = i
                    , pressure = pressure st + releasePressure s st d
                    }
  where d = (Map.!) ds (loc st, i)

open s ds i st = st { time = time st + 1
                    , pressure = pressure st + releasePressure s st 1
                    , valves = valves st // [ (i, True) ]
                    }

mapMaybe :: (a -> Maybe b) -> [a] -> [b]
mapMaybe f [] = []
mapMaybe f (a:as) = case f a of
                      Just b -> b:(mapMaybe f as)
                      Nothing -> mapMaybe f as

next s ds st@(St { loc, pressure, time, valves }) = mapMaybe f $ nextValves s st
  where f i = let d = (Map.!) ds (loc, i) in
              if 30 - time > d then Just (open s ds i $ move s ds i st) else Nothing

distances s = Map.fromList [ ((i, j), d i j) | i <- ix s, j <- ix s, i /= j ]
  where vs = length $ nextValves s $ initSt s
        ns = Set.fromList (ix s)
        d i j = dijkstra i j ns (\k -> fmap (flip (,) 1) (tunnels s ! k))

partA s = go 0 [ initSt s ]
  where ds = distances s
        go !m [] = m
        go !m (st:acc) = case next s ds st of
                           [] -> let m' = runOutTheClock st in
                                 go (max m m') acc
                           sts -> go m (sts `combine` acc)
        runOutTheClock st@(St { pressure, time }) = pressure + releasePressure s st (30 - time)

--partB :: Parse -> Parse
--partB = id

main :: IO ()
main = with parser $ do
  run' "16.example" "a example" partA 1651
  run' "16.input" "a input" partA 1896
  --run "16.example" "b example" partB
  --run "16.input" "b input" partB

A 2022/16.input => 2022/16.input +54 -0
@@ 0,0 1,54 @@
Valve AA has flow rate=0; tunnels lead to valves PM, MU, BM, AW, CB
Valve XG has flow rate=0; tunnels lead to valves CR, OH
Valve ZF has flow rate=7; tunnels lead to valves SC, BY, PM, LW, CJ
Valve RD has flow rate=13; tunnels lead to valves JS, VM
Valve XJ has flow rate=0; tunnels lead to valves JO, YO
Valve CJ has flow rate=0; tunnels lead to valves UA, ZF
Valve UA has flow rate=0; tunnels lead to valves ZP, CJ
Valve EQ has flow rate=0; tunnels lead to valves ZP, RP
Valve IU has flow rate=0; tunnels lead to valves EV, CN
Valve QM has flow rate=0; tunnels lead to valves XA, CN
Valve WC has flow rate=0; tunnels lead to valves JS, OH
Valve MU has flow rate=0; tunnels lead to valves AA, ZP
Valve MW has flow rate=11; tunnels lead to valves BM, AG, RG, NL
Valve XA has flow rate=0; tunnels lead to valves JO, QM
Valve OH has flow rate=12; tunnels lead to valves WC, YS, XG, KO
Valve QD has flow rate=20; tunnels lead to valves BY, KY, CR, RP
Valve OE has flow rate=0; tunnels lead to valves FB, BU
Valve CB has flow rate=0; tunnels lead to valves AA, FX
Valve TB has flow rate=23; tunnel leads to valve VM
Valve PM has flow rate=0; tunnels lead to valves ZF, AA
Valve YS has flow rate=0; tunnels lead to valves OH, RG
Valve KO has flow rate=0; tunnels lead to valves OH, VT
Valve RG has flow rate=0; tunnels lead to valves YS, MW
Valve BU has flow rate=0; tunnels lead to valves OE, EV
Valve RK has flow rate=0; tunnels lead to valves KY, FX
Valve JO has flow rate=18; tunnels lead to valves NL, SX, XA, XJ
Valve AG has flow rate=0; tunnels lead to valves IS, MW
Valve AW has flow rate=0; tunnels lead to valves BS, AA
Valve ZP has flow rate=9; tunnels lead to valves UA, NG, DU, MU, EQ
Valve KY has flow rate=0; tunnels lead to valves QD, RK
Valve EV has flow rate=19; tunnels lead to valves VT, BU, IU, SX
Valve FB has flow rate=24; tunnel leads to valve OE
Valve DU has flow rate=0; tunnels lead to valves IS, ZP
Valve NG has flow rate=0; tunnels lead to valves FX, ZP
Valve HC has flow rate=0; tunnels lead to valves CN, HB
Valve SC has flow rate=0; tunnels lead to valves IS, ZF
Valve HB has flow rate=22; tunnel leads to valve HC
Valve VM has flow rate=0; tunnels lead to valves RD, TB
Valve LW has flow rate=0; tunnels lead to valves ZF, FX
Valve SX has flow rate=0; tunnels lead to valves EV, JO
Valve FX has flow rate=6; tunnels lead to valves FA, NG, RK, LW, CB
Valve JS has flow rate=0; tunnels lead to valves WC, RD
Valve BM has flow rate=0; tunnels lead to valves MW, AA
Valve FA has flow rate=0; tunnels lead to valves IS, FX
Valve RP has flow rate=0; tunnels lead to valves QD, EQ
Valve NL has flow rate=0; tunnels lead to valves MW, JO
Valve CN has flow rate=15; tunnels lead to valves HC, QM, IU
Valve BS has flow rate=0; tunnels lead to valves IS, AW
Valve KP has flow rate=25; tunnel leads to valve YO
Valve YO has flow rate=0; tunnels lead to valves XJ, KP
Valve CR has flow rate=0; tunnels lead to valves XG, QD
Valve BY has flow rate=0; tunnels lead to valves QD, ZF
Valve IS has flow rate=5; tunnels lead to valves DU, SC, AG, FA, BS
Valve VT has flow rate=0; tunnels lead to valves KO, EV