Powered by AppSignal & Oban Pro

Aoc 2021 day 19

2021/elixir/day-19.livemd

Aoc 2021 day 19

Section

Mix.install([{:kino, "~> 0.5.0"}])
input = Kino.Input.textarea("input")
defmodule Parser do
  def parse(input) do
    input
    |> Kino.Input.read()
    |> String.split(~r/--- scanner \d+ ---\n/, trim: true)
    |> Enum.map(fn line ->
      String.split(line, [",", "\n"], trim: true)
      |> Enum.map(&String.to_integer/1)
      |> Enum.chunk_every(3)
    end)
  end
end

defmodule Part1 do
  def relative_coord(sc1, sc2) do
    for [x0, y0, z0] <- sc1,
        [x, y, z] <- sc2,
        {x1, y1, z1} <- [{x, y, z}, {x, z, y}, {y, x, z}, {y, z, x}, {z, y, x}, {z, x, y}] do
      [
        {x0 + x1, y0 + y1, z0 + z1, {1, 1, 1}},
        {x0 - x1, y0 + y1, z0 + z1},
        {x0 + x1, y0 - y1, z0 + z1},
        {x0 + x1, y0 + y1, z0 - z1},
        {x0 - x1, y0 - y1, z0 + z1},
        {x0 + x1, y0 - y1, z0 - z1},
        {x0 - x1, y0 + y1, z0 - z1},
        {x0 - x1, y0 - y1, z0 - z1}
      ]
    end
    |> List.flatten()
    |> Enum.frequencies()
    |> Enum.filter(fn {_, cnt} -> cnt >= 12 end)
    |> case do
      [] ->
        nil

      [{coord, _}] ->
        coord
    end
  end

  def convert_coord(coords, {x, y, z}) do
    coords
    |> Enum.map(fn [ax, ay, az] ->
      [ax - x, ay - y, az - z]
    end)
  end

  def rotation({x, y, z}) do
    1..24
    |> Enum.scan({x, y, z}, fn
      i, pos when rem(i, 4) == 0 ->
        `roll(pos)

      i, pos ->
        turn(pos, div(i, 4))
    end)
  end

  defp roll({x, y, z}), do: {-z, y, x}
  defp turn({x, y, z}, i) when rem(i, 2) == 0, do: {y, -x, z}
  defp turn({x, y, z}, _i), do: {-y, x, z}
end
Part1.rotation({4, 5, 6})
|> Enum.frequencies()
[sc0, sc1, sc2, sc3, sc4] = scanners = Parser.parse(input)
coord = Part1.relative_coord(sc0, sc1)
# Part1.convert_coord(sc1, coord)
for left <- 0..(length(scanners) - 1),
    right <- 1..length(scanners),
    sc0 = Enum.at(scanners, left),
    sc1 = Enum.at(scanners, right),
    [x0, y0, z0] <- sc0,
    [x, y, z] <- sc1,
    {x1, y1, z1} <- [{x, y, z}, {x, z, y}, {y, x, z}, {y, z, x}, {z, y, x}, {z, x, y}],
    left < right do
  [
    {x0 + x1, y0 + y1, z0 + z1},
    {x0 - x1, y0 + y1, z0 + z1},
    {x0 + x1, y0 - y1, z0 + z1},
    {x0 + x1, y0 + y1, z0 - z1},
    {x0 - x1, y0 - y1, z0 + z1},
    {x0 + x1, y0 - y1, z0 - z1},
    {x0 - x1, y0 + y1, z0 - z1},
    {x0 - x1, y0 - y1, z0 - z1}
  ]
  |> Enum.zip(Stream.repeatedly(fn -> {left, right} end))
end
|> List.flatten()
|> Enum.frequencies()
|> Enum.filter(fn {_, cnt} -> cnt >= 12 end)
i0 = """
-618,-824,-621
-537,-823,-458
-447,-329,318
404,-588,-901
544,-627,-890
528,-643,409
-661,-816,-575
390,-675,-793
423,-701,434
-345,-311,381
459,-707,401
-485,-357,347
"""

i1 = """
686,422,578
605,423,415
515,917,-361
-336,658,858
-476,619,847
-460,603,-452
729,430,532
-322,571,750
-355,545,-477
413,935,-424
-391,539,-444
553,889,-390
"""

[i0, i1]
|> Enum.map(
  &amp;(String.split(&amp;1, [",", "\n"], trim: true)
    |> Enum.map(fn s -> String.to_integer(s) end)
    |> Enum.chunk_every(3))
)
|> Enum.zip()
|> Enum.map(fn {[x0, y0, z0], [x1, y1, z1]} ->
  {x0 + x1, y0 - y1, z0 + z1}
end)