solve_2.ml 4.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. open Stdio
  2. open Str
  3. let input_info =
  4. let rec one_string inp nb_rows nb_columns =
  5. let line = In_channel.input_line In_channel.stdin in
  6. match line with
  7. | None -> (inp, (nb_rows, nb_columns))
  8. | Some x -> one_string (inp ^ x) (nb_rows + 1) (String.length x)
  9. in one_string "" 0 0
  10. ;;
  11. let input = fst input_info;;
  12. let input_mutable = Bytes.of_string input;;
  13. let nb_rows = (fst (snd input_info));;
  14. let nb_columns = (snd (snd input_info));;
  15. type coords = {
  16. position : int;
  17. direction : char;
  18. }
  19. module CoordsOrd : Set.OrderedType with type t = coords = struct
  20. type t = coords
  21. let compare p1 p2 =
  22. match Int.compare p1.position p2.position with
  23. | 0 -> Char.compare p1.direction p2.direction
  24. | c -> c
  25. end
  26. module CoordsSet = Set.Make(CoordsOrd)
  27. let initial_pos = search_forward (regexp {|\^\|<\|>\|v|}) input 0;;
  28. let guard_direction = input.[initial_pos];;
  29. let rec run_guard pos direction l_pos =
  30. if (pos < 0 || pos >= (nb_rows*nb_columns)) then (List.tl l_pos) else
  31. match direction with
  32. | '^' -> let new_pos = (pos - nb_columns) in
  33. if (new_pos >= 0 && input.[new_pos] == '#') then run_guard pos '>' l_pos else run_guard new_pos '^' (new_pos::l_pos)
  34. | 'v' -> let new_pos = (pos + nb_columns) in
  35. if (new_pos < (nb_rows*nb_columns) && input.[new_pos] == '#') then run_guard pos '<' l_pos else run_guard new_pos 'v' (new_pos::l_pos)
  36. | '<' -> let new_pos = (pos - 1) in
  37. if (new_pos mod nb_columns == nb_columns -1) then (List.tl l_pos) else
  38. if (new_pos >= 0 && input.[new_pos] == '#') then run_guard pos '^' l_pos else run_guard new_pos '<' (new_pos::l_pos)
  39. | '>' -> let new_pos = (pos + 1) in
  40. if (new_pos mod nb_columns == 0) then (List.tl l_pos) else
  41. if (new_pos < (nb_rows*nb_columns) && input.[new_pos] == '#') then run_guard pos 'v' l_pos else run_guard new_pos '>' (new_pos::l_pos)
  42. | _ -> [] (*Not supposed to happen*)
  43. let rec eliminate_duplicates = function
  44. | a :: (b :: _ as t) -> if a = b then eliminate_duplicates t else a :: eliminate_duplicates t
  45. | smaller -> smaller;;
  46. let potential_obstacles = eliminate_duplicates (List.sort compare (run_guard initial_pos guard_direction [initial_pos]));;
  47. let rec is_run_a_loop new_map pos direction visited_states_set=
  48. if (pos < 0 || pos >= (nb_rows*nb_columns)) then false else
  49. (if (CoordsSet.mem {position = pos; direction = direction} visited_states_set) then true else
  50. match direction with
  51. | '^' -> let new_pos = (pos - nb_columns) in
  52. if (new_pos >= 0 && (Bytes.get new_map new_pos) == '#') then
  53. is_run_a_loop new_map pos '>' (visited_states_set |> CoordsSet.add {position = pos; direction = '^'}) else
  54. is_run_a_loop new_map new_pos '^' (visited_states_set |> CoordsSet.add {position = pos; direction = '^'})
  55. | 'v' -> let new_pos = (pos + nb_columns) in
  56. if (new_pos < (nb_rows*nb_columns) && (Bytes.get new_map new_pos) == '#') then
  57. is_run_a_loop new_map pos '<' (visited_states_set |> CoordsSet.add {position = pos; direction = 'v'})else
  58. is_run_a_loop new_map new_pos 'v' (visited_states_set |> CoordsSet.add {position = pos; direction = 'v'})
  59. | '<' -> let new_pos = (pos - 1) in
  60. if (new_pos mod nb_columns == nb_columns -1) then false else
  61. if (new_pos >= 0 && (Bytes.get new_map new_pos) == '#') then
  62. is_run_a_loop new_map pos '^' (visited_states_set |> CoordsSet.add {position = pos; direction = '<'}) else
  63. is_run_a_loop new_map new_pos '<' (visited_states_set |> CoordsSet.add {position = pos; direction = '<'})
  64. | '>' -> let new_pos = (pos + 1) in
  65. if (new_pos mod nb_columns == 0) then false else
  66. if (new_pos < (nb_rows*nb_columns) && (Bytes.get new_map new_pos) == '#') then
  67. is_run_a_loop new_map pos 'v' (visited_states_set |> CoordsSet.add {position = pos; direction = '>'}) else
  68. is_run_a_loop new_map new_pos '>' (visited_states_set |> CoordsSet.add {position = pos; direction = '>'})
  69. | _ -> false) (*Not supposed to happen*)
  70. let solve =
  71. let aux accum pos=
  72. if pos > (nb_columns*nb_rows) then accum else
  73. if (pos == initial_pos) then accum else
  74. (Bytes.set input_mutable pos '#';
  75. if (is_run_a_loop input_mutable initial_pos guard_direction (CoordsSet.empty))
  76. then (Bytes.set input_mutable pos '.';(accum + 1))
  77. else (Bytes.set input_mutable pos '.';accum))
  78. in
  79. List.fold_left aux 0 potential_obstacles ;;
  80. let () = printf "Total: %d\n" solve;;