13
votes
Day 6: Tuning Trouble
Today's problem description: https://adventofcode.com/2022/day/6
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>
My Python solutions, which are identical other than the
WINSIZ
constant.Surprised there were so many test cases given, since this one is rather
straightforward.
Part 1
Part 2
Part 1, in Python-ish
Python code generated from the above
sed 's/4/14/'
for Part 2.Do you have a link to where I could learn more about Python-ish? When I try to google it I just get a bunch of people talking about things that are like or similar to Python and not what you are using.
https://tildes.net/~comp.advent_of_code/13l9/day_4_camp_cleanup#comment-7lvt
thanks for linking to this!
@Gyrfalcon—you won't find it searching "Python-ish" online, that's just a name i made up for the purpose of posting AoC solutions to Tildes :)
Well I definitely appreciate you posting, even though I can't say I understand what is going on all that much better after reading you describe what it is.
Part 1
The nice thing about Racket's for iterators is they can be nested (for*) or in-parallel (for). This makes iterating a small sized window nicer because you don't need to deal with indexes except for initialising them.Part 2
Extend the idea to part 2 but convert the string to a list. Named let in Racket/Scheme is an idiom like defining an internal function where the let bound variables correspond to function arguments. You _can_ define internal procedures in Racket but it's overhead for a simple case like this. The Racket libraries are littered with hundreds or thousands of named lets.Speedrun
Better to keep a running count of letters in a sliding substring. If Racket had a nice counting library like python's I wouldn't need to write these.Attempt 1:
Part 1 ~75% elapsed time
Part 2 ~35% elapsed time
Attempt 2:
I wish I could remember that
hash-count
is a constant time count of keys.Simply replace
(= n (length (hash-keys cs))
with(= n (hash-count cs))
as the exit clause below givesPart 1 ~50% elapsed time
Part 2 ~20% elapsed time
Reading your solutions [and the docs, to figure out what you did xD] is always super helpful. :D
I went about it a bit differently, by manually keeping track of the index. Which also meant part two was a change of adding a single character. xD
Both Parts
That's kind of you to say, thanks.
I did essentially the same for part-02, except I didn't check the length because AoC basically guarantees we'll find an answer. In real code you bet I'd be checking if the list is running out of items.
One thing to be careful about is that length has to consume the whole list - the compiler doesn't have internal state for list length.
Instead of repeatedly checking the length, it would be more efficient to pass the length as an argument to process-slice and keep reducing that value as you chop off more of the list. That way, you don't go through the whole list every iteration, instead you just subtract from the value you calculate once at the start.
Oh, right. O(n) in a place I didn't expect.
Thanks for the pointers! :)
Python
Elixir
👶
Both parts
Wasn't sure what to name the function tbh. It's not really giving the index.
About
|>
I abuse it in my solutions (because it's fun), but the
|>
("pipe") operator is basically just syntactic sugar.Functions in Elixir, for the most part, are not tightly coupled with data types. As a counterexample, arrays in JS have array functions as "methods"—
myArray.map(...)
. The method gets the "subject" array as an implicit firstthis
argument. There are no methods in Elixir. Data and logic are more strictly separated. Instead, we have functions where you explicitly pass the "subject" as the first argument:Enum.map(my_list, ...)
.|>
exists mostly to make "chaining" possible. It takes the result of the previous expression, and passes it as the first argument of the next function call. The code runs the same, but it reads more like a pipeline of sequential operations than one giant messy one-liner.One thing I really like about this approach is that, in referencing the module for each function call—e.g.
String.*
,Enum.*
,MapSet.*
—you can sort of annotate what type you're working with at each step. In a longer pipeline, it's often very easy to see the type transformations that are happening; something that you don't get with chained method calls in other languages.Google Sheets
Not the prettiest thing, but it works.
both parts
This does both parts.. I'm still new to SCAN, though. :)
Ruby
Part 1
Part 2
I felt like this one was especially easy, but maybe that's just me.
Part1 & Part2
Rust
Today was much easier than I expected :)
nim (both parts)
Today's was nice and easy.
Solution - Parts 1 and 2 - JavaScript
today was nice and easy. Had to find rusts window() function, though.
Driver
Utilities
Part 1
Part 2
Quick and dirty because I am quite late.
Part 1
Part 2
I'm using Rust this year, and trying to keep it
std
-only throughout the month.Part 1
Part 2
Both of today's parts in bash.
Part 1+2
There's probably a more elegant way than deleting matching letters from a stream of 4 characters then checking that 3 are still left to determine uniqueness.Well after yesterday saying that I had never done regular expressions in Python I saw a text matching challenge and tried it and then figured out that this is not, in fact, the sort of task that regular expressions make easy. I ended up doing this a little differently than the other Python solutions I see so far today, not using either queues or sets, but getting to test drive
for else
syntax, which was neat. I also did it kind of a clunky, single use way for part one, and then wrote part 2 generally so I could replace my part 1 function, though I left it for posterity. I do think my solution has a useful benefit, in that if it finds, say that the last two characters in a long search window are the same, it will skip forward such that the window starts with what was previously the last character, since we know that all windows that include those two characters at the end will not be what we are looking for.Parts 1 and 2, Python
Here's my TypeScript solution. Seconding what others have said that today's was refreshingly easy.
Parts 1 and 2
Edit: Renamed a variable that still had a name specific to part 1 even though it was used for both parts.