defmodule DayThree do def parse_claim(claim) do pattern = ~r/#(\d+) @ (\d+),(\d+): (\d+)x(\d+)/ [[_ | match]] = Regex.scan(pattern, claim) [id, x, y, xwidth, ywidth] = Enum.map(match, &String.to_integer(&1)) {id, x, y, xwidth, ywidth} end def part_one(input) do claims = String.split(input, "\n") |> Enum.filter(&(&1 != "")) |> Enum.map(&DayThree.parse_claim/1) dupes = new_doubles(claims) area_with = dupes |> Enum.map(fn {_, {_, _, dx, dy}} -> dx * dy end) |> List.foldl(0, &+/2) area_with end def new_doubles(claims) do Enum.map(claims, fn {id1, x1, y1, dx1, dy1} -> Enum.map(claims, fn {id2, x2, y2, dx2, dy2} -> {{:id, id1, id2}, intersect({id1, x1, y1, dx1, dy1}, {id2, x2, y2, dx2, dy2})} end) |> Enum.filter(fn {_, square} -> square != nil end) end) |> List.flatten() |> Enum.filter(fn {_, square} -> square != nil end) end def intersect({id1, x1, y1, dx1, dy1}, {id2, x2, y2, dx2, dy2}) do if id1 == id2 do nil else intersect({x1, y1, dx1, dy1}, {x2, y2, dx2, dy2}, true) end end def intersect({x1, y1, dx1, dy1}, {x2, y2, dx2, dy2}, ignore \\ false) do if {x1, y1, dx1, dy1} == {x2, y2, dx2, dy2} && not ignore do nil else xe1 = x1 + dx1 xe2 = x2 + dx2 ye1 = y1 + dy1 if x2 <= xe1 && y2 <= ye1 && x2 >= x1 && y2 >= y1 do {y2, x2, xe1 - x2, ye1 - y2} else if xe2 >= x1 && y2 <= ye1 && x2 <= x1 && y2 >= y1 do {x1, y2, xe2 - x1, ye1 - y2} else nil end end end end def part_two(input) do claims = String.split(input, "\n") |> Enum.filter(&(&1 != "")) |> Enum.map(&DayThree.parse_claim/1) dupes = new_doubles(claims) |> Enum.dedup() |> Enum.map(fn {{:id, id1, id2}, _} -> [id1, id2] end) |> List.flatten() claim_id = Enum.map(claims, fn {id, _, _, _, _} -> id end) [id] = Enum.filter(claim_id, &(not Enum.member?(dupes, &1))) id end end {:ok, content} = File.read("input3.txt") IO.puts("Part 1 (most likely incorrect): #{DayThree.part_one(content)}") IO.puts("Part 2: #{DayThree.part_two(content)}")