-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay23.hs
119 lines (102 loc) · 3.29 KB
/
Day23.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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
module Day23
( part1
, part2
) where
import Data.Char (isAlpha)
import Data.Map as M (Map, adjust, empty,
findWithDefault, insert,
singleton)
import Data.Maybe (fromJust, isNothing)
import Data.Sequence as S (Seq ((:<|), (:|>)),
empty, length, null)
import Data.Vector (Vector, fromList, (!?))
import Helpers.Parsers (Parser, parseByLine)
import Math.NumberTheory.Primes.Testing (isPrime)
import Text.Megaparsec (many, manyTill, optional,
sepBy, (<|>))
import Text.Megaparsec.Char (alphaNumChar, char, eol,
spaceChar, string)
import Text.Megaparsec.Debug
data Op
= Set Char String
| Sub Char String
| Mul Char String
| Jnz String String
deriving (Show)
type Program = Vector Op
data Computer = Computer
{ counter :: Int
, pointer :: Int
, memory :: Map Char Int
, program :: Program
} deriving (Show)
alnum :: Parser [String]
alnum = manyTill alnumChars eol
alnumChars :: Parser String
alnumChars = do
val <- many (char '-' <|> alphaNumChar)
optional . char $ ' '
return val
parseOp :: Parser Op
parseOp = set <|> sub <|> mul <|> jnz
set :: Parser Op
set = do
string "set "
[v1:_, v2] <- alnum
optional eol
return . Set v1 $ v2
sub :: Parser Op
sub = do
string "sub "
[v1:_, v2] <- alnum
optional eol
return . Sub v1 $ v2
mul :: Parser Op
mul = do
string "mul "
[v1:_, v2] <- alnum
optional eol
return . Mul v1 $ v2
jnz :: Parser Op
jnz = do
string "jnz "
[v1, v2] <- alnum
return . Jnz v1 $ v2
execute1 :: Computer -> Int
execute1 computer
| isNothing safeInst = counter computer
| otherwise = execute1 . execute inst $ computer
where
safeInst = program computer !? pointer computer
inst = fromJust safeInst
execute :: Op -> Computer -> Computer
execute inst computer = computer' {pointer = pointer'}
where
pointer' = posInst inst
computer' = operate inst computer
posInst (Jnz v1 v2)
| val v1 computer /= 0 = pointer computer + val v2 computer
posInst _ = pointer computer + 1
val :: String -> Computer -> Int
val v computer
| all isAlpha v = findWithDefault 0 (head v) . memory $ computer
| otherwise = read v
operate :: Op -> Computer -> Computer
operate (Jnz _ _) computer = computer
operate (Set v1 v2) computer =
computer {memory = insert v1 (val v2 computer) . memory $ computer}
operate (Sub v1 v2) computer =
computer {memory = adjust (flip (-) (val v2 computer)) v1 . memory $ computer}
operate (Mul v1 v2) computer =
computer
{ counter = counter computer + 1
, memory = adjust (* val v2 computer) v1 . memory $ computer
}
part1 :: Bool -> String -> String
part1 _ =
show . execute1 . Computer 0 0 M.empty . fromList . parseByLine parseOp
part2 :: Bool -> String -> String
part2 _ _ =
show . Prelude.length . filter (not . isPrime) $ [b,b + 17 .. b + 17000]
where
b = 100000 + 9900