-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
27 changed files
with
2,541 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,3 +8,6 @@ erl_crash.dump | |
*.beam | ||
/config/*.secret.exs | ||
.elixir_ls/ | ||
day*.txt | ||
input/ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
getLeftAndRightLists = fn -> | ||
stream = | ||
File.stream!("test/day1.txt") | ||
|> Stream.map(&String.trim/1) | ||
|> Stream.map(fn line -> | ||
[l, r] = String.split(line) | ||
{String.to_integer(l), String.to_integer(r)} | ||
end) | ||
|> Enum.to_list() | ||
|
||
Enum.unzip(stream) | ||
end | ||
|
||
part1 = fn -> | ||
{ls, rs} = getLeftAndRightLists.() | ||
sortedLs = Enum.sort(ls) | ||
sortedRs = Enum.sort(rs) | ||
|
||
result = | ||
Enum.zip(sortedLs, sortedRs) | ||
|> Enum.map(fn {l, r} -> abs(l - r) end) | ||
|> Enum.sum() | ||
|
||
result | ||
end | ||
|
||
part2 = fn -> | ||
{ls, rs} = getLeftAndRightLists.() | ||
|
||
Enum.reduce( | ||
ls, | ||
0, | ||
fn l, acc -> | ||
c = l * Enum.count(rs, fn r -> r == l end) | ||
acc + c | ||
end | ||
) | ||
end | ||
|
||
IO.puts("part 1 - " <> Integer.to_string(part1.())) | ||
|
||
IO.puts("part 2 - " <> Integer.to_string(part2.())) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
Code.require_file("./grid.ex") | ||
|
||
defmodule Day10 do | ||
defp file(), do: "test/day10.txt" | ||
|
||
def part1() do | ||
grid = Grid.parse(file(), &String.to_integer/1) | ||
|
||
for start <- find_start_points(grid) do | ||
find_trails(grid, start, [], MapSet.new()) | ||
|> List.flatten() | ||
|> Enum.uniq() | ||
|> Enum.count() | ||
end | ||
|> Enum.sum() | ||
end | ||
|
||
def part2() do | ||
grid = Grid.parse(file(), &String.to_integer/1) | ||
|
||
for start <- find_start_points(grid) do | ||
find_trails(grid, start, [], MapSet.new()) | ||
|> List.flatten() | ||
|> Enum.count() | ||
end | ||
|> Enum.sum() | ||
end | ||
|
||
defp find_trails(grid, current, acc, visited) do | ||
current_tile = Grid.at(grid, current) | ||
|
||
if current_tile == 9 do | ||
[current | acc] | ||
else | ||
new_visited = MapSet.put(visited, current) | ||
|
||
for move <- find_moves(grid, current, new_visited) do | ||
find_trails(grid, move, acc, new_visited) |> List.flatten() | ||
end ++ acc | ||
end | ||
end | ||
|
||
defp find_moves(grid, current, visited) do | ||
for move <- [Grid.up(), Grid.down(), Grid.left(), Grid.right()] do | ||
new_pos = Grid.add(current, move) | ||
|
||
if !MapSet.member?(visited, new_pos) && Grid.contains?(grid, new_pos) && | ||
Grid.at(grid, new_pos) == Grid.at(grid, current) + 1 do | ||
new_pos | ||
end | ||
end | ||
|> Enum.filter(&Function.identity/1) | ||
end | ||
|
||
defp find_start_points(grid) do | ||
for {row, y} <- Tuple.to_list(grid) |> Enum.with_index(), | ||
{elem, x} <- Tuple.to_list(row) |> Enum.with_index() do | ||
if elem == 0 do | ||
{x, y} | ||
end | ||
end | ||
|> Enum.filter(&Function.identity/1) | ||
end | ||
end | ||
|
||
IO.puts("part 1") | ||
Day10.part1() |> IO.inspect() | ||
IO.puts("part 2") | ||
Day10.part2() |> IO.inspect() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
defmodule Day11 do | ||
defp parse() do | ||
File.read!("test/day11.txt") | ||
|> String.trim() | ||
|> String.split() | ||
|> Enum.map(&String.to_integer/1) | ||
end | ||
|
||
def solve(blinks) do | ||
terms = parse() | ||
|
||
start = | ||
for term <- terms, into: %{} do | ||
{term, 1} | ||
end | ||
|
||
stone_counts = | ||
for _i <- 0..(blinks - 1), reduce: start do | ||
acc -> | ||
blink(acc) | ||
end | ||
|
||
Map.values(stone_counts) |> Enum.sum() | ||
end | ||
|
||
defp blink(stones) do | ||
for {stone, count} <- Map.to_list(stones), reduce: %{} do | ||
acc -> | ||
cond do | ||
stone == 0 -> | ||
Map.update(acc, 1, count, &(&1 + count)) | ||
|
||
rem(count_digits(stone), 2) == 0 -> | ||
digits = Integer.digits(stone) | ||
|
||
{first_digits, second_digits} = | ||
Enum.split(digits, Integer.floor_div(Enum.count(digits), 2)) | ||
|
||
Map.update(acc, Integer.undigits(first_digits), count, &(&1 + count)) | ||
|> Map.update(Integer.undigits(second_digits), count, &(&1 + count)) | ||
|
||
true -> | ||
Map.update(acc, stone * 2024, count, &(&1 + count)) | ||
end | ||
end | ||
end | ||
|
||
defp count_digits(i), do: Integer.digits(i) |> Enum.count() | ||
end | ||
|
||
IO.puts("part 1") | ||
Day11.solve(25) |> IO.inspect() | ||
IO.puts("part 2") | ||
Day11.solve(75) |> IO.inspect() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
Code.require_file("./grid.ex") | ||
|
||
defmodule Day12 do | ||
defp file(), do: "test/day12.txt" | ||
|
||
def part1() do | ||
grid = Grid.parse(file()) | ||
|
||
regions(Grid.as_map(grid), []) | ||
|> Enum.map(fn region -> | ||
region_set = MapSet.new(region) | ||
MapSet.size(region_set) * perimiter(region) | ||
end) | ||
|> Enum.sum() | ||
end | ||
|
||
def part2() do | ||
grid = Grid.parse(file()) | ||
|
||
regions(Grid.as_map(grid), []) | ||
|> Enum.map(fn region -> | ||
region_set = MapSet.new(region) | ||
MapSet.size(region_set) * sides(region) | ||
end) | ||
|> Enum.sum() | ||
end | ||
|
||
defp regions(tiles, acc) when map_size(tiles) == 0, do: acc | ||
|
||
defp regions(tiles, acc) do | ||
{pos, plant} = Enum.at(tiles, 0) | ||
{rest_tiles, region} = fill_region(tiles, plant, pos, []) | ||
regions(rest_tiles, [region | acc]) | ||
end | ||
|
||
defp fill_region(tiles, plant, pos, acc) do | ||
if tiles[pos] == plant do | ||
acc = [pos | acc] | ||
tiles = Map.delete(tiles, pos) | ||
|
||
for neighb <- Grid.neighbours(pos), reduce: {tiles, acc} do | ||
{tiles, acc} -> fill_region(tiles, plant, neighb, acc) | ||
end | ||
else | ||
{tiles, acc} | ||
end | ||
end | ||
|
||
defp perimiter(region) do | ||
border_tiles(region) | ||
|> Enum.map(fn tile -> | ||
Grid.neighbours(tile) | ||
|> Enum.count(&(&1 not in region)) | ||
end) | ||
|> Enum.sum() | ||
end | ||
|
||
def border_tiles(region) do | ||
Enum.filter(region, fn tile -> | ||
Grid.neighbours(tile) | ||
|> Enum.any?(&(&1 not in region)) | ||
end) | ||
end | ||
|
||
def sides(region) do | ||
borders = | ||
border_tiles(region) | ||
|> Enum.flat_map(fn tile -> | ||
acc = (Grid.up(tile) in region && []) || [{tile, :up}] | ||
acc = (Grid.down(tile) in region && acc) || [{tile, :down} | acc] | ||
acc = (Grid.left(tile) in region && acc) || [{tile, :left} | acc] | ||
(Grid.right(tile) in region && acc) || [{tile, :right} | acc] | ||
end) | ||
|> MapSet.new() | ||
|
||
count_sides(borders, 0) | ||
end | ||
|
||
defp remove_border(border_tiles, {tile, dir} = entry) when dir in [:up, :down] do | ||
if entry in border_tiles do | ||
border_tiles = MapSet.delete(border_tiles, entry) | ||
remove_border(border_tiles, {Grid.right(tile), dir}) | ||
else | ||
border_tiles | ||
end | ||
end | ||
|
||
defp remove_border(border_tiles, {tile, dir} = entry) when dir in [:left, :right] do | ||
if entry in border_tiles do | ||
border_tiles = MapSet.delete(border_tiles, entry) | ||
remove_border(border_tiles, {Grid.down(tile), dir}) | ||
else | ||
border_tiles | ||
end | ||
end | ||
|
||
defp count_sides(borders, acc) do | ||
if MapSet.size(borders) == 0 do | ||
acc | ||
else | ||
borders = remove_border(borders, Enum.min(borders)) | ||
count_sides(borders, acc + 1) | ||
end | ||
end | ||
end | ||
|
||
IO.puts("part 1") | ||
Day12.part1() |> IO.inspect() | ||
IO.puts("part 2") | ||
Day12.part2() |> IO.inspect() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
defmodule Day13 do | ||
defp lines() do | ||
File.stream!("test/day13.txt") | ||
|> Enum.map(&String.trim/1) | ||
|> Enum.reject(&(&1 == "")) | ||
end | ||
|
||
defp parse([], _, acc), do: acc | ||
|
||
defp parse(lines, prize_ext, acc) do | ||
{[a_line, b_line, prize_line], rest} = Enum.split(lines, 3) | ||
|
||
{px, py} = get_x_y(prize_line) | ||
crane = %{a: get_x_y(a_line), b: get_x_y(b_line), prize: {px + prize_ext, py + prize_ext}} | ||
parse(rest, prize_ext, [crane | acc]) | ||
end | ||
|
||
defp get_x_y(line) do | ||
[_, x, y] = Regex.run(~r/X.([0-9]+), Y.([0-9]+)/, line) | ||
{String.to_integer(x), String.to_integer(y)} | ||
end | ||
|
||
def solve(prize_ext) do | ||
cranes = parse(lines(), prize_ext, []) | ||
|
||
for crane <- cranes, reduce: 0 do | ||
acc -> | ||
acc + cost(crane) | ||
end | ||
end | ||
|
||
defp cost(%{:a => {ax, ay}, :b => {bx, by}, :prize => {px, py}}) do | ||
|
||
n = (px * by - py * bx) / (ax * by - bx * ay) | ||
m = (px - ax * n) / bx | ||
|
||
if whole(n) && whole(m) do | ||
trunc(n * 3 + m) | ||
else | ||
0 | ||
end | ||
end | ||
|
||
defp whole(n), do: trunc(n) == n | ||
end | ||
|
||
IO.puts("part 1") | ||
Day13.solve(0) |> IO.inspect() | ||
IO.puts("part 2") | ||
Day13.solve(10000000000000) |> IO.inspect() |
Oops, something went wrong.