diff --git a/elixir/livebook/2024/day14.livemd b/elixir/livebook/2024/day14.livemd new file mode 100644 index 0000000..76b9cb8 --- /dev/null +++ b/elixir/livebook/2024/day14.livemd @@ -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 + +```