Day 4
Mix.install([
{:aoc2024, path: "."}
])
Input
sample = """
MMMSXXMASM
MSAMXMSMSA
AMXSXMAAMM
MSAMASMSMX
XMASAMXAMM
XXAMMXXAMA
SMSMSASXSS
SAXAMASAAA
MAMMMXMMMM
MXMXAXMASX
"""
input = "priv/day4.txt"
Part 1
defmodule Part1 do
def mapper({row, row_i}) do
row
|> String.split("", trim: true)
|> Enum.with_index()
|> Enum.map(fn {val, col_i} -> {{row_i, col_i}, val} end)
end
def get_perms(poss) do
poss
|> Enum.flat_map(&flat_mapper/1)
end
defp flat_mapper({pos, "X"}) do
{row_i, col_i} = pos
perm =
[
[{row_i, col_i}, {row_i - 1, col_i - 1}, {row_i - 2, col_i - 2}, {row_i - 3, col_i - 3}],
[{row_i, col_i}, {row_i - 1, col_i}, {row_i - 2, col_i}, {row_i - 3, col_i}],
[{row_i, col_i}, {row_i - 1, col_i + 1}, {row_i - 2, col_i + 2}, {row_i - 3, col_i + 3}],
[{row_i, col_i}, {row_i, col_i - 1}, {row_i, col_i - 2}, {row_i, col_i - 3}],
[{row_i, col_i}, {row_i, col_i + 1}, {row_i, col_i + 2}, {row_i, col_i + 3}],
[{row_i, col_i}, {row_i + 1, col_i - 1}, {row_i + 2, col_i - 2}, {row_i + 3, col_i - 3}],
[{row_i, col_i}, {row_i + 1, col_i}, {row_i + 2, col_i}, {row_i + 3, col_i}],
[{row_i, col_i}, {row_i + 1, col_i + 1}, {row_i + 2, col_i + 2}, {row_i + 3, col_i + 3}]
]
perm
end
defp flat_mapper(_), do: []
end
poss =
sample
|> AoC2024.parse(&Part1.mapper/1)
|> List.flatten()
|> Map.new()
poss
|> Part1.get_perms()
|> Enum.filter(fn perm ->
word = Enum.map(perm, & poss[&1])
word == ["X", "M", "A", "S"] || word == ["S", "A", "M", "X"]
end)
|> length
poss =
AoC2024.load_text(input)
|> AoC2024.parse(&Part1.mapper/1)
|> List.flatten()
|> Map.new()
poss
|> Part1.get_perms()
|> Enum.filter(fn perm ->
word = Enum.map(perm, & poss[&1])
word == ["X", "M", "A", "S"] || word == ["S", "A", "M", "X"]
end)
|> length
Part 2
defmodule Part2 do
def mapper({row, row_i}) do
row
|> String.split("", trim: true)
|> Enum.with_index()
|> Enum.map(fn {val, col_i} -> {{row_i, col_i}, val} end)
end
def get_perms(poss) do
poss
|> Enum.flat_map(&flat_mapper(&1, poss))
end
defp flat_mapper({pos, "A"}, poss) do
{row_i, col_i} = pos
[[
{row_i, col_i}, # center
{row_i - 1, col_i - 1}, # top-left
{row_i - 1, col_i + 1}, # top-right
{row_i + 1, col_i - 1}, # bottom-left
{row_i + 1, col_i + 1} # bottom-right
]]
[
[
{row_i, col_i}, # "A" center
{row_i - 1, col_i - 1}, # Top-left "M"
{row_i + 1, col_i - 1}, # Bottom-left "M"
{row_i - 1, col_i + 1}, # Top-right "S"
{row_i + 1, col_i + 1} # Bottom-right "S"
]
]
end
defp flat_mapper(_, _), do: []
end
poss =
sample
|> AoC2024.parse(&Part2.mapper/1)
|> List.flatten()
|> Map.new()
poss
|> Part2.get_perms()
|> Enum.filter(fn perm ->
word = Enum.map(perm, &poss[&1])
word in [
["A", "M", "S", "M", "S"],
["A", "S", "M", "S", "M"],
["A", "M", "M", "S", "S"],
["A", "S", "S", "M", "M"]
]
end)
|> length
poss =
input
|> AoC2024.load_text()
|> AoC2024.parse(&Part2.mapper/1)
|> List.flatten()
|> Map.new()
poss
|> Part2.get_perms()
|> Enum.filter(fn perm ->
word = Enum.map(perm, &poss[&1])
word in [
["A", "M", "S", "M", "S"],
["A", "S", "M", "S", "M"],
["A", "M", "M", "S", "S"],
["A", "S", "S", "M", "M"]
]
end)
|> length
defmodule Temp do
def mapper({row, row_i}) do
row
|> String.split("", trim: true)
|> Enum.with_index()
|> Enum.map(fn {val, col_i} -> {{row_i, col_i}, val} end)
end
def get_perms(poss) do
poss
|> Enum.flat_map(&flat_mapper(&1, poss))
end
defp flat_mapper({pos, "A"}, poss) do
{row_i, col_i} = pos
[
[
{row_i, col_i}, # Center (A)
{row_i - 1, col_i - 1}, # Top-left (M)
{row_i - 1, col_i + 1}, # Top-right (S)
{row_i + 1, col_i - 1}, # Bottom-left (S)
{row_i + 1, col_i + 1} # Bottom-right (M)
]
]
|> Enum.filter(&valid_positions?(&1, poss))
end
defp flat_mapper(_, _), do: []
defp valid_positions?(positions, poss) do
Enum.all?(positions, &Map.has_key?(poss, &1))
end
def count_xmas(sample) do
# Parse the grid into positions
poss =
sample
|> Enum.with_index()
|> Enum.flat_map(&mapper/1)
|> Map.new()
# Find all "X-MAS" permutations and count valid patterns
poss
|> get_perms()
|> Enum.filter(fn perm ->
word = Enum.map(perm, &poss[&1])
word == ["A", "M", "S", "M", "S"] || word == ["A", "S", "M", "S", "M"]
end)
|> length()
end
end
# Original Sample Test Input
sample = [
"MMMSXXMASM",
"MSAMXMSMSA",
"AMXSXMAAMM",
"MSAMASMSMX",
"XMASAMXAMM",
"XXAMMXXAMA",
"SMSMSASXSS",
"SAXAMASAAA",
"MAMMMXMMMM",
"MXMXAXMASX"
]
# Run the test
result = Temp.count_xmas(sample)
IO.puts("Number of X-MAS patterns: #{result}")