summary refs log tree commit diff stats
path: root/day18.fsx
blob: 383519ff66879bdb5d72ab10bc5333af3e7ef3c1 (plain) (blame)
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
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 =
    | Snd of x: Value
    | Set of x: Register * y: Value
    | Add of x: Register * y: Value
    | Mul of x: Register * y: Value
    | Mod of x: Register * y: Value
    | Rcv of x: Value
    | Jgz 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 "snd ([a-p])" [x]              -> Snd (Reg x)
    | InstRegex "snd (-?\d+)" [x]              -> Snd (Literal (int x))
    | 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 "add ([a-p]) ([a-p])" [x; y]   -> Add (x, Reg y)
    | InstRegex "add ([a-p]) (-?\d+)" [x; y]   -> Add (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 "mod ([a-p]) ([a-p])" [x; y]   -> Mod (x, Reg y)
    | InstRegex "mod ([a-p]) (-?\d+)" [x; y]   -> Mod (x, Literal (int y))
    | InstRegex "rcv ([a-p])" [x]              -> Rcv (Reg x)
    | InstRegex "rcv (-?\d+)" [x]              -> Rcv (Literal (int x))
    | InstRegex "jgz ([a-p]) ([a-p])" [x; y]   -> Jgz (Reg x, Reg y)
    | InstRegex "jgz ([a-p]) (-?\d+)" [x; y]   -> Jgz (Reg x, Literal (int y))
    | InstRegex "jgz (-?\d+) ([a-p])" [x; y]   -> Jgz (Literal (int x), Reg y)
    | InstRegex "jgz (-?\d+) (-?\d+)" [x; y]   -> Jgz (Literal (int x), Literal (int y))
    | x -> printfn "%A" x; failwith "invalid input"

let rec executeInst (instructions: Instruction array) registers (index: int64) lastSound =
    match instructions.[int index] with
    | Snd x -> 
        executeInst instructions registers (index + 1L) (resolveValue x registers)
    | Set(x, y) -> 
        if not (registers.ContainsKey(x)) then registers.[x] <- 0
        registers.[x] <- resolveValue y registers
        executeInst instructions registers (index + 1L) lastSound
    | Add(x, y) ->
        if not (registers.ContainsKey(x)) then registers.[x] <- 0
        registers.[x] <- registers.[x] + resolveValue y registers
        executeInst instructions registers (index + 1L) lastSound
    | Mul(x, y) -> 
        if not (registers.ContainsKey(x)) then registers.[x] <- 0
        registers.[x] <- registers.[x] * resolveValue y registers
        executeInst instructions registers (index + 1L) lastSound
    | Mod(x, y) -> 
        if not (registers.ContainsKey(x)) then registers.[x] <- 0
        registers.[x] <- registers.[x] % resolveValue y registers
        executeInst instructions registers (index + 1L) lastSound
    | Rcv x -> 
        if (resolveValue x registers) > 0 then lastSound else executeInst instructions registers (index + 1L) lastSound
    | Jgz(x, y) ->
        if (resolveValue x registers) > 0 then
            executeInst instructions registers (index + resolveValue y registers) lastSound
        else
            executeInst instructions registers (index + 1L) lastSound

let () =
    let registers = new Dictionary<string, int64>()
    let input = File.ReadAllLines "day18.txt" |> Array.map parseValue
    let recovered = executeInst input registers 0 0
    printfn "%A" recovered