8
votes
Day 13: Care Package
Today's problem description: https://adventofcode.com/2019/day/13
Join the Tildes private leaderboard! You can do that on this page, by entering join code 730956-de85ce0c
.
Please post your solutions in your own top-level comment. Here's a template you can copy-paste into your comment to format it nicely, with the code collapsed by default inside an expandable section with syntax highlighting (you can replace python
with any of the "short names" listed in this page of supported languages):
<details>
<summary>Part 1</summary>
```python
Your code here.
```
</details>
Part 2: I made the game interactive, and used the crossterm Rust library to help render the field and receive keyboard inputs nicely. The game only steps forward when I press left, right, or spacebar. I wasn't super great at the game and messed up a lot, so I made "z" step the game backwards. I implemented rewind by recording all of my inputs into a list, and when I rewind, I reset the game state to the original state and replay all of my inputs except for the last one. (I could have optimized this by snapshotting the game state every N inputs, and replaying from the most recent snapshot, but my intcode emulator was fast enough to not need that at all for this game.) I then played the game to the end manually (with a lot of rewind usage).
Part 1 seems pretty simple. Part 2 looks like it'll be a fair bit more complex. Fuck.
Part 1 - Python
I just glued a simple script onto intputer that splits it into chunks and counts the number of block chunks. It's like 10 lines.Running in Jupyter Notebook might really bite me in the ass for Part 2. We'll see
Edit: I'm going to scream, I think I got a really shitty seed and it's causing me problems with my ball ricocheting off into unreachable areas. It's fixable, but I don't think it's going to be easy. God damn it.
Part 2 - Python
Minor update to Intputer, it now has the ability to clear it's output buffer.Yeah, this one was extremely fucky. I'll have some tips in a second once I wrap my head around how I actually got it to work.
Part 2 Tips - Not Really Spoilers
The X:-1, Y:0 location shows up for every output, not just at game over. But it's result at game over is your score. I had built my script to end when it saw that as an output, but it shows up immediatelyPart 2 Tips - Minor Spoilers
I highly recommend building a tiny bot to make the game play for you. Manual input is going to be a huge pain. My game ran for like 15k steps. You don't want to do that by handPart 2 Tips - Moderate Spoilers
Tracking the ball direction between frames is relatively easy. If you do that you can figure out the ball's direction and predict where it's going to be. Figuring out the appropriate paddle behavior was much more annoyingPart 2 Tips - Moderate Spoilers
How your paddle is moving when the ball hits it determines the angle the ball shoots off in. This had me stuck for a long time because my ball kept shooting off at an impossible angle. Eventually I modified my paddle logic to make it reflect at more reasonable logic. I'm not entirely sure why it works.This was really fun, and I was able to re-use most of my Day 11 code as a baseline.
Part 1
Part 1 was more or less exactly the same as my Day 11: run a program, paint a display on output, count the painted tiles. The only real difference is that now I have to wait for a set of three outputs before I can paint, instead of just two.Having switched to lambda/callback driven IO also helped here.
Code for P1/P2 - Crystal
Once again my VM code itself is pretty much unchanged
For Part 2, I already had a debugger that I'd made yesterday, so once I knew what I was looking for I could load it up and find the memory addresses for the ball and paddle, and use that information to create an autopilot to find the answer.
To find the paddle, I watched the input routine to see what it examined and output to, there was an address that always either increased or decreased by the appropriate amount (there was also a check to stop it going over the borders, which was another hint), so that wasn't too hard.
Once I had the paddle, I could disassemble the rest of the program and look for all the places that address was used to find where the ball-paddle check was happening, and determine the address for the balls x and y positions there. I briefly explored patching the game itself to always register a paddle hit, but ended up just writing an autopilot function into my arcade machine input routine.
After I had all that working, I went back to work on the input and display and found a Crystal binding for ncurses. It took a while to get it working the way I wanted, but I'm pretty happy with the result.
I liked this one. I maybe overcomplicated it in displaying the board but oh well.
Code is in its happy little Python modules again for both parts 1 and 2.
Intputer.py
CarePackage.py
Part 2 Spoilers
I used a super simple bot for playing the game. All it does is move towards the ball, and that was enough for me to get it. I tried playing by hand but it was frustrating, and I figured doing all the work of a replay system like I saw discussed here and then having to play would be more effort than just making a simple bot. I did try to just have it move randomly but that did not really work so I gave up on it.
It's fun to let what is basically a virtual machine you programmed yourself run a little game like that! But I found a frustrating amount of work to go into basically reverse-engineering the actual game code. God knows when the paddle is actually redrawn.
The intcode interpreter is also the first time I did something proper with generators and yield in js. I still don't get why I have to run an empty next() before actually putting in the input?
Intcode module
Part 2