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}")