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!