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 ) = 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() let input = File.ReadAllLines "day18.txt" |> Array.map parseValue let recovered = executeInst input registers 0 0 printfn "%A" recovered