diff options
author | Alexandre Jesus <adbjesus@gmail.com> | 2024-12-14 21:32:28 +0000 |
---|---|---|
committer | Alexandre Jesus <adbjesus@gmail.com> | 2024-12-14 21:32:28 +0000 |
commit | 2b62af01948904129db4835bf70adf1b8feaa95d (patch) | |
tree | 278883a2294c3de13149431d8e4dcb895730f4f6 | |
parent | c23fda0a9e5cd521ce7ffc1857f184b76ecfc6b3 (diff) | |
download | aoc2024-2b62af01948904129db4835bf70adf1b8feaa95d.tar.gz aoc2024-2b62af01948904129db4835bf70adf1b8feaa95d.zip |
Day 14
-rw-r--r-- | src/day14.exs | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/src/day14.exs b/src/day14.exs new file mode 100644 index 0000000..84353f6 --- /dev/null +++ b/src/day14.exs @@ -0,0 +1,111 @@ +defmodule Day14 do + defmodule Board do + @derive Inspect + defstruct [:w, :h, :robots] + + def from_data(data, w, h) do + robots = data + |> String.split("\n", trim: true) + |> Enum.map(fn line -> + Regex.scan(~r/-?\d+/, line) + |> List.flatten() + |> Enum.map(&String.to_integer/1) + |> List.to_tuple() + end) + + %Board{w: w, h: h, robots: robots} + end + + def move(board, moves) do + board.robots + |> Enum.map(fn {x, y, vx, vy} -> + { + posrem(x+moves*vx, board.w), + posrem(y+moves*vy, board.h) + } + end) + end + + defp posrem(n, m) do + rem(rem(n, m)+m, m) + end + + def print(board, pos) do + pos = MapSet.new(pos) + for i <- 0..board.w-1 do + for j <- 0..board.h-1 do + if MapSet.member?(pos, {j, i}) do + "X" + else + "." + end + end + end + |> Enum.map(&List.to_string/1) + |> Enum.join("\n") + |> IO.puts() + end + end + + def part1(data) do + board = Board.from_data(data, 101, 103) + + Board.move(board, 100) + |> Enum.map(fn {x, y} -> + cond do + x < div(board.w, 2) and y < div(board.h, 2) -> + {1, 0, 0, 0} + x < div(board.w, 2) and y > div(board.h, 2) -> + {0, 1, 0, 0} + x > div(board.w, 2) and y < div(board.h, 2) -> + {0, 0, 1, 0} + x > div(board.w, 2) and y > div(board.h, 2) -> + {0, 0, 0, 1} + true -> + {0, 0, 0, 0} + end + end) + |> Enum.reduce({0, 0, 0, 0}, fn {i1, i2, i3, i4}, {q1, q2, q3, q4} -> + {q1+i1, q2+i2, q3+i3, q4+i4} + end) + |> then(fn {q1, q2, q3, q4} -> q1*q2*q3*q4 end) + end + + def part2(data) do + board = Board.from_data(data, 101, 103) + + Stream.map(0..10000, fn i -> + pos = Board.move(board, i) + + most = pos + |> Enum.group_by(&elem(&1, 0), &(elem(&1, 1))) + |> Enum.map(&Enum.sort(elem(&1, 1))) + |> Enum.map(fn ys -> + Enum.zip(ys, tl(ys)) + |> Enum.map(fn {a, b} -> b-a end) + end) + |> List.flatten() + |> Enum.frequencies() + |> Enum.max_by(&elem(&1, 1)) + + if elem(most, 0) == 1 and elem(most, 1) > 100 do + dbg({i, most}) + Board.print(board, pos) + i + end + end) + |> Stream.filter(& &1 != nil) + |> Enum.take(1) + |> hd() + end +end + +data = IO.read(:stdio, :eof) + +{time1, ans1} = :timer.tc(fn -> Day14.part1(data) end) +IO.puts("Time : #{time1 / 1000000}") +IO.puts("Answer: #{ans1}") + +{time2, ans2} = :timer.tc(fn -> Day14.part2(data) end) +IO.puts("Time : #{time2 / 1000000}") +IO.puts("Answer: #{ans2}") |