(* Common util. Should probably put this in a module or something.. *) let explode s = (* convert a string to a list of chars *) let rec exp i l = if i < 0 then l else exp (i - 1) (s.[i] :: l) in exp (String.length s - 1) [] let implode l = String.of_seq (List.to_seq l) let (<<) f g x = f(g(x)) let (>>) f g x = g(f(x)) let rec uniq = function (* dedups a list *) | [] -> [] | x :: xs -> if List.mem x xs then uniq xs else x :: (uniq xs) (* --- *) let string_of_cube (x, y, z, w) = Printf.sprintf "(%i, %i, %i, %i) " x y z w let print_cube = print_string << string_of_cube let print_cubes cubes = (List.map print_cube cubes; print_newline ()) let read_grid lines = (* string list to active cube list *) List.mapi (fun x line -> List.mapi (fun y cell -> if cell = '#' then Some (x, y, 0, 0) else None ) (explode line) ) lines |> List.concat |> List.filter Option.is_some |> List.map Option.get let neighbor_d = [-1; 0; 1] (* donno how to do this nicely.. *) let find_neighbors (x, y, z, w) = (* find all of the neighboring cubes *) List.map (fun dx -> List.map (fun dy -> List.map (fun dz -> List.map (fun dw -> (x + dx, y + dy, z + dz, w + dw) ) neighbor_d ) neighbor_d ) neighbor_d ) neighbor_d |> List.concat |> List.concat |> List.concat (* flatten *) |> List.filter (fun (x', y', z', w') -> not (x = x' && y = y' && z = z' && w = w')) (* remove the point itself *) let update position cubes = (* returns true if this position should be active *) let neighbors = find_neighbors position in let active_neighbors = List.filter (fun x -> List.mem x cubes) neighbors in let num_active_neighbors = List.length active_neighbors in let active = List.mem position cubes in let active' = num_active_neighbors = 3 || (active && num_active_neighbors = 2) in num_active_neighbors = 3 || (active && num_active_neighbors = 2) let cycle cubes = let neighbors = List.map find_neighbors cubes |> List.concat in let uniq_neighbors = uniq neighbors in let cubes' = List.map (fun n -> (n, update n cubes)) uniq_neighbors in List.filter_map (fun (c, active) -> if active then Some c else None) cubes' (* only return the active ones *) let rec go cubes n = (* cycle n times *) Printf.printf "GO! %i\n" n; match n with | 0 -> cubes | n -> go (cycle cubes) (n - 1) let () = let test = [ ".#."; "..#"; "###"; ] in let start = [ "...###.#"; "#.#.##.."; ".##.##.."; "..##...#"; ".###.##."; ".#..##.."; ".....###"; ".####..#"; ] in let cubes = read_grid start in print_string "starting coordinates\n"; print_cubes cubes; print_newline (); let n = 6 in let cubes' = go cubes n in Printf.printf "after %i cycle(s)\n" n; print_cubes cubes'; let count = List.length cubes' in Printf.printf "count: %i\n" count;