Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Advent of Code - Day 4

livebooks/day4.livemd

Advent of Code - Day 4

Part 1

sample = """
MMMSXXMASM
MSAMXMSMSA
AMXSXMAAMM
MSAMASMSMX
XMASAMXAMM
XXAMMXXAMA
SMSMSASXSS
SAXAMASAAA
MAMMMXMMMM
MXMXAXMASX
"""
grid = 
sample
  |> String.split("\n", trim: true)

# turn it into a map
defmodule Part1 do
  def horizontal(grid) do
    gc = grid
     
    rc = grid
      |> Enum.map(&String.reverse/1)

    rc ++ gc
  end

  def vertical(grid) do
    column_strings = vertical_gen(grid)

    gc = column_strings

    rc = column_strings
      |> Enum.map(&String.reverse/1)

    rc ++ gc
  end

  def vertical_gen(grid) do
    cols = String.length(grid |> Enum.at(0))

    for j <- 0..(cols - 1) do
      grid
      |> Enum.map(&amp;String.at(&amp;1, j))
      |> Enum.join()
    end
  end

  def right_diagonals(grid) do
    rows = length(grid)
    cols = String.length(Enum.at(grid, 0))

    # Collect all right diagonals
    diags = (for start_col <- 0..(cols - 1), into: [] do
       extract_diagonal(grid, 0, start_col, 1, 1)
     end) ++
    (for start_row <- 1..(rows - 1), into: [] do
       extract_diagonal(grid, start_row, 0, 1, 1)
     end)

    (diags
      |> Enum.map(&amp;String.reverse(&amp;1)))
      ++ diags
  end

  def left_diagonals(grid) do
    rows = length(grid)
    cols = String.length(Enum.at(grid, 0))

    # Collect all left diagonals
    diags = (for start_col <- 0..(cols - 1), into: [] do
       extract_diagonal(grid, 0, start_col, 1, -1)
     end) ++
    (for start_row <- 1..(rows - 1), into: [] do
       extract_diagonal(grid, start_row, cols - 1, 1, -1)
     end)

    (diags
      |> Enum.map(&amp;String.reverse(&amp;1)))
      ++ diags
  end

  defp extract_diagonal(grid, start_row, start_col, row_step, col_step) do
    rows = length(grid)
    cols = String.length(Enum.at(grid, 0))

    Enum.reduce_while(0..(rows - 1), [], fn step, acc ->
      row = start_row + step * row_step
      col = start_col + step * col_step

      if row < rows and col >= 0 and col < cols do
        {:cont, [String.at(Enum.at(grid, row), col) | acc]}
      else
        {:halt, acc}
      end
    end)
    |> Enum.reverse()
    |> Enum.join("")
  end  

  def count_xmas_in_line(line) do
    Regex.scan(~r/XMAS/, line) |> Enum.count()
  end

  def count_all_matches(grid) do
    (horizontal(grid) ++ vertical(grid) ++ left_diagonals(grid) ++ right_diagonals(grid))
    |> Enum.reduce(0, fn line, acc -> count_xmas_in_line(line) + acc end)
  end
end
Part1.right_diagonals(grid) |> Enum.map(&amp;String.reverse(&amp;1))
Part1.count_all_matches(grid)
day1 = File.read!("/Users/errantsky/elixir-projects/phoenix-projects/advent_of_code_2024/inputs/day4.txt")

day1= day1
  |> String.split("\n", trim: true)

day1
  |> Part1.count_all_matches()

Part 2

sgrid = sample
  |> String.split("\n", trim: true)

sgrid |> Enum.at(0)
defmodule Part2 do
  def iterate(grid) do
    rows = grid |> length()
    cols = grid |> Enum.at(0) |> String.length()

    mat = grid
      |> Enum.with_index()
      |> Enum.map(fn {string, i} -> 
        String.graphemes(string)
          |> Enum.with_index()
          |> Enum.map(fn {char, j} -> {i, j, char} end)
        end)
      |> List.flatten()
      |> Enum.reduce(Map.new(), fn {i, j, char}, map -> Map.put(map, {i, j}, char) end)

    
    
    for i <- 1..(rows - 2) do
      for j <- 1..(cols - 2) do
        # -1 -1 is M
        # 0 0 is A
        # -1 1 S 
        # 1 -1 M 
        # 1 1 S 
        (Map.fetch!(mat, {i - 1, j - 1}) == "M" and
        Map.fetch!(mat, {i, j}) == "A" and
        Map.fetch!(mat, {i - 1, j + 1}) == "M" and
        Map.fetch!(mat, {i + 1, j - 1}) == "S" and
        Map.fetch!(mat, {i + 1, j + 1}) == "S") or
          (Map.fetch!(mat, {i - 1, j - 1}) == "M" and
        Map.fetch!(mat, {i, j}) == "A" and
        Map.fetch!(mat, {i - 1, j + 1}) == "S" and
        Map.fetch!(mat, {i + 1, j - 1}) == "M" and
        Map.fetch!(mat, {i + 1, j + 1}) == "S") or
          (Map.fetch!(mat, {i - 1, j - 1}) == "S" and
          Map.fetch!(mat, {i, j}) == "A" and
          Map.fetch!(mat, {i - 1, j + 1}) == "M" and
          Map.fetch!(mat, {i + 1, j - 1}) == "S" and
          Map.fetch!(mat, {i + 1, j + 1}) == "M") or
        (Map.fetch!(mat, {i - 1, j - 1}) == "S" and
          Map.fetch!(mat, {i, j}) == "A" and
          Map.fetch!(mat, {i - 1, j + 1}) == "S" and
          Map.fetch!(mat, {i + 1, j - 1}) == "M" and
          Map.fetch!(mat, {i + 1, j + 1}) == "M")

          
      end
    end 
  end
end
sgrid
Part2.iterate(sgrid)
Part2.iterate(sgrid)
|> List.flatten()
|> Enum.count(fn b -> b end)
Part2.iterate(day1)
|> List.flatten()
|> Enum.count(fn b -> b end)