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

Advent 2022 - Day 5

day5.livemd

Advent 2022 - Day 5

Mix.install([
  {:kino, github: "livebook-dev/kino"}
])
:ok

Setup

input = Kino.Input.textarea("Please paste your input file:")
[initial_state_string, instructions_string] =
  input
  |> Kino.Input.read()
  |> String.split("\n\n", trim: true)
["    [D]    \n[N] [C]    \n[Z] [M] [P]\n 1   2   3 ",
 "move 1 from 2 to 1\nmove 3 from 1 to 3\nmove 2 from 2 to 1\nmove 1 from 1 to 2"]

Parsing Initial State

rows =
  initial_state_string
  |> String.split("\n")
  |> Enum.reverse()
  |> tl()
  |> Enum.reverse()
["    [D]    ", "[N] [C]    ", "[Z] [M] [P]"]
rows =
  rows
  |> Enum.map(fn line ->
    line
    |> String.graphemes()
    |> tl
    |> Enum.take_every(4)
  end)
[[" ", "D", " "], ["N", "C", " "], ["Z", "M", "P"]]
initial_state =
  rows
  |> Enum.reduce(List.duplicate([], length(rows) + 1), fn row, acc ->
    Enum.zip(row, acc)
    |> Enum.map(fn {row, acc} -> [row | acc] end)
    |> Enum.map(&Enum.filter(&1, fn item -> item != " " end))
  end)
  |> Enum.map(&Enum.reverse(&1))
[["N", "Z"], ["D", "C", "M"], ["P"]]

Parsing Instructions

instructions =
  instructions_string
  |> String.split("\n")
  |> Enum.map(fn instruction ->
    instruction
    |> String.split(" ")
    |> tl
    |> Enum.take_every(2)
    |> Enum.map(&String.to_integer(&1))
  end)
[[1, 2, 1], [3, 1, 3], [2, 2, 1], [1, 1, 2]]

Utils

defmodule CargoCrane do
  def activate(model, instructions, initial_state) do
    Enum.reduce(instructions, initial_state, fn [move, from, to], state ->
      to_move =
        state
        |> Enum.at(from - 1)
        |> Enum.take(move)

      state
      |> List.update_at(to - 1, fn stack ->
        case model do
          :CrateMover9000 -> (to_move |> Enum.reverse()) ++ stack
          :CrateMover9001 -> to_move ++ stack
          _ -> raise "I don't know that model of crane!"
        end
      end)
      |> List.update_at(from - 1, fn stack ->
        stack |> Enum.drop(move)
      end)
    end)
  end

  def inspect_tops(state) do
    state |> Enum.map(&hd(&1)) |> Enum.join()
  end
end
{:module, CargoCrane, <<70, 79, 82, 49, 0, 0, 12, ...>>, {:inspect_tops, 1}}

Part 1

CargoCrane.activate(:CrateMover9000, instructions, initial_state)
|> CargoCrane.inspect_tops()
"CMZ"

Part 2

CargoCrane.activate(:CrateMover9001, instructions, initial_state)
|> CargoCrane.inspect_tops()
"MCD"