[TASK] Implemented Day4
This commit is contained in:
17
functions/src/day-template.ts
Normal file
17
functions/src/day-template.ts
Normal 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;
|
||||
@@ -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
129
functions/src/day4.ts
Normal 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;
|
||||
@@ -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) }),
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user