58 lines
2.0 KiB
OCaml
58 lines
2.0 KiB
OCaml
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 _ -> 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))
|