aoc2020/day8.ml

58 lines
2.0 KiB
OCaml
Raw Normal View History

2020-12-09 00:51:24 +01:00
let read name =
let ic = open_in name in
let try_read () =
try Some (input_line ic)
with End_of_file -> None in
let rec loop acc =
match try_read () with
| Some s -> loop (s::acc)
| None -> close_in ic; acc in
List.rev (loop [])
let build lines =
let rec aux res idx = function
| h :: t -> let [instr; value] = String.split_on_char ' ' h in
let () = res.(idx) <- (0, instr, int_of_string value) in
aux res (idx + 1) t
| [] -> res in
aux (Array.make (List.length lines) (0, "nop", 0)) 0 lines
let rec step pc acc instructions =
let (n, instr, v) = instructions.(pc) in
let () = instructions.(pc) <- (n + 1, instr, v) in
match instr with
| "nop" -> (n + 1, pc + 1, acc)
| "acc" -> (n + 1, pc + 1, acc + v)
| "jmp" -> step (pc + v) acc instructions
| _ -> raise (Failure "unreachable")
let run instructions =
let rec aux pc acc instructions =
match step pc acc instructions with
| (2, _, _) -> raise (Failure (Printf.sprintf "Loop detected with accumulator %d!" acc))
| (_, pc, result) when pc = (Array.length instructions - 1) -> result
| (_, pc, acc_) -> aux pc acc_ instructions
in aux 0 0 instructions
let rec swap_from idx ins =
match ins.(idx) with
| (_, "nop", v) when v <> 0 -> let () = ins.(idx) <- (0, "jmp", v) in (idx + 1, ins)
| (_, "jmp", v) -> let () = ins.(idx) <- (0, "nop", v) in (idx + 1, ins)
| _ -> swap_from (idx + 1) ins
let fix instructions =
let rec aux idx ins instructions =
try run ins
with e -> let (i, ins) = swap_from idx (Array.copy instructions) in
aux i ins instructions
in aux 0 (Array.copy instructions) instructions
let () = try let _ = read "day8.input" |> build |> run in ()
with Failure msg -> print_endline msg
let () = print_endline (string_of_int (read "day8.input" |> build |> fix))