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

Day 10

day10.livemd

Day 10

Setup

https://adventofcode.com/2022/day/10

test_input_str = """
  addx 15
  addx -11
  addx 6
  addx -3
  addx 5
  addx -1
  addx -8
  addx 13
  addx 4
  noop
  addx -1
  addx 5
  addx -1
  addx 5
  addx -1
  addx 5
  addx -1
  addx 5
  addx -1
  addx -35
  addx 1
  addx 24
  addx -19
  addx 1
  addx 16
  addx -11
  noop
  noop
  addx 21
  addx -15
  noop
  noop
  addx -3
  addx 9
  addx 1
  addx -3
  addx 8
  addx 1
  addx 5
  noop
  noop
  noop
  noop
  noop
  addx -36
  noop
  addx 1
  addx 7
  noop
  noop
  noop
  addx 2
  addx 6
  noop
  noop
  noop
  noop
  noop
  addx 1
  noop
  noop
  addx 7
  addx 1
  noop
  addx -13
  addx 13
  addx 7
  noop
  addx 1
  addx -33
  noop
  noop
  noop
  addx 2
  noop
  noop
  noop
  addx 8
  noop
  addx -1
  addx 2
  addx 1
  noop
  addx 17
  addx -9
  addx 1
  addx 1
  addx -3
  addx 11
  noop
  noop
  addx 1
  noop
  addx 1
  noop
  noop
  addx -13
  addx -19
  addx 1
  addx 3
  addx 26
  addx -30
  addx 12
  addx -1
  addx 3
  addx 1
  noop
  noop
  noop
  addx -9
  addx 18
  addx 1
  addx 2
  noop
  noop
  addx 9
  noop
  noop
  noop
  addx -1
  addx 2
  addx -37
  addx 1
  addx 3
  noop
  addx 15
  addx -21
  addx 22
  addx -6
  addx 1
  noop
  addx 2
  addx 1
  noop
  addx -10
  noop
  noop
  addx 20
  addx 1
  addx 2
  addx 2
  addx -6
  addx -11
  noop
  noop
  noop
"""
defmodule Load do
  def input do
    File.read!(Path.join(Path.absname(__DIR__), "input/10.txt"))
  end
end
defmodule Parse do
  def input(inputString) do
    inputString
    |> String.split("\n", trim: true)
    |> Enum.map(fn line ->
      line
      |> String.split(" ", trim: true)
      |> List.to_tuple()
    end)
    |> Enum.map(fn
      {"noop"} -> {"noop"}
      {"addx", num_str} -> {"addx", elem(Integer.parse(num_str), 0)}
    end)
  end
end

test_input =
  test_input_str
  |> Parse.input()
real_input =
  Load.input()
  |> Parse.input()

Part 1

defmodule Part1 do
  def is_interesting_cycle(cycle) do
    rem(cycle - 20, 40) == 0
  end

  def solve(commands) do
    results =
      commands
      |> Enum.reduce(%{elapsed_cycles: 0, x: 1, signal_strengths: []}, fn command, acc ->
        new_cycle_count =
          case command do
            {"noop"} -> acc.elapsed_cycles + 1
            {"addx", _} -> acc.elapsed_cycles + 2
          end

        new_x_val =
          case command do
            {"addx", add_val} -> acc.x + add_val
            {"noop"} -> acc.x
          end

        interesting_cycle =
          (acc.elapsed_cycles + 1)..new_cycle_count
          |> Enum.filter(&is_interesting_cycle(&1))
          |> List.first()

        new_signal_strengths =
          case interesting_cycle do
            nil ->
              acc.signal_strengths

            cycle ->
              acc.signal_strengths ++ [{cycle, acc.x * cycle}]
          end

        %{elapsed_cycles: new_cycle_count, x: new_x_val, signal_strengths: new_signal_strengths}
      end)

    results.signal_strengths
    |> Enum.map(&elem(&1, 1))
    |> Enum.sum()
  end
end

Part1.solve(test_input)
Part1.solve(real_input)

Part 2

defmodule Part2 do
  def solve(commands) do
    result =
      commands
      |> Enum.map(fn
        # Insert dummy "addx 0"s to make commands and cpu cycles 1:1
        {"noop"} -> [{"noop"}]
        {"addx", x} -> [{"noop"}, {"addx", x}]
      end)
      |> List.flatten()
      |> Enum.reduce(%{elapsed_cycles: 0, x: 1, output_str: ""}, fn command, acc ->
        sprite_range = (acc.x - 1)..(acc.x + 1)
        current_cycle = acc.elapsed_cycles

        new_char =
          case Enum.member?(sprite_range, rem(current_cycle, 40)) do
            true -> "#"
            false -> "."
          end

        new_x_val =
          case command do
            {"addx", add_val} -> acc.x + add_val
            {"noop"} -> acc.x
          end

        %{
          elapsed_cycles: acc.elapsed_cycles + 1,
          x: new_x_val,
          output_str: acc.output_str <> new_char
        }
      end)

    result.output_str
    |> String.to_charlist()
    |> Enum.chunk_every(40)
    |> Enum.join("\n")
    |> IO.puts()
  end
end

Part2.solve(test_input)
Part2.solve(real_input)