[Advent Of Code 2022] Day 10: Cathode-Ray Tube [SPOILERS]

Solved this in a fairly straightforward way. Always fun to write things to the console as part of a solution.

Ruby Solution
registers = File.readlines('inputs/10.txt', chomp: true).inject([1]) do |history, instruction|
  case instruction.split(' ')
  in ['noop'] then history.push(history.last)
  in ['addx', value] then history.push(history.last).push(history.last + value.to_i)
  end
end

a = [20, 60, 100, 140, 180, 220].sum {|cycle| cycle * registers[cycle - 1] }
b = registers[0..-2].each_slice(40).map do|row|
  row.each_with_index.map {|register, col| (register - col).abs <= 1 ? "#" : '.' }.join + "\n"
end.join

require 'minitest/autorun'

expected_b = <<~B
####.####.###..####.#..#..##..#..#.###..
...#.#....#..#.#....#..#.#..#.#..#.#..#.
..#..###..###..###..####.#....#..#.#..#.
.#...#....#..#.#....#..#.#.##.#..#.###..
#....#....#..#.#....#..#.#..#.#..#.#....
####.#....###..#....#..#..###..##..#....
B

describe 'day 10' do
  it 'part a' do assert_equal 15_680, a end
  it 'part b' do assert_equal expected_b, b end
end

Flashbacks to 2019. I hope we won’t do something like Intcode this year.

Python Solution
def read_file(file: TextIO) -> tuple[str, tuple[int, ...]]:
    """Read lines from the `file`."""
    lines = (line.split() for line in file)
    return [(cmd, tuple(int(arg) for arg in args)) for cmd, *args in lines]


def run_program(program: tuple[str, tuple[int, ...]]) -> list[int]:
    """Determine the value of the register 'X' for each cycle."""
    result = []
    reg_x = 1
    for cmd, args in program:
        if cmd == 'noop':
            result.append(reg_x)
        elif cmd == 'addx':
            result.append(reg_x)
            result.append(reg_x)
            reg_x += args[0]
    return result


def part1(file: TextIO) -> int:
    """Solve the first part of the puzzle."""
    program = read_file(file)
    reg_x_values = run_program(program)
    signal_strengths = (reg_x * i for i, reg_x in enumerate(reg_x_values, 1))
    return sum(itertools.islice(signal_strengths, 19, None, 40))


def part2(file: TextIO) -> str:
    """Solve the second part of the puzzle."""
    program = read_file(file)
    crt = [['.'] * 40 for _ in range(6)]
    signals = run_program(program)
    for i, reg_x in enumerate(signals):
        # pylint: disable-next=invalid-name
        y, x = divmod(i % (6 * 40), 40)
        if reg_x - 1 <= x <= reg_x + 1:
            crt[y][x] = '#'
        else:
            crt[y][x] = '.'
    return '\n'.join(''.join(line) for line in crt)

I got tripped up multiple times trying to solve this, by performing the operations in the wrong order (updating the register too early in the cycle).

I finally added an “OCR” to my library. It converts the pixels (list[list[bool]]) to a series of bits which is then just an int. Combine that with a map[int, char] and I can run this type of exercise through the “OCR” logic and get a string!

Code: FinalJust Make It Work

Python Solution
    def run_program(self, lines: InputType) -> list[int]:
        regx = 1
        regx_values = []
        size = {"addx": 2, "noop": 1}
        for parts in lines:
            for _ in range(size[str(parts[0])]):
                regx_values.append(regx)
            if parts[0] == "addx":
                regx += int(parts[1])
        return regx_values

    def part1(self, parsed_input: InputType) -> int:
        regx_values = self.run_program(parsed_input)
        out = 0
        for cycle in range(20, 240, 40):
            out += regx_values[cycle - 1] * cycle
        return out

    def part2(self, parsed_input: InputType) -> str:
        regx_values = self.run_program(parsed_input)

        pixels = []
        for cycle, regx in enumerate(regx_values):
            horizontal_position = cycle % 40
            pixels.append(abs(horizontal_position - regx) <= 1)

        rows = [pixels[i*40:(i+1)*40] for i in range(6)]
        return aoc.OCR(rows).as_string()