-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay19.hs
73 lines (61 loc) · 2.04 KB
/
Day19.hs
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
{-# LANGUAGE TupleSections #-}
module Day19 (solve) where
import Data.Function ( (&) )
import Data.List
import qualified Data.List.Split as Split
solve input lines = do
let blueprints = readBlueprints lines
print $
blueprints
& map (uncurry (*) . quality 24)
& sum
print $
blueprints
& take 3
& map (snd . quality 32)
& product
quality minutes blueprint = do
let inventory = [0, 0, 0, 0]
let army = [1, 0, 0, 0]
let (id, costs) = blueprint
[(inventory, army)]
& iterate (prune . advanceMinute costs)
& (!! minutes)
& geodes
& (id,)
where
geodes states = states & map (last . fst) & maximum
prune = nub . take 1024 . sortOnDesc value
value (inventory, army) =
sum (zipWith (*) inventory [1, 20, 400, 8000])
+ sum (zipWith (*) army [2, 40, 800, 16000])
advanceMinute costs states =
states
& map (\ (a, b) -> (b, (a, b)))
& spendChoices costs
& map (\ (origArmy, (inventory, army)) ->
(zipWith (+) inventory origArmy, army))
spendChoices costs states = states ++ concatMap (tryBuildEach costs) states
tryBuildEach costs (origArmy, (inventory, army)) =
costs
& map (zipWith (-) inventory)
& zip [0 .. ]
& filter (all (>= 0) . snd)
& map (\ (kind, inventory') ->
(origArmy, (inventory', incAt kind army)))
incAt pos = zipWith (\ i n -> if i == pos then n + 1 else n) [0 .. ]
sortOnDesc pred = reverse . sortOn pred
readBlueprints =
map readLine
where
readLine line = do
let parts = Split.splitOn " " line
let id = parts !! 1 & init & read :: Int
let nums =
[6, 12, 18, 21, 27, 30] & map (read . (parts !!)) :: [Int]
let details =
[ [head nums, 0, 0, 0],
[nums !! 1, 0, 0, 0],
[nums !! 2, nums !! 3, 0, 0],
[nums !! 4, 0, nums !! 5, 0] ]
(id, details)