d04
Section
defmodule D04 do
# @ can also be used for constants, but it seems to be preferred
# in guards or places where a function would not work.
def deltas, do: for(dr <- -1..1, dc <- -1..1, do: {dr, dc}) -- [{0, 0}]
def parse(input) do
lists =
String.split(input, "\n", trim: true)
# charlist are deprecated but more convenient than Unicode strings.
|> Enum.map(&String.to_charlist/1)
for {row, i} <- Enum.with_index(lists),
{letter, j} <- Enum.with_index(row),
into: %{} do
{{i, j}, letter}
end
end
def matches?(_, [], _, _), do: true
def matches?(grid, [x | xs], {r, c}, {dr, dc}) do
Map.get(grid, {r, c}) == x &&
D04.matches?(grid, xs, {r + dr, c + dc}, {dr, dc})
end
def part1(grid) do
{height, width} = Enum.max(Map.keys(grid))
for row <- 0..height,
col <- 0..width,
delta <- D04.deltas() do
D04.matches?(grid, ~c"XMAS", {row, col}, delta)
end
|> Enum.count(& &1)
end
defp part2_pattern?(~c"AMMSS"), do: true
defp part2_pattern?(~c"AMSMS"), do: true
defp part2_pattern?(~c"ASMSM"), do: true
defp part2_pattern?(~c"ASSMM"), do: true
defp part2_pattern?(_), do: false
def part2(grid) do
{height, width} = Enum.max(Map.keys(grid))
for row <- 0..height,
col <- 0..width do
cross = [{0,0},{-1,-1},{-1,1},{1,-1},{1,1}]
|> Enum.map(fn {dr, dc} -> Map.get(grid, {row + dr, col + dc}) end)
if part2_pattern?(cross) do
1
else
0
end
end
|> Enum.sum()
end
end
sample = "MMMSXXMASM
MSAMXMSMSA
AMXSXMAAMM
MSAMASMSMX
XMASAMXAMM
XXAMMXXAMA
SMSMSASXSS
SAXAMASAAA
MAMMMXMMMM
MXMXAXMASX
"
sample_grid = D04.parse(sample)
18 = D04.part1(sample_grid)
9 = D04.part2(sample_grid)
input = File.read!(__DIR__ <> "/input")
grid = D04.parse(input)
D04.part1(grid)
D04.part2(grid)