import fs from "fs"; 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)); export class Scratchcard { private readonly numbers: number[]; private readonly winningNumbers: number[]; private children: Scratchcard[] = []; constructor(input: string) { const [ winningNumbers, numbers ] = winningNumberParser.parse(input).value; this.winningNumbers = winningNumbers; this.numbers = numbers; } 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; return Math.pow(2, matches.length - 1); } 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); }