2023-12-04 08:12:05 +00:00
|
|
|
import fs from "fs";
|
2023-12-04 21:54:46 +00:00
|
|
|
import {whitespace, int, string} from "parjs";
|
|
|
|
import {between, manySepBy, then} from "parjs/combinators";
|
|
|
|
|
|
|
|
const cardIdParser = int()
|
|
|
|
.pipe(between(whitespace()))
|
|
|
|
.pipe(between(string('Card'), string(': ')));
|
|
|
|
|
|
|
|
const numbersParser = int()
|
|
|
|
.pipe(between(whitespace()))
|
|
|
|
.pipe(manySepBy(whitespace()));
|
|
|
|
|
|
|
|
const winningNumberParser = numbersParser
|
|
|
|
.pipe(between(cardIdParser, string('|')))
|
|
|
|
.pipe(then(numbersParser));
|
2023-12-04 08:12:05 +00:00
|
|
|
|
|
|
|
export class Scratchcard {
|
|
|
|
private readonly numbers: number[];
|
|
|
|
private readonly winningNumbers: number[];
|
|
|
|
private children: Scratchcard[] = [];
|
|
|
|
|
|
|
|
constructor(input: string) {
|
2023-12-04 21:54:46 +00:00
|
|
|
const [
|
|
|
|
winningNumbers,
|
|
|
|
numbers
|
|
|
|
] = winningNumberParser.parse(input).value;
|
2023-12-04 08:12:05 +00:00
|
|
|
|
2023-12-04 21:54:46 +00:00
|
|
|
this.winningNumbers = winningNumbers;
|
|
|
|
this.numbers = numbers;
|
2023-12-04 08:12:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private parseNumberList(input: string): number[] {
|
|
|
|
return [...input.matchAll(/\d+/g)].map(match => parseInt(match[0], 10));
|
|
|
|
}
|
|
|
|
|
|
|
|
public get matches() {
|
|
|
|
return this.numbers.filter(number => this.winningNumbers.includes(number));
|
|
|
|
}
|
|
|
|
|
|
|
|
get score() {
|
|
|
|
const matches = this.matches;
|
|
|
|
if (!matches.length) return 0;
|
|
|
|
|
2023-12-04 08:17:01 +00:00
|
|
|
return Math.pow(2, matches.length - 1);
|
2023-12-04 08:12:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
get isWinner() {
|
|
|
|
return Boolean(this.matches.length);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export const runDayFour = () => {
|
|
|
|
const input = fs.readFileSync('./inputs/day_four_input.txt', 'utf8').split('\n').filter(Boolean);
|
|
|
|
const scratchCards = new ScratchcardSet(input);
|
|
|
|
|
|
|
|
console.log(scratchCards.totalScore);
|
|
|
|
console.log(scratchCards.length);
|
|
|
|
}
|