summary refs log blame commit diff stats
path: root/day23.fsx
blob: 3378516661aadf1eb7581e2cb01838f22b2e5c19 (plain) (tree)


















































































































                                                                                                          
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