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
|
open System.IO
open System.Collections.Generic
open System.Text.RegularExpressions
type Register = string
type Value =
| Literal of int64
| Reg of Register
let (|InstRegex|_|) pattern string =
let m = Regex(pattern).Match(string)
if m.Success then
Some(List.tail [for g in m.Groups -> g.Value])
else None
type Instruction =
| Set of x: Register * y: Value
| Sub of x: Register * y: Value
| Mul of x: Register * y: Value
| Jnz of x: Value * y: Value
let resolveValue (value: Value) (registers: Dictionary<string, int64> ) =
let tryGetDefaultRegister key =
if not (registers.ContainsKey(key)) then registers.[key] <- 0L
registers.[key]
match value with
| Literal x -> x
| Reg x -> tryGetDefaultRegister x
let parseValue line =
match line with
| InstRegex "set ([a-p]) ([a-p])" [x; y] -> Set (x, Reg y)
| InstRegex "set ([a-p]) (-?\d+)" [x; y] -> Set (x, Literal (int y))
| InstRegex "sub ([a-p]) ([a-p])" [x; y] -> Sub (x, Reg y)
| InstRegex "sub ([a-p]) (-?\d+)" [x; y] -> Sub (x, Literal (int y))
| InstRegex "mul ([a-p]) ([a-p])" [x; y] -> Mul (x, Reg y)
| InstRegex "mul ([a-p]) (-?\d+)" [x; y] -> Mul (x, Literal (int y))
| InstRegex "jnz ([a-p]) ([a-p])" [x; y] -> Jnz (Reg x, Reg y)
| InstRegex "jnz ([a-p]) (-?\d+)" [x; y] -> Jnz (Reg x, Literal (int y))
| InstRegex "jnz (-?\d+) ([a-p])" [x; y] -> Jnz (Literal (int x), Reg y)
| InstRegex "jnz (-?\d+) (-?\d+)" [x; y] -> Jnz (Literal (int x), Literal (int y))
| x -> printfn "%A" x; failwith "invalid input"
let rec executeInst (instructions: Instruction array) (registers: Dictionary<string, int64>) (index: int64) mulCount =
if (int index) >= Array.length instructions || (int index) < 0 then mulCount
else
match instructions.[int index] with
| Set(x, y) ->
if not (registers.ContainsKey(x)) then registers.[x] <- 0
registers.[x] <- resolveValue y registers
executeInst instructions registers (index + 1L) mulCount
| Sub(x, y) ->
if not (registers.ContainsKey(x)) then registers.[x] <- 0
registers.[x] <- registers.[x] - resolveValue y registers
executeInst instructions registers (index + 1L) mulCount
| Mul(x, y) ->
if not (registers.ContainsKey(x)) then registers.[x] <- 0
registers.[x] <- registers.[x] * resolveValue y registers
executeInst instructions registers (index + 1L) (mulCount + 1)
| Jnz(x, y) ->
if (resolveValue x registers) <> 0 then
executeInst instructions registers (index + resolveValue y registers) mulCount
else
executeInst instructions registers (index + 1L) mulCount
let part1() =
let registers = new Dictionary<string, int64>()
let input = File.ReadAllLines "day23.txt" |> Array.map parseValue
let mulCount = executeInst input registers 0 0
printfn "%A" mulCount
// i knew it couldn't be that easy :(
// time to decompile the assembly and figure out what's happening
// let part2() =
// let registers = new Dictionary<string, int64>()
// registers.["a"] <- 1
// let input = File.ReadAllLines "day23.txt" |> Array.map parseValue
// executeInst input registers 0 0 |> ignore
// printfn "%A" registers.["h"]
let () =
part1()
|