We're parsing instructions and plotting in the terminal today!
What is Advent of Code?
In this little series, I want to write about the thought processes I have behind solving the puzzles presented in Advent of Code.
During the Advent of Code small coding puzzles are presented with varying levels of difficulty. They're always Christmas-themed text puzzles where you help elves out of some mess to save the holidays. The puzzles are deliberately ambiguous to not bias puzzlers into a certain solution, they always have an example input in the text to explain some details and an input file for each day that comes in the form of a text file you can download. The solution is a simple number or a string you enter, which is checked by the website automatically. After you finish part 1, part 2 unlocks, which is a variation on part 2. This can be a little twist on part 1 or a large twist that changes the problem formulation into a problem that would take brute force solutions to compute longer than the heat death of the universe would take.
Find my solutions here: github.com/JesperDramsch/advent-of-code
These descriptions won't be a perfect narrative, but rather how I think about these problems and where I see different solutions. I apologise for the possibility of rambling!
The example input
Is this this year's compiler problem? Noice!
noop addx 3 addx -5
Right away I can say that I should use match-case
statements
The implementation
This is another brain-in-a-knot problem.
We have instructions that take different amounts of time to complete. We want to have the values at certain times that may be in between instructions.
So I add an increment inc
in addition to the add
argument.
def process_instruction(instruction, cycles, X): add = 0 match instruction.split(" "): case "noop",: inc = 1 case "addx", add: inc = 2 add = int(add) return inc, add
Important to note that we have X
that starts at 1
too.
I wonder if some sort of queue system will be necessary and I'm terrified of what part 2 might throw at us. 👀
I think I want to go "sparse" with this one. I could set up a queue I fill up, but I can also simply increase the counters with a check, so I don't run into troubles, when the queues suddenly get long.
cycles, X = 0, 1 for line in instructions: inc, add = process_instruction(line, cycles, X) if cycles < check <= cycles + inc: checks[check] = X check += 40 cycles += inc X += add
Fairly simple.
Part Deux
Part 2 needed a bit of refactoring so I can reuse the instruction processing you saw in part 1.
Everything else was just using the inc
and add
arguments in different ways:
inc, add = process_instruction(line, cycles, X) for i in range(inc): if X - 1 <= cycles % 40 <= X + 1: crt.append("#") else: crt.append(".")
Then I simply added a little function to draw the CRT
def plot_crt(crt): return "\n".join("".join(crt[i : i + 40]) for i in range(0, len(crt), 40))
And it was the first solution I couldn't submit automagically, but I love these honestly.
Error Log
Annoyingly repeated a mistake by forgetting to set a variable this time around and hade a small misunderstanding of part 2 which was quickly resolved.
cycle += 1 UnboundLocalError: cannot access local variable 'cycle' where it is not associated with a value
forgot to start cyclescheck = checks.values()[0] TypeError: 'dict_values' object is not subscriptable
thought that would be a list or something.check = checks[20] KeyError: 20
oh my. Good thing I caught that, I set up myrange()
wrong.if cycles < check <= cycles+inc: TypeError: '<' not supported between instances of 'int' and 'NoneType'
Time to debug what I messed up here! I clearly don't understand thematch
statement well enough yet. Ok, since I split on an empty space the "noop" line still is a list, so the case has to also look into a list like this:case "noop",:
. Good to know.if cycles < check <= cycles+inc: TypeError: '<' not supported between instances of 'int' and 'NoneType'
ah. Messed up my logic about usingchecks
. It should be the keys I'm working with and I also caught that I need to increment it.return sum(cyclce*X for cycle, X in checks.items()) NameError: name 'cyclce' is not defined. Did you mean: 'cycle'?
haha, those typos will get me every time.return inc, add UnboundLocalError: cannot access local variable 'add' where it is not associated with a value
you'd think I'd learn this by now.return plot_crt(draw_crt(instructions)) NameError: name 'instructions' is not defined
argh. wrong name!- Bit of an understanding error about the CRT. I thought it was continuous indexing, but in fact it is for every line individually. Easy fix!