Skip to content

Latest commit

 

History

History
88 lines (72 loc) · 1.83 KB

day10.livemd

File metadata and controls

88 lines (72 loc) · 1.83 KB

Cathode-Ray Tube

Mix.install([
  {:kino, "~> 0.8.0"}
])

Input

input = Kino.Input.textarea("Input:")
input = Kino.Input.read(input) |> String.trim() |> String.split("\n")

Execute

# Used in map_reduce, takes instruction and state, returns
# list (of intermediate states) and new state.
execute = fn
  "noop", {clock, reg} ->
    # noop takes 1 cycle, leaves the register alone.
    {[{clock + 1, reg}], {clock + 1, reg}}

  "addx " <> value, {clock, reg} ->
    value = String.to_integer(value)
    # addx takes 2 cycles without changing the register.
    # register is changed at the _end_ of the 2nd cycle.
    {[{clock + 1, reg}, {clock + 2, reg}], {clock + 2, reg + value}}
end
{states, result} = Enum.map_reduce(input, {0, 1}, execute)
states = List.flatten(states)

Part 1

part1 =
  states
  |> Enum.drop(19)
  |> Enum.take_every(40)
  |> Enum.take(6)
  |> Enum.map(fn {clock, reg} -> clock * reg end)
  |> Enum.sum()

Part 2

# For each clock tick, if the register is at pixel - 1, pixel or pixel +1, then draw the pixel.

pixels =
  Enum.reduce(states, "", fn
    {clock, reg}, acc when reg >= rem(clock, 40) - 2 and reg <= rem(clock, 40) ->
      # IO.puts("During cycle #{clock}, sprite is at #{reg}, draw pixel")
      acc <> "#"

    {clock, reg}, acc ->
      # IO.puts("During cycle #{clock}, sprite is at #{reg}")
      acc <> "."
  end)
display = fn pixels ->
  String.slice(pixels, 0..39) <>
    "\n" <>
    String.slice(pixels, 40..79) <>
    "\n" <>
    String.slice(pixels, 80..119) <>
    "\n" <>
    String.slice(pixels, 120..159) <>
    "\n" <>
    String.slice(pixels, 160..199) <>
    "\n" <>
    String.slice(pixels, 200..239) <> "\n"
end

screen = display.(pixels)
Kino.Markdown.new("```\n" <> screen <> "\n```\n")