2024 day 17 part 1

This commit is contained in:
2024-12-17 08:58:31 +00:00
parent f271e93e63
commit 80e923b074
2 changed files with 120 additions and 2 deletions

116
bin/day2417.ml Normal file
View File

@@ -0,0 +1,116 @@
type vm = {
a : int;
b : int;
c : int;
ip : int;
code : int array;
out : int list;
}
let vm_of_strings lst =
let re_val = Str.regexp {|Register [ABC]: \([0-9]+\)|} in
let re_prog = Str.regexp {|Program: \([0-9,]+\)|} in
let get_val = function
| [] -> failwith "vm_of_strings.get_val"
| h :: t ->
let _ = Str.search_forward re_val h 0 in
(int_of_string (Str.matched_group 1 h), t)
in
let skip_line = function
| "" :: t -> t
| _ -> failwith "vm_of_strings.skip_line"
in
let get_code = function
| [] -> failwith "vm_of_strings.get_prog"
| h :: t ->
let _ = Str.search_forward re_prog h 0 in
let nums =
Str.matched_group 1 h |> Aoc.ints_of_string ~sep:"," |> Array.of_list
in
(nums, t)
in
let a, lst = get_val lst in
let b, lst = get_val lst in
let c, lst = get_val lst in
let lst = skip_line lst in
let code, lst = get_code lst in
let ip = 0 in
let out = [] in
assert (List.is_empty lst);
{ a; b; c; ip; code; out }
let vm_of_file fname = Aoc.strings_of_file fname |> vm_of_strings
let get_literal vm = vm.code.(vm.ip + 1)
let print_combo vm =
match vm.code.(vm.ip + 1) with
| 0 | 1 | 2 | 3 -> print_int vm.code.(vm.ip + 1)
| 4 -> Printf.printf "A (=%d)" vm.a
| 5 -> Printf.printf "B (=%d)" vm.a
| 6 -> Printf.printf "C (=%d)" vm.a
| 7 -> failwith "print_combo reserved"
| _ -> failwith "print_combo not 3-bit"
let get_combo vm =
match vm.code.(vm.ip + 1) with
| 0 | 1 | 2 | 3 -> vm.code.(vm.ip + 1)
| 4 -> vm.a
| 5 -> vm.b
| 6 -> vm.c
| 7 -> failwith "get_combo reserved"
| _ -> failwith "get_combo not 3-bit"
let is_halted vm = vm.ip >= Array.length vm.code || vm.ip < 0
let print_insn vm =
Printf.printf "%d: " vm.ip;
if is_halted vm then print_endline "Halted"
else Printf.printf "%d " vm.code.(vm.ip);
(match vm.code.(vm.ip) with
| 0 ->
print_string "adv ";
print_combo vm
| 1 -> Printf.printf "bxl %d" (get_literal vm)
| 2 ->
print_string "bst ";
print_combo vm
| 3 -> Printf.printf "jnz %d" (get_literal vm)
| 4 -> print_string "bxc"
| 5 ->
print_string "out ";
print_combo vm
| 6 ->
print_string "bdv ";
print_combo vm
| 7 ->
print_string "cdv ";
print_combo vm
| _ -> failwith "print_insn");
Printf.printf " A=%d B=%d C=%d\n" vm.a vm.b vm.c
let execute_insn vm =
if is_halted vm then vm
else (
print_insn vm;
match vm.code.(vm.ip) with
| 0 -> { vm with a = vm.a / (1 lsl get_combo vm); ip = vm.ip + 2 }
| 1 -> { vm with b = vm.b lxor get_literal vm; ip = vm.ip + 2 }
| 2 -> { vm with b = get_combo vm land 7; ip = vm.ip + 2 }
| 3 ->
if vm.a <> 0 then { vm with ip = get_literal vm }
else { vm with ip = vm.ip + 2 }
| 4 -> { vm with b = vm.b lxor vm.c; ip = vm.ip + 2 }
| 5 -> { vm with out = (get_combo vm land 7) :: vm.out; ip = vm.ip + 2 }
| 6 -> { vm with b = vm.a / (1 lsl get_combo vm); ip = vm.ip + 2 }
| 7 -> { vm with c = vm.a / (1 lsl get_combo vm); ip = vm.ip + 2 }
| _ -> failwith "execute_insn")
let rec execute_until_halted vm =
match is_halted vm with
| true -> vm
| false -> execute_until_halted (execute_insn vm)
let string_of_output vm =
List.rev vm.out |> List.map string_of_int |> String.concat ","
let _ = Aoc.main vm_of_file [ (string_of_output, execute_until_halted) ]

View File

@@ -15,7 +15,8 @@
day2413
day2414
day2415
day2416)
day2416
day2417)
(names
day2401
day2402
@@ -32,5 +33,6 @@
day2413
day2414
day2415
day2416)
day2416
day2417)
(libraries str aoc))