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 ) = 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) (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() 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() // registers.["a"] <- 1 // let input = File.ReadAllLines "day23.txt" |> Array.map parseValue // executeInst input registers 0 0 |> ignore // printfn "%A" registers.["h"] let () = part1()