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<string, Lit> = 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