123 lines
2.7 KiB
Markdown
123 lines
2.7 KiB
Markdown
# 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
|
|
|
|
```
|