day 2024 day 14
This commit is contained in:
parent
7dfc62354d
commit
e4de674377
1 changed files with 123 additions and 0 deletions
123
elixir/livebook/2024/day14.livemd
Normal file
123
elixir/livebook/2024/day14.livemd
Normal file
|
@ -0,0 +1,123 @@
|
|||
# AOC 2024 Day 14
|
||||
|
||||
## Section
|
||||
|
||||
```elixir
|
||||
input = """
|
||||
"""
|
||||
```
|
||||
|
||||
positive `rem` that only returns positive number
|
||||
|
||||
```elixir
|
||||
rrem = fn a, b ->
|
||||
t = rem(a, b)
|
||||
if t < 0 do
|
||||
t + b
|
||||
else
|
||||
t
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
```elixir
|
||||
quadrant = fn {x, y}, {w, h} ->
|
||||
{cx, cy} = {div(w, 2), div(h, 2)}
|
||||
{
|
||||
(if x < cx, do: -1, else: (if cx < x, do: 1, else: nil)),
|
||||
(if y < cy, do: -1, else: (if cy < y, do: 1, else: nil))
|
||||
}
|
||||
end
|
||||
```
|
||||
|
||||
```elixir
|
||||
w = 101
|
||||
h = 103
|
||||
```
|
||||
|
||||
```elixir
|
||||
pos = for line <- input |> String.trim() |> String.split("\n", trim: true),
|
||||
[p, v] = String.split(line, " "),
|
||||
{x,y} = p |> String.split("=") |> Enum.at(1) |> String.split(",") |> Enum.map(&String.to_integer/1) |> List.to_tuple(),
|
||||
{px, py} = v |> String.split("=") |> Enum.at(1) |> String.split(",") |> Enum.map(&String.to_integer/1) |> List.to_tuple(),
|
||||
reduce: %{}
|
||||
do
|
||||
acc ->
|
||||
{fx, fy} = {rrem.(x + 100*px, w), rrem.(y + 100*py, h)}
|
||||
if (fx != div(w, 2) and fy != div(h, 2)) do
|
||||
acc |> Map.update(quadrant.({fx, fy}, {w, h}), 1, &(&1 + 1))
|
||||
else
|
||||
acc
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
```elixir
|
||||
pos |> Map.values() |> Enum.product()
|
||||
```
|
||||
|
||||
```elixir
|
||||
points = for line <- input |> String.trim() |> String.split("\n", trim: true),
|
||||
[p, v] = String.split(line, " "),
|
||||
{x,y} = p |> String.split("=") |> Enum.at(1) |> String.split(",") |> Enum.map(&String.to_integer/1) |> List.to_tuple(),
|
||||
{px, py} = v |> String.split("=") |> Enum.at(1) |> String.split(",") |> Enum.map(&String.to_integer/1) |> List.to_tuple(),
|
||||
reduce: MapSet.new
|
||||
do
|
||||
acc ->
|
||||
MapSet.put(acc, {{x, y}, {px, py}})
|
||||
end
|
||||
```
|
||||
|
||||
```elixir
|
||||
draw = fn points ->
|
||||
for y <- 0..(h-1) do
|
||||
for x <- 0..(w-1) do
|
||||
File.write("buffer.txt", (if MapSet.member?(points, {x, y}), do: "*", else: "."), [:write, :append])
|
||||
if x == (w-1) do
|
||||
File.write("buffer.txt", "\n", [:write, :append])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
```elixir
|
||||
q = Stream.iterate(0, &(&1 + 1))
|
||||
|> Enum.take(10_000)
|
||||
|> Enum.reduce(%{}, fn i, seen ->
|
||||
safety = for {{x, y}, {px, py}} <- points,
|
||||
reduce: %{} do
|
||||
acc ->
|
||||
f = quadrant.({rrem.(x + i*px, w), rrem.(y + i*py, h)}, {w, h})
|
||||
case f do
|
||||
{nil, _ } -> acc
|
||||
{_, nil} -> acc
|
||||
x -> Map.update(acc, x, 1, &(&1 + 1))
|
||||
end
|
||||
end |> Map.values() |> Enum.product()
|
||||
Map.put(seen, i, safety)
|
||||
end
|
||||
)
|
||||
```
|
||||
|
||||
```elixir
|
||||
q |> Enum.min_by(&elem(&1, 1))
|
||||
```
|
||||
|
||||
I solved part two by a mix of searching frames around the min safety factor. The below cell renders the frames in a range near the min.
|
||||
|
||||
```elixir
|
||||
for i <- 6200..6300 do
|
||||
for {{x, y}, {px, py}} <- points,
|
||||
reduce: MapSet.new do
|
||||
acc ->
|
||||
f = {rem(x + i*px, w), rem(y + i*py, h)}
|
||||
MapSet.put(acc, f)
|
||||
end |> draw.()
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
```elixir
|
||||
|
||||
```
|
Loading…
Add table
Reference in a new issue