Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Day 22

2023/day22.livemd

Day 22

Mix.install([
  {:kino, "~> 0.11.3"}
])

Section

input = Kino.Input.textarea("Input")
defmodule Sol22 do
  def read_brick(text) do
    # IO.inspect(text)
    # [x1, y1, z1, x2, y2, z2]
    Regex.split(~r/[,~]/, text)
    |> Enum.map(&String.to_integer(&1))
  end

  def cover(a, b, bricks_map) when a == b do
    false
  end

  def cover(a, b, bricks_map) do
    [ax1, ay1, az1, ax2, ay2, az2] = bricks_map[a]
    [bx1, by1, bz1, bx2, by2, bz2] = bricks_map[b]
    ix1 = max(ax1, bx1)
    ix2 = min(ax2, bx2)
    iy1 = max(ay1, by1)
    iy2 = min(ay2, by2)
    az1 > bz2 and ix2 >= ix1 and iy2 >= iy1
  end

  def find_pairs(bricks_map) do
    n = length(Map.keys(bricks_map))

    for b1 <- 1..n, b2 <- 1..n, Sol22.cover(b2, b1, bricks_map) do
      {b1, b2}
    end
  end

  def read(text) do
    String.split(text, "\n")
    |> Enum.map(&amp;read_brick(&amp;1))
  end

  def build_graph(bricks, pairs) do
    g = :digraph.new()

    Enum.with_index(bricks, fn brick, idx ->
      :digraph.add_vertex(g, idx + 1, brick)
    end)

    for {src, dest} <- pairs do
      :digraph.add_edge(g, src, dest)
    end

    g
  end

  def fall([], _, bricks_map) do
    bricks_map
  end

  def fall([node | tail], g, bricks_map) do
    lowest_z =
      (([0] ++
          for parent <- :digraph.in_neighbours(g, node) do
            [x1, y1, z1, x2, y2, z2] = bricks_map[parent]
            z2
          end)
       |> Enum.max()) + 1

    IO.inspect({"node", node, "lowest_z", lowest_z, :digraph.in_neighbours(g, node)})
    [x1, y1, z1, x2, y2, z2] = bricks_map[node]
    z2 = z2 - z1 + lowest_z
    z1 = lowest_z
    newmap = Map.put(bricks_map, node, [x1, y1, z1, x2, y2, z2])
    IO.inspect({node, [x1, y1, z1, x2, y2, z2]})
    fall(tail, g, newmap)
  end

  def remove_notouch_pairs(g, bricks_map) do
    edges = :digraph.edges(g)

    for edge <- edges do
      {_, src, dest, _} = :digraph.edge(g, edge)
      [ax1, ay1, az1, ax2, ay2, az2] = bricks_map[src]
      [bx1, by1, bz1, bx2, by2, bz2] = bricks_map[dest]

      if az2 + 1 != bz1 do
        IO.inspect({"remove edge", src, dest, "az2", az2, "bz1", bz1})
        :digraph.del_edge(g, edge)
      end
    end

    edges = :digraph.edges(g)

    for edge <- edges do
      {_, src, dest, _} = :digraph.edge(g, edge)
      IO.inspect({src, dest})
    end
  end

  def find_safe_bricks([], _, counter), do: counter

  def find_safe_bricks([node | tail], g, counter) do
  end
end

input_data = Kino.Input.read(input)
bricks = Sol22.read(input_data)
bricks_map = Enum.zip(1..length(bricks), bricks) |> Enum.into(Map.new())

pairs = Sol22.find_pairs(bricks_map)
g = Sol22.build_graph(bricks, pairs)
toporder = :digraph_utils.topsort(g)
bricks_map = Sol22.fall(toporder, g, bricks_map)
Sol22.remove_notouch_pairs(g, bricks_map)
Sol22.find_safe_bricks(toporder, g, 0)