#!nix-shell --pure -i ocaml -p ocaml
*)
let grid_size = (101, 103)
let midpoint = (fst grid_size / 2, snd grid_size / 2)
type robot = {p: int * int; v: int * int}
let input : robot list =
let parse_coord coord =
match
String.sub coord 2 (String.length coord - 2) |> String.split_on_char ','
with
| [x; y] ->
(int_of_string x, int_of_string y)
| _ ->
failwith "invalid coord"
in
let parse_line line =
match String.split_on_char ' ' line with
| [pos; vel] ->
{p= parse_coord pos; v= parse_coord vel}
| _ ->
failwith "invalid line format"
in
let rec read_input acc =
try (read_line () |> parse_line) :: acc |> read_input
with End_of_file -> acc
in
read_input []
let interpolate n =
let positive_mod x m = ((x mod m) + m) mod m in
let interpolate_single robot : robot =
{ p=
( positive_mod (fst robot.p + (fst robot.v * n)) (fst grid_size)
, positive_mod (snd robot.p + (snd robot.v * n)) (snd grid_size) )
; v= robot.v }
in
input |> List.map interpolate_single
let find_in_segments robots =
let in_segment robot =
if fst robot.p < fst midpoint && snd robot.p < snd midpoint then
Some 0
else if fst robot.p > fst midpoint && snd robot.p < snd midpoint then
Some 1
else if fst robot.p < fst midpoint && snd robot.p > snd midpoint then
Some 2
else if fst robot.p > fst midpoint && snd robot.p > snd midpoint then
Some 3
else None
in
robots |> List.filter_map in_segment
module IntMap = Map.Make (struct
type t = int
let compare = compare
end)
let group_and_mul lst =
let aux acc x =
let count = (IntMap.find_opt x acc |> Option.value ~default:0) + 1 in
IntMap.add x count acc
in
let fold _key value acc = acc * value in
let grouped = lst |> List.fold_left aux IntMap.empty in
IntMap.fold fold grouped 1
let rec debug = function
| x :: xs ->
print_int x |> print_newline ;
debug xs
| [] ->
()
let rec debug' robots =
let print_robot robot =
print_string "x=" ;
print_int (fst robot.p) ;
print_string " y=" ;
print_int (snd robot.p) |> print_newline
in
match robots with x :: xs -> print_robot x ; debug' xs | [] -> ()
let part1 =
interpolate 100 |> find_in_segments |> group_and_mul |> print_int
|> print_newline
let part2 =
let rec heuristic seen xs =
match xs with
| [] ->
true
| x :: xs ->
if List.mem x seen then false else heuristic (x :: seen) xs
in
let rec debug x y curr =
if x > fst grid_size then (
print_newline () ;
debug 0 (y + 1) curr )
else if y > snd grid_size then print_newline ()
else if List.mem (x, y) curr then (
print_int 1 ;
debug (x + 1) y curr )
else (
print_char '.' ;
debug (x + 1) y curr )
in
let rec aux n =
let curr = interpolate n |> List.map (fun robot -> robot.p) in
if heuristic [] curr then (
print_int n |> print_newline ;
debug 0 0 curr )
else aux (n + 1)
in
aux 0