r/adventofcode • u/musifter • 5h ago
Other [2023 Day 4] In Review (Scratchcards)
The gondola arrives at Island Island... and island with islands, so there's plenty of water, but apparently no immediate water source. An Elf at the station directs us to ask the gardener about it, who's on another island. They'll let us borrow a boat to get there, if we help them figure out their winnings on a big stack of scratchcards.
And so the input is a big list of cards (mine has 220). The number of each card (1-220) is part of the input, but again, they're sorted and so you can ignore that if you want. The card is divided into two sections with a |... the winning numbers and the numbers to compare against them. These numbers are from 1-99 (the absence of 0 is useful again). The number of numbers in each section are regular... 10 winning, 25 have. That can be used, but the test case has different sizes (5 and 8), so I just ignored that. These are proper cards... there isn't a card with two of the same winning number or two of the same "having" number. All the better for throwing things into two hashes/sets/bit arrays.
Part 1 is just a simple counting of winning numbers, but you score them with the power of 2 of that. So you can bitshift, but 1 << 0 is 1, but 2-1 is 0.5, which truncates to 0 as an integer (and so you can avoid a special case). This was especially useful for my dc solution for this:
sed -e's/|/0/;s/[^0-9 ]//g' <input | dc -e'0?[0Sh[1r:hd0<L]dsLx[r;h+z3<L]dsLxrs.1-2r^+?z1<M]dsMxp'
The input is mostly numbers, and I convert the | to the unused 0, which can then be used as the accumulator for counting wins. This is using ? to separate the lines by reading them one at a time, and so is a v1.4.1 solution.
Part 2, complicates things by having cards win copies of the next n cards. And just from the description, there's an immediate feel that this is describing a dynamic programming tabulation (there's an order to the cards, where previous ones are used to calculate the later). Of course, you can also do the same work with a recursive memoized function. And I did solutions both ways. My Smalltalk tabulation (you can also use a Bag for this):
cards := Array new: cardWins size withAll: 1.
cards keysAndValuesDo: [ :card :num |
(card + 1 to: card + (cardWins at: card)) do: [:i | cards at: i inc: num].
].
So there is a bit of advance concepts for day 4 behind this one. But the problem is linear and small. You can easily brute for the number of wins on card with loops... and removing the memoization in part 2 still results in a things only taking a couple seconds. And I think that helped this one be considered a "good dog" compared to it's neighbours.