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

Day 5

day5.livemd

Day 5

Section

defmodule Day5 do
  def parse_input(input) do
    [stacks, instructions] = String.split(input, "\n\n", parts: 2)

    {parse_stacks(stacks), parse_instructions(instructions)}
  end

  defp parse_stacks(stacks) do
    stacks
    |> String.split("\n", trim: true)
    |> Enum.map(fn line ->
      line
      |> String.graphemes()
      |> Enum.chunk_every(4)
      |> Enum.map(fn chunk -> chunk |> Enum.find(&Regex.match?(~r/[A-Z0-9]/, &1)) end)
    end)
    |> Enum.zip_with(& &1)
    |> Enum.map(&(&1 |> Enum.filter(fn x -> x end) |> Enum.drop(-1)))
    |> Enum.with_index()
    |> Map.new(fn {v, k} -> {k, v} end)
  end

  defp parse_instructions(instructions) do
    instructions
    |> String.split("\n", trim: true)
    |> Enum.map(fn instruction ->
      [_move, count, _from, from, _to, to] = String.split(instruction, " ", trim: true)
      {String.to_integer(count), String.to_integer(from) - 1, String.to_integer(to) - 1}
    end)
  end

  def part_1(input) do
    {stacks, instructions} = parse_input(input)

    moved_stacks =
      Enum.reduce(instructions, stacks, fn {count, from, to}, stacks ->
        from_data = stacks[from]
        to_data = stacks[to]
        {moved, from_data} = Enum.split(from_data, count)

        stacks
        |> Map.put(from, from_data)
        |> Map.put(to, Enum.reverse(moved) ++ to_data)
      end)

    moved_stacks
    |> Enum.map(fn {_, v} -> hd(v) || "" end)
    |> Enum.join()
  end

  def part_2(input) do
    {stacks, instructions} = parse_input(input)

    moved_stacks =
      Enum.reduce(instructions, stacks, fn {count, from, to}, stacks ->
        from_data = stacks[from]
        to_data = stacks[to]
        {moved, from_data} = Enum.split(from_data, count)

        stacks
        |> Map.put(from, from_data)
        |> Map.put(to, moved ++ to_data)
      end)

    moved_stacks
    |> Enum.map(fn {_, v} -> hd(v) || "" end)
    |> Enum.join()
  end
end
test_input = """
    [D]    
[N] [C]    
[Z] [M] [P]
 1   2   3 

move 1 from 2 to 1
move 3 from 1 to 3
move 2 from 2 to 1
move 1 from 1 to 2
"""
Day5.part_1(test_input)
Day5.part_1(File.read!("day5_input.txt"))
Day5.part_2(File.read!("day5_input.txt"))