Copyright | (c) Eric Mertens 2017 |
---|---|
License | ISC |
Maintainer | emertens@gmail.com |
Safe Haskell | None |
Language | Haskell2010 |
https://adventofcode.com/2017/day/18
Day 18 defines a simple programming language with arithmetic operations and asynchronous communication. Our task will be to analyze the behavior of the send and receive commands performed by these kinds of programs.
This implementation uses the following passes to transform the input program into a high-level interpretation of the effects of the program from which we can then easily answer the questions posed.
- Get input file with
getInput
- Parse the input with
parser
- Compute effects with
interpreter
- Analyze the effects with
part1
andpart2
>>>
:main
Just 2951 7366
Synopsis
- main :: IO ()
- part1 :: (Integer -> Effect) -> Maybe Integer
- part2 :: (Integer -> Effect) -> Int
- feed :: Integer -> Effect -> Effect
- data Effect
- interpreter :: [Instruction] -> Integer -> Effect
- data Instruction
- data Expression
- newtype Register = Register Char
- instruction :: P Instruction
- register :: P Register
- expression :: P Expression
Main drivers
Print the solution to both parts of the puzzle. Input file can be overridden via command-line argument.
>>>
:main
Just 2951 7366
Compute the last send command that precedes a non-zero receive command.
>>>
:{
let pgm = map (runP instruction) $ lines "set a 1\nadd a 2\nmul a a\nmod a 5\nsnd a\nset a 0\n\ \rcv a\njgz a -1\nset a 1\njgz a -2\n" in part1 (interpreter pgm) :} Just 4
Run two programs concurrently and count how many sends the second program executes once both programs are blocked.
>>>
:{
let pgm = map (runP instruction) $ lines "snd 1\nsnd 2\nsnd p\nrcv a\nrcv b\nrcv c\nrcv d\n" in part2 (interpreter pgm) :} 3
Interpreter
The Interpreter transforms a program from the world of instructions, registers, and program counters into only the effects of interpreting those programs. We'll be able to process these effects in order to answer the questions posed in part 1 and part 2 of this task.
Observable program execution effects
:: [Instruction] | instructions |
-> Integer | program ID |
-> Effect | program effect |
Compute the effect of executing a program starting at the first instruction using the given map as the initial set of registers.
Parser
The language defined by this problem is particularly simple and so is its parser. Each instruction can be found on its own line, and tokens in the language are separated by whitespace. Each instruction has one or two operands. Some of these operands need to be register names while others can be an expression composed of either an integer literal or a register name.
data Instruction Source #
Program instruction
Snd Expression |
|
Rcv Register |
|
Set Register Expression |
|
Add Register Expression |
|
Mul Register Expression |
|
Mod Register Expression |
|
Jgz Expression Expression |
|
Instances
Read Instruction Source # | |
Defined in Main readsPrec :: Int -> ReadS Instruction # readList :: ReadS [Instruction] # readPrec :: ReadPrec Instruction # readListPrec :: ReadPrec [Instruction] # | |
Show Instruction Source # | |
Defined in Main showsPrec :: Int -> Instruction -> ShowS # show :: Instruction -> String # showList :: [Instruction] -> ShowS # |
data Expression Source #
Expressions are either integer literals or register values
RegisterExpression Register | read from register |
IntegerExpression Integer | constant integer |
Instances
Read Expression Source # | |
Defined in Main readsPrec :: Int -> ReadS Expression # readList :: ReadS [Expression] # readPrec :: ReadPrec Expression # readListPrec :: ReadPrec [Expression] # | |
Show Expression Source # | |
Defined in Main showsPrec :: Int -> Expression -> ShowS # show :: Expression -> String # showList :: [Expression] -> ShowS # |
Register names: single letters
expression :: P Expression Source #