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

Day 18

day18.livemd

Day 18

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

Section

input = Kino.Input.textarea("Puzzle input")
cubes =
  input
  |> Kino.Input.read()
  |> String.split("\n", trim: true)
  |> Enum.map(fn line ->
    line
    |> String.split(",", trim: true)
    |> Enum.map(&String.to_integer/1)
    |> Enum.map(&(&1 + 1))
  end)

Part 1

cubes
|> Enum.map(fn [x, y, z] ->
  [
    [-1, 0, 0],
    [1, 0, 0],
    [0, -1, 0],
    [0, 1, 0],
    [0, 0, -1],
    [0, 0, 1]
  ]
  |> Enum.reject(fn [nx, ny, nz] ->
    new_pos = [x + nx, y + ny, z + nz]

    new_pos in cubes
  end)
  |> Enum.count()
end)
|> Enum.sum()

Part 2

defmodule Part2 do
  def get_neighbors([x, y, z]) do
    [
      [-1, 0, 0],
      [1, 0, 0],
      [0, -1, 0],
      [0, 1, 0],
      [0, 0, -1],
      [0, 0, 1]
    ]
    |> Enum.map(fn [nx, ny, nz] -> [x + nx, y + ny, z + nz] end)
  end

  def get_reachable_neighbors(cubes, pos) do
    pos
    |> get_neighbors()
    |> Enum.reject(fn [x, y, z] = n_pos ->
      cond do
        n_pos in cubes -> true
        x < 0 or y < 0 or z < 0 or x > 22 or y > 22 or z > 22 -> true
        true -> false
      end
    end)
  end

  def bfs(_cubes, [], [], explored), do: explored

  def bfs(cubes, [], next, explored) do
    bfs(cubes, next, [], explored)
  end

  def bfs(cubes, [current | queue], next, explored) do
    if current in explored do
      bfs(cubes, queue, next, explored)
    else
      explored = [current | explored]
      next = next ++ get_reachable_neighbors(cubes, current)
      bfs(cubes, queue, next, explored)
    end
  end
end
start = [0, 0, 0]
queue = [start]
explored = [start]

explored = Part2.bfs(cubes, queue, Part2.get_reachable_neighbors(cubes, start), explored)

Enum.reduce(cubes, 0, fn cube, count ->
  cube
  |> Part2.get_neighbors()
  |> Enum.filter(&amp;(&amp;1 in explored))
  |> Enum.count()
  |> Kernel.+(count)
end)