Advent of Code 2019

The story of my slow descent into madness

View on GitHub
13 December 2019

Day 13: Care Package

by Simon Berger


Links:

We have another intcode problem on our hands, but this time with very few and ambiguous instructions. Is it just me or did today’s puzzle omit a lot of details which would’ve otherwise been included? It didn’t pose a problem, I just thought it was weird.

Like yesterday, today’s first part only really checks whether one has comprehended the problem and that the machine does what it should.

The second part makes things slightly harder by requiring “you” to beat the game. The idea is of course to write an AI that does it for you. Because the game is pretty much just Atari’s Breakout this isn’t all that hard. To beat the game we can just make the paddle follow the ball’s position. I suppose the challenge is to actually get the input timing and output parsing right, which, depending on the implementation of the intcode machine, can be pretty difficult.

My idea was to generate the input “on demand” so that whenever the machine reads the input it is calculated based on the paddle’s position relative to the ball’s. Sadly, my intcode interpreter doesn’t support “lazy input”, so I had to resort to some pretty hacky code.

You can just look at it yourself, but basically the game loop manually steps through the intcode until it has collected three outputs. If, while running, the machine reaches a state where it can no longer continue, the code will either provide an input or stop the game, if the machine has halted. It ain’t pretty, but it works!

In hindsight I should have just let the machine run until it halts or requires input and then parse the output. This way I could’ve just re-used the send method. There is no need to handle each output instruction right on the spot. The only thing that matters is to know the current position of the ball and the paddle when providing the input.

I spent most of my time today trying to visualise the second part. I wanted to just print every “frame” of the game to the console, but that doesn’t look any good. The problem is that you get this weird scrolling effect, which I think is caused by the fact that the operating system uses a line buffer for the STDOUT stream. Because each line is flushed separately you get this line-by-line effect which makes it look like the game is scrolling by.

To solve this I started using ANSI Escape Codes to move the cursor around. This is also what I’m using for the coloured output. By moving the cursor I can avoid having to print the entire image over and over again. Instead, I just keep modifying the same image. Additionally, I keep track the lines that were modified by the machine and only redraw those. This avoids a lot of unnecessary writing and thus removes (most of) the flickering.

Here it is in action:

Visualisation of the second part

Fun Fact: Maybe you’ve noticed that the cursor on the right hardly ever moves. The reason for this is that the paddle moves a lot and thus its line has to be redrawn a lot. But the ball moves just as much, why does the cursor always show up at the paddle’s line? You might think that it’s because the image is rendered top to bottom, but that isn’t actually true. As I stated before, only “dirty” lines are redrawn and these lines are stored in a hash set, which yields its item in an arbitrary order. To be fair, it isn’t completely arbitrary, but at least it’s not sorted in ascending or descending order. Based on this we would expect to see the cursor switch between the paddle and the ball, but as we know, that’s not what it does. If you were hoping to read a satisfying explanation for this then I’m sorry to disappoint. I don’t understand why this happens. I hope you enjoyed this not-so-satisfying not-so-fun fact.

tags: intcode - visualisation
Overview
Previous day Next day