diff --git a/index.ts b/index.ts index 3bd2ad1..1994fcb 100644 --- a/index.ts +++ b/index.ts @@ -1,3 +1,3 @@ -import { runDayThree } from "./src/day_three"; +import {runDayFour} from "./src/day_four"; -runDayThree(); \ No newline at end of file +runDayFour(); \ No newline at end of file diff --git a/src/day_four.test.ts b/src/day_four.test.ts new file mode 100644 index 0000000..71f7cce --- /dev/null +++ b/src/day_four.test.ts @@ -0,0 +1,41 @@ +import {Scratchcard, ScratchcardSet} from "./day_four"; + +describe('Day 4', () => { + const inputs: [string, number][] = [ + ['Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53', 8], + ['Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19', 2], + ['Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1', 2], + ['Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83', 1], + ['Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36', 0], + ['Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11', 0] + ]; + + it.each(inputs)('should score %s with %d', (input, expectedScore) => { + const scratchcard = new Scratchcard(input); + expect(scratchcard.score).toEqual(expectedScore); + }); + + it.each(inputs.map(([input, score]) => [input, score !== 0]))('should return whether %s is a winner', (input, winner) => { + const scratchcard = new Scratchcard(input); + + expect(scratchcard.isWinner).toEqual(winner); + }); + + it('should report the correct scratchcard size', () => { + const scratchcard = new Scratchcard(inputs[0][0]); + const children = inputs.slice(1, 5).map(([input]) => new Scratchcard(input)); + + scratchcard.setChildren(children); + expect(scratchcard.size).toEqual(5); + }); + + it('should calculate the total score', () => { + const scratchcards = new ScratchcardSet(inputs.map(([input]) => input)); + expect(scratchcards.totalScore).toEqual(13); + }); + + it('should calculate the total number of scratchcards', () => { + const scratchcards = new ScratchcardSet(inputs.map(([input]) => input)); + expect(scratchcards.length).toEqual(30); + }); +}); \ No newline at end of file diff --git a/src/day_four.ts b/src/day_four.ts new file mode 100644 index 0000000..f819e03 --- /dev/null +++ b/src/day_four.ts @@ -0,0 +1,76 @@ +import fs from "fs"; +import {Engine} from "./day_three"; +import {forEach} from "lodash"; + +export class Scratchcard { + private readonly numbers: number[]; + private readonly winningNumbers: number[]; + private children: Scratchcard[] = []; + + constructor(input: string) { + const [_, withoutId] = input.split(':'); + const [winning, ourNumbers] = withoutId.split('|'); + + this.winningNumbers = this.parseNumberList(winning); + this.numbers = this.parseNumberList(ourNumbers); + } + + 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; + if (matches.length === 1) return 1; + + return Math.pow(2, Math.max(matches.length - 1, 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); +} \ No newline at end of file