diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/day04.exs | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/src/day04.exs b/src/day04.exs new file mode 100644 index 0000000..990e04f --- /dev/null +++ b/src/day04.exs @@ -0,0 +1,110 @@ +defmodule Day04 do + def part1(data, word \\ ~c"XMAS") do + data = data + |> String.split("\n", trim: true) + |> Enum.map(&(:array.from_list(String.to_charlist(&1)))) + + count_word(0, data, word) + + count_word(0, data, Enum.reverse(word)) + end + + def count_word(acc, [], _) do + acc + end + + def count_word(acc, data, word) do + count_word(acc + count_word_hd(data, word), tl(data), word) + end + + def count_word_hd(data, word) do + 0..:array.size(hd(data))-1 + |> Enum.map(&(count_word_hd_col(data, word, &1))) + |> Enum.sum() + end + + def count_word_hd_col(data, word, col) do + [check_word_hori(data, word, col), + check_word_vert(data, word, col), + check_word_diag_right(data, word, col), + check_word_diag_left(data, word, col)] + |> Enum.count(&(&1)) + end + + def check_word_hori(data, word, col) do + check_word(data, word, col, &(&1), &(&1 + 1)) + end + + def check_word_vert(data, word, col) do + check_word(data, word, col, &tl/1, &(&1)) + end + + def check_word_diag_right(data, word, col) do + check_word(data, word, col, &tl/1, &(&1 + 1)) + end + + def check_word_diag_left(data, word, col) do + check_word(data, word, col, &tl/1, &(&1 - 1)) + end + + def check_word(data, word, col, data_step_fn, col_step_fn) do + cond do + word == [] -> + true + data == [] or col < 0 or col >= :array.size(hd(data)) -> + false + hd(word) == :array.get(col, hd(data)) -> + check_word( + data_step_fn.(data), + tl(word), + col_step_fn.(col), + data_step_fn, + col_step_fn + ) + true -> + false + end + end + + def part2(data, word \\ ~c"MAS") do + data = data + |> String.split("\n", trim: true) + |> Enum.map(&(:array.from_list(String.to_charlist(&1)))) + + count_cross(0, data, word) + end + + def count_cross(acc, [], _) do + acc + end + + def count_cross(acc, data, word) do + count_cross(acc + count_cross_hd(data, word), tl(data), word) + end + + def count_cross_hd(data, word) do + 0..:array.size(hd(data))-1 + |> Enum.count(&(check_cross_hd_col(data, word, &1))) + end + + def check_cross_hd_col(data, word, col) do + (check_word_diag_right(data, word, col) and + check_word_diag_left(data, word, col+2)) or + (check_word_diag_right(data, Enum.reverse(word), col) and + check_word_diag_left(data, word, col+2)) or + (check_word_diag_right(data, word, col) and + check_word_diag_left(data, Enum.reverse(word), col+2)) or + (check_word_diag_right(data, Enum.reverse(word), col) and + check_word_diag_left(data, Enum.reverse(word), col+2)) + end +end + +data = IO.read(:stdio, :eof) + +{time1 , ans1} = :timer.tc(fn -> Day04.part1(data) end) +IO.puts("Time : #{time1 / 1000000}") +IO.puts("Answer: #{ans1}") + +{time2 , ans2} = :timer.tc(fn -> Day04.part2(data) end) +IO.puts("Time : #{time2 / 1000000}") +IO.puts("Answer: #{ans2}") + |