open System.IO type Reg = string type Lit = int type Value = | LiteralVal of literal: Lit | Register of register: Reg type Instruction = | Cpy of copied: Value * register: Reg | Inc of register: Reg | Dec of register: Reg | Jnz of compared: Value * offset: Value | Tgl of offset: Value | Nop let parseInstruction (line:string): Instruction = let split = line.Split " " match split[0] with | "inc" -> Inc split[1] | "dec" -> Dec split[1] | "cpy" -> let mutable parsed = 0 if (System.Int32.TryParse(split[1], &parsed)) then Cpy (LiteralVal parsed, split[2]) else Cpy (Register split[1], split[2]) | "jnz" -> let mutable parsed1 = 0 if (System.Int32.TryParse(split[1], &parsed1)) then let mutable parsed2 = 0 if (System.Int32.TryParse(split[2], &parsed2)) then Jnz (LiteralVal parsed1, LiteralVal parsed2) else Jnz (LiteralVal parsed1, Register split[2]) else let mutable parsed2 = 0 if (System.Int32.TryParse(split[2], &parsed2)) then Jnz (Register split[1], LiteralVal parsed2) else Jnz (Register split[1], Register split[2]) | "tgl" -> let mutable parsed = 0 if (System.Int32.TryParse(split[1], &parsed)) then Tgl (LiteralVal parsed) else Tgl (Register split[1]) | _ -> Inc "" let toggleInst (inst: Instruction) : Instruction = match inst with | Inc reg -> Dec reg | Dec reg -> Inc reg | Tgl offset -> match offset with | LiteralVal v-> Nop | Register r -> Inc r | Cpy (copied, register) -> Jnz (copied, Register register) | Jnz (compared, offset) -> match offset with | LiteralVal v-> Nop | Register r -> Cpy (compared, r) | Nop -> Nop let rec execute index insts registers = if index < 0 || index > (Array.length insts) - 1 then Map.find "a" registers else match insts[index] with | Cpy (value, reg) -> let copied = match value with | LiteralVal num -> num | Register reg -> Map.find reg registers let newRegisters = Map.change reg (function | Some x -> Some copied | None -> None) registers execute (index + 1) insts newRegisters | Inc reg -> let newRegisters = Map.change reg (function | Some x -> Some (x + 1) | None -> None) registers execute (index + 1) insts newRegisters | Dec reg -> let newRegisters = Map.change reg (function | Some x -> Some (x - 1) | None -> None) registers execute (index + 1) insts newRegisters | Jnz (reg, offset) -> let offset = match offset with | LiteralVal x -> x | Register x -> Map.find x registers let compared = match reg with | LiteralVal num -> num | Register reg -> Map.find reg registers if compared <> 0 then execute (index + offset) insts registers else execute (index + 1) insts registers | Tgl offset -> let offset = match offset with | LiteralVal x -> x | Register x -> Map.find x registers let newIndex = index + offset let newInsts = Array.mapi (fun i v -> match i with | _ when i = newIndex -> toggleInst v | _ -> v) insts execute (index + 1) newInsts registers | Nop -> execute (index + 1) insts registers let lines = File.ReadAllLines "day23.txt" |> Array.map parseInstruction let regsPart1: Map = Map.ofList [("a", 7); ("b", 0); ("c", 0); ("d", 0)] execute 0 lines regsPart1 |> printfn "%d" // analysis of the code indicates it actually calculates reg[a]! + some constant derived from the code // in this case, the constant is 90 * 81 // thus part 2 is 90 * 81 + 12! = 479008890