Commit Graph

37 Commits

Author SHA1 Message Date
ec27a5ec6c Day 16 solution
Following the formula for part 1 was straightforward enough, but finding the pattern for part 2 and deducing the shortcut formula took me a while. That first 0 1 propagate enough that by the time we get halfway through applying the formula, it's all 0s and 1s, so sort of like an addition with a mask on what numbers we're adding.

Also, fun fact: changing the numberSet from an array of ints (my initial implementation) to an array of int8's (what's here now) reduced the memory footprint of the application substantially (from something like 50mb to closer to 8).
2022-06-30 08:03:18 -05:00
f0be3f9f98 Day 15 solution
I wanted to use something like a right-hand wall solver, but the fact that you don't know the maze ahead of time and you can't see what something is without trying to move into it made that difficult. This semi-brute-force approach works well enough. I originally stopped as soon as I found the oxygen system and figured out the shortest path, but once I submitted that answer and saw that part 2 wanted the full map explored, I figured I might as well just fill the map all at once.

I think I would have been stuck on part 1 longer if my input set didn't happen to find the goal system fairly easily (or maybe my debug drawing helped me work through it with that input set specifically, I'm not sure) since a different input set required some tweaking to the max-visited threshold in order to find things that my first input set found with a lower setting.

Regardless, I'm pretty excited that I came to Trémaux's algorithm, more or less, on my own. I went to Wikipedia to see if I was on the right track and lo and behold, I had come to a version of it myself.

Part 2 turned out easier than I originally thought. I suspected this solution would work, but wasn't completely confident. It can only work for the type of maze used by this problem (where there are no loops of open areas). I'm just glad I didn't need A* or anything.

Oh, and this `stringer` command that allows debug printing of enums can be installed with `go install golang.org/x/tools/cmd/stringer@latest`
2022-06-29 08:11:33 -05:00
4cde56eb84 Day 14 solution
This one's part 1 destroyed me. I had a very difficult time, trying 3 separate approaches, each one of which worked for most cases but eventually fell apart on the 5th sample or my actual puzzle input. I ended up tweaking and rewriting until I landed on this which wasn't far off from what I was trying to do previously, but I had been overcomplicating things.

Part 2 surprised me in that I expected a simple "ore available divided by ore needed for 1 fuel" would solve it, but of course the excess chemicals produced in any given reaction meant that it wasn't that simple. So this approach uses that estimate as a lower bound, since it always underestimates, and then bisects its way to the solution (starting at the lower bound and adding 1 each time took too long). I'm sure a smarter upper bound choice could lower the runtime of this by a bit, but runtime isn't bad enough right now for me to try any additional optimizations.
2022-06-28 08:32:59 -05:00
dd5ea5ea86 Day 13 solution
This was incredibly cool and I had a really fun time with it. Uncomment the draw and sleep in Part2 to see the game play itself! Note that I'm not seeking around in the terminal window to make the drawing smooth, I'm just outputting each new frame as it happens, so there's some jitter, but it still looks great!

I messed around a bit with control codes to move the cursor around instead of the "draw the buffer over and over again" approach, and they work, mostly, but I'm sticking with this for now.
2022-06-27 00:01:19 -05:00
2178a2618d Day 12 solution
Okay, I had to seek some advice on this one. The orbital period + least-common-multiple solution was not coming to me naturally.
2022-06-23 10:08:33 -05:00
4cdd9c645b Day 11 solution 2022-06-22 08:17:45 -05:00
14625d191e Add utility for array AddUnique 2022-06-21 12:23:12 -05:00
1cdc94bebe Move Pair to a more reusable location
I originally used this in my day 10 solution, but ended up removing it. Either way, it's a general utility so it belongs here.
2022-06-21 12:22:30 -05:00
ff10dfd1ba Display part1 output as soon as it's ready
When we start having problems that take a while to run, it sucks to have to wait for everything to finish before we see any output.
2022-06-21 12:21:03 -05:00
ca6a16cedd Intcode Reset optimization
Initially I noticed that I was copying twice unnecessarily (once in init() after nulling out memory, and again after returning from init()). After cleaning that up, I realized that we don't need to create a new buffer at all if the program never malloc-ed, so sometimes we can skip the re-init and we can always avoid the double-copy. I don't know if this is actually measurable anywhere, but I spot-checked some results and I still seem to be getting the same answers, so I'm gonna roll with it.
2022-06-21 12:20:37 -05:00
0b4cd9e634 Day 10 solution
This one was an absolute beating for me. I am so bad at these sorts of problems. Ultimately I settled on a probably-not-ideal solution that crawls the graph with offsets of each variant of (+/-x,+/-y), marking nodes visited as we come across them so that we end up with a list of asteroids that we can see. Given that this is day 10, and knowing how bad I am at math, I'm assuming this is very far from the intended solution, but it works reasonably quickly and I managed to come up with it myself, so I'm not going to stress too much about it.

For asteroid destruction, the best method I could come up with for finding the correct order was to implement an entire Vector class and sort by angle, which worked, but again, I can't decide if it was the intended solution or not. I should start reusing past years' codebases so I don't have to keep building a utility library from scratch.
2022-06-21 12:18:31 -05:00
d7836f4e59 Day 9 solution
This day showed me that when the input instruction was introduced and said "write addresses will never be in immediate mode", that didn't mean "so don't bother handling modes for input addresses", it meant "handle the mode, but assert if it's immediate mode". It was super helpful that this program contained a bootstrap sequence to validate each instruction.

Memory expansion came with a few caveats: obviously reads and writes needed to handle expanding the memory space, but a Reset also can no longer get away with simply copying the program into memory again because we need to ensure that any additional memory is cut off (or at least zeroed), so the quickest way to handle that in Go is to simply allocate a new buffer; I'd rather manipulate the existing buffer, but I'm having a hard time finding the best way to do that.

And finally, make sure you reset your relativeBase when resetting the program...that one was ugly to track down.
2022-06-20 08:54:52 -05:00
b321fb87ec Day 8 solution
I had fun with this one. I liked how straightforward it was, and it's always satisfying to see the code print a message visually when you're done.
2022-06-16 08:24:56 -05:00
d129e52c70 Day 7 solution
I will probably end up regretting this since I assume the "wait to be given an input from some other process before continuing execution" paradigm is going to come up again, but this part 2 goroutine+channel solution felt good (taking advantage of Go features) and made me happy, so I rolled with it.
2022-06-15 08:58:51 -05:00
c8878ffbce Day 6 solution
I'm reasonably happy with this. I started with a bi-directional linked list, but realized that a flat list of all nodes came in handy for one use case while the linked list came in handy for another, so I settled on that.
2022-06-14 09:21:10 -05:00
acef5fdc12 Day 5 solution
This required an overhaul of the intcode machine to actually be its own type that could operate on its own memory and stuff. So I had to touch day 2 to make it adhere to the new API.

Feeling good about this foundation now. Until I get gobsmacked at some point later, which I expect to happen.
2022-06-13 15:29:18 -05:00
bdd007bb4d Reduce changes needed to the template
I always end up making these changes each time I copy from the template.
2022-06-12 13:37:24 -05:00
6d3627e93b Improve output formatting
Adds some whitespace, a divider, and indents each part's output a bit.
2022-06-10 10:34:44 -05:00
40d5eb59be Add flags to only run a specific part
Now we can specify to only run part1 or part2 of the given day(s). Just in case we need some super focused testing or debugging!
2022-06-10 09:56:37 -05:00
731e991f1f Support piping data in
This allows using someone else's data to compare runtimes, behavior, etc. without having to recompile. Since it's patched into the function that all days use to read, it's incompatible with running all days, which I feel is a reasonable compromise and behavior expectation.

The Mode() check is how the internet says you can test if you should even try to look at stdin, and the Size() check ensures that there's actually data to be read instead of just an open stdin handle (running in VSCode with a debugger seems to keep the stdin handle open, for example, so it passes the Mode() check and then hangs when trying to read since there's nothing to actually read).
2022-06-10 09:42:04 -05:00
c9cfffcc1c Show timing information when running all days 2022-06-10 09:15:08 -05:00
28ea3ff6a1 Handle an empty argument
This makes it slightly easier to adjust VSCode's launch.json to hop around debugging different days. Not much, but a little. And every little bit helps!
2022-06-09 13:17:51 -05:00
bc8ebae440 Day 4 solution
Plenty of room for optimization here, but it's enough for my needs for now.
2022-06-09 08:23:34 -05:00
a53e3467fe Make the linter happy
I mean, it's right, but still...
2022-06-08 18:03:08 -05:00
8ec5aafcc2 Day 3 solution
This is horrendous and slow. But it works. I really don't like grid problems.
2022-06-08 08:23:07 -05:00
2a8384949f I kinda like this Run method on the receiver 2022-06-07 22:54:57 -05:00
092fe15b07 Fix running "all" tests out of order sometimes
Maps are unordered, so this uses an array, which is simpler overall, really.
2022-06-07 22:54:11 -05:00
e8e9eeee02 Remove unnecessary breaks
I forgot that Go doesn't require these.
2022-06-07 20:41:41 -05:00
8cd4994300 More slight streamlining 2022-06-07 10:01:29 -05:00
dd5c072730 Make opcode constants
Just planning for the future...
2022-06-07 09:54:40 -05:00
9b65c91041 Add readme 2022-06-07 09:54:20 -05:00
93c9bc7d6f Day 2 initial solution
There's room to optimize part 2, but I wanted to commit my original brute-force solution first.
2022-06-07 09:26:21 -05:00
d2fbe85a71 Set to automatically run the most recent day 2022-06-07 09:14:24 -05:00
2f5dac4487 Add new day template 2022-06-06 15:33:26 -05:00
85da090c2b Output tweaks, fix day numbering 2022-06-06 15:30:58 -05:00
131fb0f03a Remove sleep added for timing testing 2022-06-06 15:18:26 -05:00
662d76eb7c Bootstrap and day 1 solution 2022-06-06 15:14:31 -05:00