Day Four

This commit is contained in:
Lewis Dale 2023-12-04 08:12:05 +00:00
parent a29299ede8
commit dcff332499
3 changed files with 119 additions and 2 deletions

View File

@ -1,3 +1,3 @@
import { runDayThree } from "./src/day_three";
import {runDayFour} from "./src/day_four";
runDayThree();
runDayFour();

41
src/day_four.test.ts Normal file
View File

@ -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);
});
});

76
src/day_four.ts Normal file
View File

@ -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);
}