---
title: "Advent of Code 2023: Day Four"
date: 2023-12-04T08:24:54
slug: advent-of-code-2023-day-four
tags: [advent-of-code-2023]
---
Read the [previous Advent of Code posts](https://lewisdale.dev/post/tag/advent-of-code-2023), or checkout the [Git repository](https://git.lewisdale.dev/lewis/advent-of-code-2023).

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:

```javascript
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`.

```javascript
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!
