import AOC aoc 2021, 5 do import NimbleParsec defparsec( :vent_readout_parsec, integer(min: 1) |> ignore(string(",")) |> integer(min: 1) |> ignore(string(" -> ")) |> integer(min: 1) |> ignore(string(",")) |> integer(min: 1) ) def parse_vent_readout(line) do {:ok, [x1, y1, x2, y2], _, _, _, _} = line |> vent_readout_parsec() {{x1, y1}, {x2, y2}} end def input_stream(), do: super() |> Stream.map(&parse_vent_readout/1) def p1 do input_stream() |> Enum.reduce(Map.new(), &record_line_on_map(&1, &2, false)) |> Map.values() |> Enum.count(&(&1 > 1)) end def p2 do input_stream() |> Enum.reduce(Map.new(), &record_line_on_map(&1, &2, true)) |> Map.values() |> Enum.count(&(&1 > 1)) end def record_line_on_map(line, map, include_diagonals), do: map |> record_points_on_map(points_on_line(line, include_diagonals)) def record_points_on_map(map, points) do for point <- points, reduce: map do map -> Map.update(map, point, 1, &(&1 + 1)) end end # vertical lines def points_on_line({{x, y1}, {x, y2}}, _) do for y <- y1..y2, do: {x, y} end # horizontal lines def points_on_line({{x1, y}, {x2, y}}, _) do for x <- x1..x2, do: {x, y} end # diagonal lines def points_on_line({{x1, y1}, {x2, y2}}, true) do Enum.zip(x1..x2, y1..y2) end def points_on_line(_, false), do: [] end