This repository has been archived by the owner on Nov 17, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathDay21.hs
100 lines (93 loc) · 3.07 KB
/
Day21.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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
-- |
-- Module : AOC.Challenge.Day21
-- Copyright : (c) Justin Le 2018
-- License : BSD3
--
-- Maintainer : justin@jle.im
-- Stability : experimental
-- Portability : non-portable
--
-- Day 21. See "AOC.Solver" for the types used in this module!
module AOC.Challenge.Day21 (
day21a
, day21b
) where
import AOC.Common.Elfcode (ECProg, Instr(..), OpCode(..), Peephole, IMem, currPeepPos, peep, traceECProg_, optimizeEC, parseElfcode)
import AOC.Solver ((:~>)(..))
import Data.Finite (Finite)
import Data.Maybe (listToMaybe, mapMaybe)
import qualified Data.Set as S
import qualified Data.Vector as UV
import qualified Data.Vector.Unboxed.Sized as V
-- | All the times where the program checks if something is equal to the
-- value in register zero
zeroChecks
:: Finite 6
-> ECProg
-> [IMem]
-> [Int]
zeroChecks iPtr prog = mapMaybe checksZero
where
checksZero v = prog UV.!? (v `V.index` iPtr) >>= \case
I OEqIR x 0 _ -> Just x
I OEqRI 0 x _ -> Just x
I OEqRR 0 r _ -> Just $ v `V.index` fromIntegral r
I OEqRR r 0 _ -> Just $ v `V.index` fromIntegral r
_ -> Nothing
day21a :: (Finite 6, ECProg) :~> Int
day21a = MkSol
{ sParse = parseElfcode
, sShow = show
, sSolve = \(i, optimizeEC [division i] -> p) ->
listToMaybe
. zeroChecks i p
. traceECProg_ i p
$ V.replicate 0
}
day21b :: (Finite 6, ECProg) :~> Int
day21b = MkSol
{ sParse = parseElfcode
, sShow = show
, sSolve = \(i, optimizeEC [division i] -> p) ->
listToMaybe . reverse . uniqRun
. zeroChecks i p
. traceECProg_ i p
$ V.replicate 0
}
uniqRun :: [Int] -> [Int]
uniqRun = go S.empty
where
go _ [] = []
go seen (x:xs)
| x `S.member` seen = []
| otherwise = x : go (S.insert x seen) xs
-- | Peephole optimize a division
division
:: Finite 6 -- ^ instruction register
-> Peephole [Instr]
division i = do
a <- currPeepPos
I OSetI _ _ z1 <- peep (Just 0) Nothing Nothing
let z1' = fromIntegral z1
I OAddI _ _ z2 <- peep (Just z1') (Just 1) Nothing
let z2' = fromIntegral z2
n <- peep (Just z2') Nothing (Just z2) >>= \case
I OMulR _ n _ -> pure $ Left n
I OMulI _ n _ -> pure $ Right n
_ -> fail "No match"
I OGtRR _ m _ <- peep (Just z2') Nothing (Just z2)
I OAddR _ _ _ <- peep (Just z2') (Just i') (Just i )
I OAddI _ _ _ <- peep (Just i' ) (Just 1 ) (Just i )
I OSetI q _ _ <- peep Nothing Nothing (Just i )
I OAddI _ _ _ <- peep (Just z1') (Just 1 ) (Just z1)
I OSetI _ _ _ <- peep (Just a ) Nothing (Just i )
I OSetR _ _ o <- peep (Just z1') Nothing Nothing
c <- currPeepPos
pure . take (c - a) $
[ case n of
Left r -> I ODivR m r o
Right x -> I ODivI m x o
, I OSetI q 0 i
] ++ repeat (I ONoOp 0 0 0)
where
i' = fromIntegral i