[TASK] Implemented Day4

This commit is contained in:
2021-12-05 12:21:31 +01:00
parent 8b3963fa6a
commit f1192091eb
6 changed files with 783 additions and 5 deletions

View File

@@ -0,0 +1,17 @@
import Day from "./day";
class DayX implements Day {
part1(input: string[]): number | string {
// TODO implement
return 0;
}
part2(input: string[]): number | string {
// TODO implement
return 0;
}
}
export default DayX;

View File

@@ -1,7 +1,7 @@
interface Day {
part1(input: string[]): number;
part2(input: string[]): number;
part1(input: string[]): number | string;
part2(input: string[]): number | string;
}
export default Day;

129
functions/src/day4.ts Normal file
View File

@@ -0,0 +1,129 @@
import Day from "./day";
import Utils from "./utils";
class Day4 implements Day {
part1(input: string[]): number | string {
const { drawnNumbers, bingoCards } = this.parseInput(input);
// We are done as soon as we encounter the first bingo
return this.playBingo(drawnNumbers, bingoCards, b => ({ isDone: true }) ).score;
}
part2(input: string[]): number | string {
const { drawnNumbers, bingoCards } = this.parseInput(input);
// We are done when the first bingo is encountered before every card has had a bingo:
const bingo = this.playBingo(drawnNumbers, bingoCards, (b, bc, bcs) => ({ isDone: b.firstBingo && bcs.every(bc => bc.hadBingo) }));
return bingo.score;
}
playBingo(drawnNumbers: number[], bingoCards: BingoCard[], bingoHandler: (b: Bingo, bingoCard: BingoCard, allCards: BingoCard[]) => { isDone: boolean }): Bingo {
for (const draw of drawnNumbers) {
for (let bingoCard of bingoCards) {
const cardResult = bingoCard.cross(draw);
if (cardResult instanceof Bingo) {
const handleResult = bingoHandler(cardResult, bingoCard, bingoCards);
if (handleResult.isDone) return cardResult;
}
}
}
throw Error("We were never done...");
}
parseInput(input: string[]): { drawnNumbers: number[], bingoCards: BingoCard[] } {
const drawnNumbers = input[0].split(",").map(s => parseInt(s));
const bingoCards = [];
let currentCardNumbers: number[] = [];
let currentCardWidth = 0;
for (let i = 1; i < input.length; i++) {
// Empty line indicates a new bingo card
const line = input[i];
if (line === "") {
if (currentCardNumbers.length > 0) {
bingoCards.push(new BingoCard(currentCardNumbers, currentCardWidth));
}
currentCardNumbers = [];
currentCardWidth = 0;
} else {
const cardLine = line.split(/\s+/).filter(s => s != "").map(s => parseInt(s));
currentCardNumbers.push(...cardLine);
currentCardWidth = cardLine.length;
}
}
if (currentCardNumbers.length > 0) {
bingoCards.push(new BingoCard(currentCardNumbers, currentCardWidth));
}
return { drawnNumbers, bingoCards }
}
}
class BingoCard {
readonly numbers: number[];
readonly width: number;
crossed: boolean[];
hadBingo = false;
constructor(numbers: number[], width: number) {
this.numbers = numbers;
this.width = width;
this.crossed = new Array(numbers.length).fill(false);
}
/**
* Cross the given numbers of the bingo card. Returns Bingo if this card scored a bingo!
* @param nr
*/
cross(nr: number): null | Bingo {
const nrIndex = this.numbers.indexOf(nr);
if (nrIndex === -1) return null;
this.crossed[nrIndex] = true;
// Check for bingo
const rowStart = Math.floor(nrIndex / this.width) * this.width;
const rowComplete = this.crossed.slice(rowStart, rowStart + this.width).every(c => c);
const colStart = nrIndex % this.width;
const colComplete = this.crossed.filter((v, i) => i % this.width === colStart).every(c => c);
if (rowComplete || colComplete) {
const firstBingo = !this.hadBingo;
this.hadBingo = true;
return new Bingo(Utils.sum(this.numbers.filter((n, i) => !this.crossed[i])) * nr, nr, firstBingo);
} else {
return null;
}
}
}
class Bingo {
readonly score: number;
readonly winningNr: number;
readonly firstBingo: boolean;
constructor(score: number, winningNr: number, firstBingo: boolean) {
this.score = score;
this.winningNr = winningNr;
this.firstBingo = firstBingo;
}
}
export default Day4;

View File

@@ -1,10 +1,11 @@
import * as functions from "firebase-functions";
import Utils from "./utils";
import Day1 from "./day1";
import {Request, Response} from "firebase-functions";
import Utils from "./utils";
import Day from "./day";
import Day1 from "./day1";
import Day2 from "./day2";
import Day3 from "./day3";
import Day from "./day";
import Day4 from "./day4";
// // Start writing Firebase Functions
@@ -24,6 +25,7 @@ export const day = {
1: functions.region("europe-west1").https.onRequest((request, response) => { processDay(new Day1(), request, response) }),
2: functions.region("europe-west1").https.onRequest((request, response) => { processDay(new Day2(), request, response) }),
3: functions.region("europe-west1").https.onRequest((request, response) => { processDay(new Day3(), request, response) }),
4: functions.region("europe-west1").https.onRequest((request, response) => { processDay(new Day4(), request, response) }),
}