From aecafff2679472ac1ad26391048c5e5ed71d0c59 Mon Sep 17 00:00:00 2001 From: sloane Date: Wed, 4 Dec 2024 08:20:10 -0500 Subject: [PATCH] solve 2024 day 4 --- 2024/README.md | 3 +- 2024/lib/2024/4.ex | 105 +++++++++++++++++++++++++++++++++++++++++++++ README.md | 2 +- 3 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 2024/lib/2024/4.ex diff --git a/2024/README.md b/2024/README.md index 88d41bf..e49d199 100644 --- a/2024/README.md +++ b/2024/README.md @@ -2,7 +2,7 @@ | S | M | T | W | T | F | S | | :-: | :-: | :-: | :-: | :-: | :-: | :-: | -| [1] | [2] | [3] | 4 | 5 | 6 | 7 | +| [1] | [2] | [3] | [4] | 5 | 6 | 7 | | 8 | 9 | 10 | 11 | 12 | 13 | 14 | | 15 | 16 | 17 | 18 | 19 | 20 | 21 | | 22 | 23 | 24 | 25 | | | | @@ -10,3 +10,4 @@ [1]: ./lib/2024/1.ex [2]: ./lib/2024/2.ex [3]: ./lib/2024/3.ex +[4]: ./lib/2024/4.ex diff --git a/2024/lib/2024/4.ex b/2024/lib/2024/4.ex new file mode 100644 index 0000000..0b3b0b0 --- /dev/null +++ b/2024/lib/2024/4.ex @@ -0,0 +1,105 @@ +import AOC + +aoc 2024, 4 do + @directions ~w[n ne e se s sw w nw]a + + def p1(input) do + grid = to_grid(input) + {xs, ys} = bounds(grid) + + pos_and_dirs = for x <- xs, y <- ys, dir <- @directions, do: {{x, y}, dir} + + Enum.count(pos_and_dirs, fn {pos, dir} -> + spells_xmas?(grid, pos, dir) + end) + end + + def p2(input) do + grid = to_grid(input) + {xl..xh, yl..yh} = bounds(grid) + + xs = (xl + 1)..(xh - 1) + ys = (yl + 1)..(yh - 1) + + positions = for x <- xs, y <- ys, do: {x, y} + + Enum.count(positions, &x_mas?(grid, &1)) + end + + def spells_xmas?(grid, pos, dir) do + spells?(grid, pos, dir, "XMAS") + end + + def x_mas?(grid, pos) do + ~w[ne se sw nw]a + |> Enum.map(&{&1, move(pos, &1)}) + |> Enum.count(fn {op_dir, pos} -> + dir = + case op_dir do + :ne -> :sw + :nw -> :se + :se -> :nw + :sw -> :ne + end + + spells?(grid, pos, dir, "MAS") + end) == 2 + end + + def spells?(grid, pos, dir, word) do + letters = String.split(word, "", trim: true) + + grid + |> walk(pos, dir) + |> Stream.zip_with(letters, &(&1 == &2)) + |> Enum.all?() + end + + defp to_grid(input) do + grid = + input + |> String.split("\n") + |> Enum.map(fn line -> + line + |> String.split("", trim: true) + |> List.to_tuple() + end) + |> List.to_tuple() + + grid + end + + def bounds(grid) do + ys = 0..(tuple_size(grid) - 1) + xs = 0..(tuple_size(elem(grid, 0)) - 1) + + {xs, ys} + end + + def walk(grid, pos, dir) do + pos + |> indexes(dir) + |> Stream.map(&get(grid, &1)) + end + + def indexes(pos, dir) do + Stream.iterate(pos, &move(&1, dir)) + end + + def move({x, y}, :n), do: {x, y - 1} + def move({x, y}, :e), do: {x + 1, y} + def move({x, y}, :s), do: {x, y + 1} + def move({x, y}, :w), do: {x - 1, y} + def move(pos, :ne), do: pos |> move(:n) |> move(:e) + def move(pos, :se), do: pos |> move(:s) |> move(:e) + def move(pos, :sw), do: pos |> move(:s) |> move(:w) + def move(pos, :nw), do: pos |> move(:n) |> move(:w) + + def get(grid, {x, y}) do + {xs, ys} = bounds(grid) + + if x in xs and y in ys do + elem(elem(grid, y), x) + end + end +end diff --git a/README.md b/README.md index 7e678ac..2289258 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ | [2021] | **43/50** 🌟 | Elixir | | [2022] | **14/50** 🌟 | Elixir, Haskell | | [2023] | **19/50** 🌟 | Elixir, Haskell | -| [2024] | **6/50** 🌟 | Elixir | +| [2024] | **8/50** 🌟 | Elixir | | **Total** | **162** 🌟 | | [2015]: ./2015