# 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 ```