Live data from Hacker News

Advent of Code 2023 is nigh

adventofcode.com

141–150 of 319 posts

Re: Advent of Code 2023 is nigh

#141
I don't know if I'll even bother this year. Their puzzles start feeling like chores by the 10th problem or so and I drop out. Maybe I'll learn a new language to spice it up this year.

Re: Advent of Code 2023 is nigh

#142
post #46
post #24

Part two was exceptionally hard. Many people on reddit reporting they were hit by one edge case that's not covered in the examples. But my implementation passed these edge cases too. I was hit by another edge case. So there are at least two edge-cases (which are in the actual data) that aren't covered in the examples or the description.

Warning: post contains spoilers, HN doesn't support spoiler text so continue reading at your peril. These edge cases are triggered by fundamentally approaching the problem incorrectly. In some ways it's excellent to bring that up early in a way that's relatively easy to debug and diagnose. Like many others I started with the wrong solution, and I was hit by the same problematic cases, but what I found interesting was…

Here's a snippet of a first attempt, which does not work:

  |> Array.map (fun s -> Regex(@"(one|two|three|four|five|six|seven|eight|nine|\d)").Matches(s))
  |> Array.map (fun m -> m |> Seq.map (fun g -> g.Value) |> Seq.toList)
And here's the correct code:

  |> Array.map (fun s -> Regex(@"(?=(one|two|three|four|five|six|seven|eight|nine|\d))").Matches(s))
  |> Array.map (fun m -> m |> Seq.map (fun g -> g.Groups.[1].Value) |> Seq.toList)
There's no "fundamental" difference between the two, rather, one uses a regex with positive lookahead and the other doesn't. The first approach was not operating under the assumption that there would be strings like "oneighth" at the end of a line. That's a detail and it only applies to one part of a functional pipeline!

Re: Advent of Code 2023 is nigh

#143
Advice from 7 years of doing (and sometimes completing!) the Advent of Code:

1. Look at the example input.

2. Run your code on the example input.

3. Seriously -- make extra super 100% sure your code works on the example input. Write some boilerplate code to make it easy to switch between your input and the example input.

4. Think about possible edge cases in the input -- there will probably be some. Looking at your input in a text editor can help uncover them.

5. If part 1 is simple, it's just there to test your input processing, and part 2 will be the real puzzle.

6. If part 1 is solvable with brute force, part 2 probably won't be. But sometimes it's helpful to brute-force part 1 just to see what the question is.

7. Many problems that involve the word "shortest" or "fastest" are good candidates for a breadth-first search. Make sure you know how to do that.

8. Test your code as you go. Printing the output of intermediate steps to the console is a great way of catching bugs.

9. There's going to be some hideous puzzle, probably involving a maze, which is too hard for a simple BFS and requires heavy pruning of alternatives. If you know how to do this kind of puzzle, please tell me how; they get me every time. :-(

10. Don't even look at the leaderboard times. Those people are nuts.

Re: Advent of Code 2023 is nigh

#144
post #127

Earlier quoted context omitted.

Rust regex crate author here. fancy-regex is built on top of the regex crate and supports look-around. The regex crate doesn't support arbitrary look-around because it isn't known how to implement efficiently. See: https://swtch.com/~rsc/regexp/regexp1.html

> The regex crate doesn't support arbitrary look-around because it isn't known how to implement efficiently. A bit of a philosophical question: If how to write an efficient implementation is yet not known to man, ie. not a matter of the library's author time or skills, but literally a limit on human knowledge: why not at least provide the functionality with a good enough implementation? (with caveats just possibly me…

Because it is a mechanism for ReDOS, and the standard library should not be introducing vulnerabilities into users. Other libraries can implement it for folks who decide they really need it.

Re: Advent of Code 2023 is nigh

#146

Advice from 7 years of doing (and sometimes completing!) the Advent of Code: 1. Look at the example input. 2. Run your code on the example input. 3. Seriously -- make extra super 100% sure your code works on the example input. Write some boilerplate code to make it easy to switch between your input and the example input. 4. Think about possible edge cases in the input -- there will probably be some. Looking at your i…

[deleted]

Re: Advent of Code 2023 is nigh

#147

Seems to me that people made part 2 harder than it us. Just define an array containing the digits: "one", "two", and so forth. Then check for substring matches, position by position. Maybe not elegant, but effective.

I think the issue is that they tried to separate the input into a list of tokens, like ["5", "nine"], and work from there, which doesn't work on something like "oneight".

Re: Advent of Code 2023 is nigh

#148
post #16

A bit off-topic, but does anyone know if Hanukkah of Data[0] is happening again this year? [0] https://hanukkah.bluebird.sh/about/

We didn't put another one together this year. But I'm hoping to do another data game sometime in Q1--ideas are brewing.

Re: Advent of Code 2023 is nigh

#149

I think the edge cases were entirely unclear in day 1, part 2. I had to redo it in a "dumb"/brute-force way to avoid using fancy regex tricks I don't know. It's quite clear the small sample data was chosen intentionally to not cover them.

that's interesting.

my example data did include the edge case that caught me out in part two, but didn't include it in a way that broke my first pass at a solution.

funny piece is it didn't click until i submitted a wrong answer, read my code for a few minutes, added a bunch of logging, and then saw the trick. i looked back at the given example and it was right there the whole time, just not called out explicitly.

Re: Advent of Code 2023 is nigh

#150

Advice from 7 years of doing (and sometimes completing!) the Advent of Code: 1. Look at the example input. 2. Run your code on the example input. 3. Seriously -- make extra super 100% sure your code works on the example input. Write some boilerplate code to make it easy to switch between your input and the example input. 4. Think about possible edge cases in the input -- there will probably be some. Looking at your i…

> Run your code on the example input.

> Seriously -- make extra super 100% sure your code works on the example input. Write some boilerplate code to make it easy to switch between your input and the example input.

> Test your code as you go. Printing the output of intermediate steps to the console is a great way of catching bugs.

Honestly, just set up whatever you need to be able to write unit tests in your lang of choice. These problems are _so_ amenable to a piecewise approach driven by tests. I'm not like a big TDD advocate or anything, but these problems are great practice for that style of coding - it's just so damn useful to know each of your small pieces of code work.

Parameterized tests are amazing for AoC, because you can get a handful of test cases basically for free from the puzzle description. If your code doesn't work once you've got all the samples working, you either have some weird edge case that you didn't consider, or you've got one of the brute-force killer puzzles.

Even for today's, I wound up with 43 different test cases. The vast majority of those are from the puzzle text, and adding them didn't really make the puzzle take that much longer. (Obviously, if you're optimizing for solve speed, you probably wouldn't bother with this approach, but I'm not).

https://github.com/epiccoleman/advent_of_code_ex/blob/master...

Another thing of note is that every puzzle basically operates on a list of strings, so it's pretty easy to genericize certain parts of the work of solving puzzles. I have a script which generates a module for the solution in my repo, with separate functions for each part that receive the input, and a test file that has tests for part 1 and part 2. The tests read the input file and pass it as a list of strings (lines) to the part_1 and part_2 functions, so that all the boilerplate is already done, and I get to just focus on writing the guts of the part_1 and part_2 functions (which usually get broken down into several other functions, which can also be tested individually).

Post reply on HN