Advent of Code 2023: Day Four
Published:
Read the previous Advent of Code posts, or checkout the Git repository.
Day Four was much easier than Day Three, and I’m actually quite pleased with my solution.
Part One
Given a list of “scratchcards” that look like Card ID: list of winning numbers | list of scratched numbers
, calculate the score, where the score is 1 if there is 1 match, and then doubles for each subsequent match afterwards.
I realised that is basically just exponents of 2 - 2^0, 2^1
etc. So, I parse each scratchcard into an object, and then to calculate the score I do:
get matches() {
return this.numbers.filter(number => this.winningNumbers.includes(number));
}
get score() {
if (!this.matches.length) return 0;
return Math.pow(2, this.matches.length - 1);
}
And then just do Array.prototype.reduce
over my list of scratchcards to get the total score. Pretty tidy, I’m happy with it.
Part Two
Now the scoring changes. If a scratchcard is a winner, instead of just having a score, it takes the next n
scratchcards from the list, where n
is the number of winning numbers matched. If one of the “copied” scratchcards later gets children, that also has to be reflected in the earlier copies (basically, we need to maintain references).
I just made each scratchcard a tree, essentially, with an empty array of children scratchcards, and then pulled references from my Scratchcard list using Array.prototype.slice
. I then recursively calculated the total size of my scratchcard set, where each scratchcard implements a size
getter, which returns 1 + sum of children sizes
.
class Scratchcard {
...
public setChildren(children: Scratchcard[]) {
this.children = children;
}
get size(): number {
return 1 + this.children.reduce((totalSize, child) => totalSize + child.size, 0);
}
}
export class ScratchcardSet {
private readonly scratchcards: Scratchcard[];
constructor(inputs: string[]) {
this.scratchcards = inputs.map(input => new Scratchcard(input));
this.scratchcards.forEach((scratchcard, index) => {
if (scratchcard.isWinner) {
const children = this.scratchcards.slice(index + 1, index + 1 + scratchcard.matches.length);
scratchcard.setChildren(children);
}
});
}
get totalScore() {
return this.scratchcards.reduce((total, scratchcard) => total + scratchcard.score, 0);
}
get length() {
return this.scratchcards.reduce((totalSize, scratchcard) => totalSize + scratchcard.size, 0);
}
}
And that’s Day Four complete!