Commit Graph

56 Commits

Author SHA1 Message Date
8a6bf8604a Day 21 part 1 and WIP for part 2
I also improved the main startup code to require a little less maintenance.
2021-12-21 22:51:21 -06:00
60d61584c8 Day 19 solution
Cribbed heavily from https://www.reddit.com/r/adventofcode/comments/rjpf7f/comment/hp5k554/?utm_source=share&utm_medium=web2x&context=3 because this problem breaks my brain in so many ways. I understand the approach, but I got twisted up in my own head trying to write down the solution, so instead I started from a working copy and optimized it (a little bit) to make sure I understood what it was doing.
2021-12-20 15:37:41 -06:00
e818c949ef Fix piped input...again
I don't understand why this keeps breaking. I guess a char can be more than a byte, which makes sense, but I also don't understand why these files (which multiple editors claim are utf8-with-bom) are prepended with apparently utf32 characters or something. Anyway, hopefully just embedding the array I'm seeing and comparing against that will work...
2021-12-20 12:27:06 -06:00
8a33549ad2 Day 20 solution
I would have had this done last night, but... _unintelligible muttering about key[0] being '#' in the real input and '.' in the sample...

Day 19 is...still vexing me. Maybe I'll get back to it later.
2021-12-20 09:09:43 -06:00
fd1a93fa10 Add testing utilities
These are pretty rudimentary and I'd like to expand them, but I don't know that I'll need them for future days, so I'll solve that problem if I need to later.
2021-12-18 16:24:05 -06:00
fd0fd238f7 Day 18 solution
I have a very strong feeling that I massively over-complicated this, but it works. I spent a ton of time making sure each component of the problem was implemented correctly so I could quickly identify where things went wrong, and that setup was convenient enough that I just formalized it and left it in. Maybe it'll be useful for another day...
2021-12-18 16:23:54 -06:00
67a5560dd8 Use the convenience method I added
Why did I add it and then not use it? We may never know.
2021-12-17 12:03:14 -06:00
8e0e515164 Make VS be quiet 2021-12-17 11:55:11 -06:00
8c97fff459 Cut day 17 run time in half
You'd think I'd have learned my lesson about Dictionaries by now. They're great, but only for sparse input sets or where lookup needs to be as fast as possible and other access types are less important.
2021-12-17 11:49:03 -06:00
5189bb6734 Fix day 17 edge case
My algorithm failed with the input in https://www.reddit.com/r/adventofcode/comments/rid0g3/2021_day_17_part_1_an_input_that_might_break_your/ as predicted by the poster. Instead of judging only X values which eventually settle to 0, I am now considering all X values that ever pass through the target area.
2021-12-17 11:46:13 -06:00
41f0d167e4 Report more accurate timings
The string colorizer is slow (but apparently only the first time it runs, for some reason?), printing can be slow, who knows what else the framework is doing, etc., so manually inserting Stop()s exactly where we want the timings to stop is the most reliable way to handle this. I like the elegance of the disposable solution, but my goal here is to measure the actual algorithm, not anything else.

A slightly restructuring would make it so I don't have to do this; if main.cs was receiving a string from Part1 and Part2 instead of having each day individually print its own results, we could scope timings to exclude any console writing. But whatever.

I also went ahead and made 17 only run once since I was using the same result to answer part 1 and 2. I've since discovered that part 1 is far simpler and can be found without solving the entire problem space, but whatever.
2021-12-17 10:57:33 -06:00
4062039bad Day 17
I've done better. I've done worse. ¯\_(ツ)_/¯
2021-12-17 10:20:18 -06:00
c48770c388 Use switch statement
I keep forgetting these exists and they're great.
2021-12-16 16:06:45 -06:00
13cc275842 Expand color code support
Because @tocchan had such a better implementation than me.
2021-12-16 16:06:27 -06:00
542df5bd8c Day 16, extreme parsing edition 2021-12-16 09:23:08 -06:00
eeed2bbdd3 Save another 30% or so part 2 perf
This is really dipping into "sacrifice programming convenience for performance" territory, but the savings are nice enough that I'll sacrifice a bit here. This drops my 50ms part 2 to more like 34ms.
2021-12-15 13:28:53 -06:00
84c7f424ba >2x speedup for part 2
Based on a suggestion from @tocchan I converted the total risk map from a Dictionary to an array and things really took off (125ms to 50ms on my machine in Release). And that's with a sub-optimal fill/memset of the array to int.MaxValue (which I couldn't find a better way to do without diving into `unsafe` territory), though that step only takes about 500us with this method anyway, so it's hardly the worst part.
2021-12-15 12:15:31 -06:00
eb45460f21 Add ability to manually stop a timer
This way I can have multiple timers in a given scope that measure different things without super awkward `using`s that end up scoping out variables that I need access to later. The timings get printed in reverse order, of course, but the conveniences provided outweight that minor flaw.
2021-12-15 10:51:34 -06:00
5f830051e8 Day 15 solution
Heavily cribbed from https://github.com/encse/adventofcode/blob/master/2021/Day15/Solution.cs but transformed to be more my style. At its core, this is just "implement Dijkstra", so I feel no shame in using an existing implementation of a known algorithm. :)
2021-12-15 10:50:33 -06:00
aaf31ed7b1 Shave a few ms off day 14
This is a small low-hanging fruit pass. I was really just curious where the time was going since I didn't feel like the algorithm was actually expensive. Turns out it's not, really...the larger cost is setting up the frequencies and pairs collections, and computing min/max was 9x more expensive than it needed to be (I was expecting 2x since I was iterating over the collection twice, but 9x is...unreasonable, so I just unrolled it myself). It also turns out that MinBy() is marginally slower than Min() with no gain (for this use case), so that was an easy win on the brute force solution.
2021-12-14 12:51:50 -06:00
07cad08733 Add ability to name timers 2021-12-14 12:48:45 -06:00
49e1e667a8 Fix input redirection for hyperfine
For some reason, Console.IsInputRedirected is true when run under hyperfine even if we're not redirecting anything. I wonder if hyperfine is opening an input channel in case it's needed? Either way, the fix is pretty simply to try reading from stdin and then falling back to the file on disk if our input set is still empty afterward.
2021-12-14 12:14:14 -06:00
bd6038c837 Day 14 initial solution
Part 1 brute force, part 2 solved "correctly" (I think, anyway). This day runs slower than I would expect, given how little part 2 is doing.
2021-12-14 12:01:35 -06:00
43be612236 Apply VS suggestion 2021-12-13 12:14:48 -06:00
dd14127c1e Update template again 2021-12-13 12:14:48 -06:00
ddf758951e Add ability to pipe input from a file
I'm sure there's a better way to strip the UTF-8 BOM from the beginning of the file (and/or use that information to actually handle the string appropriately) but this works for my use case. At this point, we support ASCII and UTF-8 in LE order with or without the byte-order mark and, I think, either \n or \n\r line endings as input text file formats.
2021-12-13 12:14:48 -06:00
f2e8a3a288 Add ForEach extension method on IEnumerable 2021-12-13 12:14:48 -06:00
fe2d276115 Add colors and stuff
Because I think it's neat. Ref: https://www.lihaoyi.com/post/BuildyourownCommandLinewithANSIescapecodes.html
2021-12-13 12:14:48 -06:00
884e685c62 Make code much more readable
Thanks for the idea, r/adventofcode!
2021-12-13 09:03:11 -06:00
4fc4bd2c20 Day 13 optimized and fixed
This fixes my logic errors from the first attempt so the letters are much clearer now. It also swaps from trying to iterate over segments of a grid, pulling from later segments, to simply storing the list of marked points in a more efficient (and obviously smaller) collection that we add to and remove from when transforming points via folding, which is where the speedup comes from.

Fun fact: printing the result is about a quarter of the runtime of part 2.
2021-12-13 08:51:49 -06:00
4b9ff1c4bd Day 13 solution
Honestly I think I have an error somewhere in the part 2 logic because my final output characters weren't exactly correct, but they were close enough that my first guess for each letter was right. So I may revisit this to find and fix the logic bug, but apparently it's Close Enough™ to be done for the night.
2021-12-12 23:58:42 -06:00
9e7942a35e Enable running all days at once
I'm kinda bored and wanted to.
2021-12-12 15:28:41 -06:00
5c37fc4129 More day 12 optimizations
Down to  ~98ms from the original ~940ms. That's a very respectable gain, but I am still not quite happy with the runtime. At this point, though, I think I will need to re-think my approach rather than making small tweaks.
2021-12-12 11:25:58 -06:00
c292bd45c6 3.4x speedup on Day 12
First round of the lowest of low-hanging fruits to get day 12 runtime from ~1s to ~280ms on my machine in Release. Still not happy with 280ms, so I will probably keep digging.
2021-12-12 10:57:29 -06:00
0dc2abeca9 Day 12 solution
This was my initial solution I used to submit the puzzle answer. Runtime for part 2 on my input set was around a second, so now I'm going to find optimization targets. I'm sure there's a lot I could be doing much better.
2021-12-12 10:08:46 -06:00
03c6ab60ef Update template
I found out that C# 10 added file-scoped namespaces that don't need the whole thing to be wrapped in braces, so that's neat.
2021-12-10 23:51:57 -06:00
a522b93f9b Day 11 solution
Pretty happy with this one overall. I tripped myself up on part 2 and caused a huge headache by not realizing that I was passing the already-modified array from part 1 into part 2. I left some code to copy the 2d array because that was my original solution (and it's not straightforward to copy jagged arrays), but then realized that the synchronized flash doesn't happen until after step 100 (at least for my input and the demo input) so we can just account for that in part 2 and pick up where part 1 left off.
2021-12-10 23:49:32 -06:00
e61f2bd255 Enable specifying which day to run
I like this tradeoff of running a single day in isolation so the output isn't muddied by other days but also being able to go back and run previous days' solutions (for comparison with friends also participating in advent). The only thing I wish I could do here is run "all" to fire them back to back, but this particular implementation doesn't allow that easily. Maybe later...
2021-12-10 13:54:18 -06:00
0cda2f9406 Equivalent day 1 in C#
Again, purely for curiosity/performance comparison reasons
2021-12-10 13:51:44 -06:00
db06f5b5c6 Day 1 in Go
Purely for curiosity/benchmarking-against-identical-Rust-version reasons

Spoilers: Rust is somewhat faster than Go and very much faster than .net
...though presumably .net's problem is purely startup time
2021-12-10 13:46:41 -06:00
21b9ccbfee Fix to run on Windows
I forgot about line ending differences.
2021-12-10 13:22:33 -06:00
f4a43710b8 Minor day 10 updates
I feel like this solution is a little cleaner/clearer. Same concept, just cleaned up the code a little more to my usual style. Some parts are a little bit slower, but I don't mind too much for this purpose.
2021-12-10 10:49:00 -06:00
55b385f779 Day 10 solution
I actually feel pretty good about this one.
2021-12-09 23:23:49 -06:00
2c224483b4 Day 9 solution
As always, plenty of room for improvement, but I'm reasonably satisfied with the core implementation. I'm honestly not sure why the Distinct is needed in the GetBasinSize() result as it's supposed to not even add the point if the point is already in there, but it's late so I'll check that out later.
2021-12-09 00:40:02 -06:00
0dd261b964 Enable nullability
I thought this was the old way. Apparently it's the new way.
2021-12-08 11:55:19 -06:00
1330d1eb66 Day 8
I hate almost everything about this solution. It's all awful and a product of constantly adjusting how I was solving the problem to try and get the correct answer, so there are vestigial pieces of each road I headed down. Then I ended up using some combination of all of those pieces to get the actual answer, and...well it just needs to be overhauled dramatically. But it works, so I guess mission accomplished.
2021-12-08 10:57:36 -06:00
cfb3c668c7 Day 7 solution
I'm reasonably happy with this one. I'm sure there's an easier way to determine the smallest distance, at least for part 1, but this works fast enough for me.
2021-12-07 07:56:11 -06:00
2cc95c6e8e Day 6 solution
Took me a while to come to the fast solution, but I got there.
2021-12-05 23:55:15 -06:00
b8848ab334 C# day template 2021-12-05 11:19:13 -06:00
7d93691276 Day 5 solution
There is a lot to be disliked here, starting with the Line Length calculation, which I'm sure I'm just totally overthinking or otherwise being dumb about, to the way I'm picking the next point while moving along the line.

Also, TIL how much of a difference a good GetHashCode() override can make when comparing/equating custom struct instances. Not implementing GetHashCode() on this solution resulted in ~250ms runtime on my PC. Implementing a "bad" GetHashCode() (which was `return x.GetHashCode() | y.GetHashCode();` which seemed fine to me ¯\_(ツ)_/¯) resulted in >1s runtime on my PC. Using this implementation (HashCode.Combine()) results in ~25ms runtime on my PC. Those numbers are with nothing changing other than the implementation of GetHashCode() on struct Point.

I also disabled nullability in my quest to improve performance here. The compiler was complaining that my Equals() override wasn't equivalent because of nullability, so it had to be `object? obj` which I didn't care for since this was a value type and not a reference type.
2021-12-05 11:19:13 -06:00