Powered by AppSignal & Oban Pro

Day 10

2022/day_10.livemd

Day 10

Setup

Mix.install([:kino])
input =
  Kino.Input.textarea("Paste input here",
    default: """
    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
    """
  )
instructions =
  Kino.Input.read(input)
  |> String.split("\n", trim: true)
  |> Stream.map(fn
    "addx " <> v -> {:addx, String.to_integer(v)}
    "noop" -> :noop
  end)
  |> Enum.into([])
defmodule ClockCircuit do
  def process_instruction(:noop, {cycle, x}), do: [{cycle + 1, x}]

  def process_instruction({:addx, v}, {cycle, x}) do
    [{cycle + 2, x + v}, {cycle + 1, x}]
  end
end
cycles =
  instructions
  |> Enum.reduce([{1, 1}], fn ins, acc ->
    [current | _] = acc
    new = ClockCircuit.process_instruction(ins, current)
    new ++ acc
  end)

Part 1

cycles
|> Stream.filter(fn {cycle, _} -> cycle == 20 or rem(cycle - 20, 40) == 0 end)
|> Stream.map(fn {cycle, x} -> cycle * x end)
|> Enum.sum()

Part 2

instructions
|> Enum.reduce([{0, 1}], fn ins, acc ->
  [current | _] = acc
  new = ClockCircuit.process_instruction(ins, current)
  new ++ acc
end)
|> Enum.reverse()
|> Stream.map(fn {c, x} ->
  pixel = rem(c, 40)
  sprite_pos = [x - 1, x, x + 1]
  if Enum.member?(sprite_pos, pixel), do: "#", else: " "
end)
|> Stream.chunk_every(40)
|> Stream.map(&Enum.join(&1, ""))
|> Enum.join("\n")
|> then(&"<pre>#{&1}</pre>")
|> Kino.Markdown.new()