Skip to content

Commit

Permalink
add 2024
Browse files Browse the repository at this point in the history
  • Loading branch information
kraii committed Dec 28, 2024
1 parent d7423a8 commit 19fd899
Show file tree
Hide file tree
Showing 27 changed files with 2,541 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@ erl_crash.dump
*.beam
/config/*.secret.exs
.elixir_ls/
day*.txt
input/

42 changes: 42 additions & 0 deletions 2024/day1.exs
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.()))
69 changes: 69 additions & 0 deletions 2024/day10.exs
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()
54 changes: 54 additions & 0 deletions 2024/day11.exs
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()
110 changes: 110 additions & 0 deletions 2024/day12.exs
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()
50 changes: 50 additions & 0 deletions 2024/day13.exs
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()
Loading

0 comments on commit 19fd899

Please sign in to comment.