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

Day17

day17.livemd

Day17

Setup

Mix.install([
  {:kino, "~> 0.5.0"}
])
sample_text = Kino.Input.textarea("sample")
input_text = Kino.Input.textarea("input")
sample = Kino.Input.read(sample_text)
input = Kino.Input.read(input_text)
defmodule Shared do
  def parse(text) do
    text
    |> String.replace("#", "1")
    |> String.replace(".", "0")
    |> String.split("\n", trim: true)
    |> Enum.map(fn row ->
      row
      |> String.graphemes()
      |> Enum.map(&String.to_integer/1)
    end)
  end
end
defmodule PartA do
  def cube(array_of_array) do
    size = length(array_of_array) - 1

    null_array_of_array =
      for _ <- 0..size do
        for _ <- 0..size do
          0
        end
      end

    [null_array_of_array] ++
      [array_of_array] ++
      for _ <- 0..(size - 2) do
        null_array_of_array
      end
  end

  def grow(matrix) do
    new_size = length(matrix)

    for x <- -1..new_size do
      for y <- -1..new_size do
        for z <- -1..new_size do
          access(matrix, x, y, z)
        end
      end
    end
  end

  def access(matrix, x, y, z) do
    size = length(matrix)
    oob? = x < 0 || x >= size || y < 0 || y >= size || z < 0 || z >= size
    if oob?, do: 0, else: matrix |> Enum.at(x) |> Enum.at(y) |> Enum.at(z)
  end

  def neighbors(matrix, i, j, k) do
    for x <- -1..1, y <- -1..1, z <- -1..1, x != 0 || y != 0 || z != 0 do
      access(matrix, i + x, j + y, k + z)
    end
    |> Enum.sum()
  end

  def cycle(matrix) do
    grown_matrix = grow(matrix)
    size = length(grown_matrix) - 1

    for x <- 0..size do
      for y <- 0..size do
        for z <- 0..size do
          case {access(grown_matrix, x, y, z), neighbors(grown_matrix, x, y, z)} do
            {1, 2} -> 1
            {1, 3} -> 1
            {1, _} -> 0
            {0, 3} -> 1
            {0, _} -> 0
          end
        end
      end
    end
  end
end

part a

input
|> Shared.parse()
|> PartA.cube()
|> PartA.cycle()
|> PartA.cycle()
|> PartA.cycle()
|> PartA.cycle()
|> PartA.cycle()
|> PartA.cycle()
|> Enum.concat()
|> Enum.concat()
|> Enum.sum()

part b

defmodule PartB do
  def hypercube(array_of_array) do
    cube = PartA.cube(array_of_array)
    size = length(cube) - 1

    null_cube =
      for _ <- 0..size do
        for _ <- 0..size do
          for _ <- 0..size do
            0
          end
        end
      end

    [null_cube] ++
      [cube] ++
      for _ <- 0..(size - 2) do
        null_cube
      end
  end

  def access(cube, x, y, z, w) do
    size = length(cube)
    oob? = x < 0 || x >= size || y < 0 || y >= size || z < 0 || z >= size || w < 0 || w >= size

    if oob? do
      0
    else
      cube |> Enum.at(x) |> Enum.at(y) |> Enum.at(z) |> Enum.at(w)
    end
  end

  def grow(cube) do
    new_size = length(cube)

    for x <- -1..new_size do
      for y <- -1..new_size do
        for z <- -1..new_size do
          for w <- -1..new_size do
            access(cube, x, y, z, w)
          end
        end
      end
    end
  end

  def neighbors(cube, i, j, k, l) do
    for x <- -1..1, y <- -1..1, z <- -1..1, w <- -1..1, x != 0 || y != 0 || z != 0 || w != 0 do
      access(cube, i + x, j + y, k + z, l + w)
    end
    |> Enum.sum()
  end

  def cycle(cube) do
    grown_cube = grow(cube)
    size = length(grown_cube) - 1

    for x <- 0..size do
      for y <- 0..size do
        for z <- 0..size do
          for w <- 0..size do
            case {access(grown_cube, x, y, z, w), neighbors(grown_cube, x, y, z, w)} do
              {1, 2} -> 1
              {1, 3} -> 1
              {1, _} -> 0
              {0, 3} -> 1
              {0, _} -> 0
            end
          end
        end
      end
    end
  end
end
input
|> Shared.parse()
|> PartB.hypercube()
|> PartB.cycle()
|> PartB.cycle()
|> PartB.cycle()
|> PartB.cycle()
|> PartB.cycle()
|> PartB.cycle()
|> Enum.concat()
|> Enum.concat()
|> Enum.concat()
|> Enum.sum()