I hope it doesn't scare off newcomers, but I already know a few who have given up on part 2.
I hope it doesn't scare off newcomers, but I already know a few who have given up on part 2.
I suspect it was purpose-built to foil ChatGPT. I solved it on my own first and then went back and tried to help GPT4 write a solution. Even after carefully walking it through a strategy, discussing edge cases, and having it outline a solution in pseudocode, it still failed completely to translate our conversation into working code. (It didn't even work for non-tricky input.) It did anticipate the edge cases though, so that's something.
Did anyone have any better luck with ChatGPT? I wonder if LLM-resistant puzzles and generally greater difficulty (at least for the second star) will be a theme this year.
My strategy was not efficient, but did work.
I walked the string twice, first LTR and replaced all found strings with numbers, then walked right to left, and replaced all backwards strings to numbers.
Then took the first digit from the left walked string, and the last from the right walked string.
(?=(one|two|three|[...]))
would return `["two", "one"]` for the input string `twone` since the lookahead operator doesn't consume the next character.No hate on AOC though, I really respect all the hard work that goes into it.
one -> eno
two -> owt
three -> eerht
etc
It makes the entire solution extremely simple, though a little verbose.
1. Build a list of values with corresponding string matches: [ 0 => ['zero', '0'], 1 => ['one', '1'], ...]
2. Loop through that and find the index of each within the input string, maintaining the lowest seen index + associated value.
3. When done, return value.
To find the last occurrence... just reverse the input string and all the search strings.
I'm not even sure it's all that verbose. If you exclude the part where I hardcoded an array of ten digits, it was... 11 lines of code, a third of which are closing braces. I'm sure I could cut it in half if I used some builtins for mapping/reducing/etc.
Mine is. But that's because I don't bother DRYing it and making it more clever (yanking and pasting is faster than thinking)
100% with you on this. Last year was the first year I'd had time to complete it, and I always love the challenge.
> eightwothree
> 4nineeightseven2
> zoneight234
I test my AoC solutions incrementally by printing output, so I found that I was failing to produce the correct list of numbers in a line right away. I suppose if you're taking a faster approach and just trying to extract the first and last numbers that it's easier to miss. It's always a good idea to look at the example input, though.
Though, I have no problem with the "spec". This a code puzzle game, so figuring that out was part of the fun, in my opinion
Meaning:
- eightwothree -> 823 (answer 83)
- 4nineeightseven2 -> 49872 (answer 42)
- zoneight234 -> z18234 (answer 14)
I interpreted the instructions as saying to take the first match from the left and not count the overlaps.
Unfortunately this gives the same answer as the overlap interpretation on the examples given in the problem statement: all the overlaps occurred in the middle where they didn't matter.
If they had shown
oneight -> answer: 18
then I would have understood the spec.
But I suppose can see the other side as well: the wording makes it sound like any spellings of those digits _counts_ as a digit rather than should be _replaced_ by a digit.
However I think the ambiguity here made the puzzle more difficult in a non-fun way.
https://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_algorithm
I then figured I'd use aho-corasick because that was an opportunity to, and there's no kill like overkill.
I then proceeded to waste half an hour because I didn't read the documentation, so I didn't see that `find_iter` finds non-overlapping occurrences. I assumed it found overlapping occurrences since that's what the algorithm does out of the box.
In particular, the SIMD optimizations in the aho-corasick crate only apply when MatchKind::LeftmostFirst or MatchKind::LeftmostLongest are used.
[1]: https://docs.rs/aho-corasick/latest/aho_corasick/enum.MatchK...
I thought it was over-complicating a day one solution, so I ended up brute-forcing similar to above solutions. Still, it is nice to learn about this algorithm. I may come back to give it a shot and compare runtimes later. Thanks!
However the 'naive' solution still feels quite nice. Some python, at the risk of sharing spoilers:
fixes = { "seven":"7", "two":"2", "one":"1", "nine":"9", "eight":"8", "three":"3", "four":"4", "five":"5", "six":"6" }
cands = set(fixes.keys()) | set(fixes.values())
total = 0
for line in Path("input/1.txt").read_text().splitlines():
matches = list(filter(lambda k: k in line, cands))
first, *_ = sorted(matches, key=line.index)
*_, last = sorted(matches, key=line.rindex)
total += int(fixes.get(first, first) + fixes.get(last, last))
print(total)