|
@@ -0,0 +1,89 @@
|
|
|
+import { ExtractNumbers, LoadInput } from "../common.ts";
|
|
|
+
|
|
|
+const tests = [
|
|
|
+ "Time: 7 15 30",
|
|
|
+ "Distance: 9 40 200",
|
|
|
+];
|
|
|
+
|
|
|
+const input = await LoadInput(6);
|
|
|
+
|
|
|
+const races = ParseRaces(input);
|
|
|
+
|
|
|
+races.forEach((race) => FindWinningTimes(race));
|
|
|
+
|
|
|
+// Get our output as a "checksum"
|
|
|
+// The checksum is the number of ways each race could be won multiplied by each other
|
|
|
+console.log("The race checksum is", races.reduce((accumulator, race) => accumulator *= race.WinningTimes.length, 1));
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * Parse the input to get a list of races
|
|
|
+ *
|
|
|
+ * @param {string[]} inputLines The two lines of input
|
|
|
+ * @returns {Race[]} A list of race details
|
|
|
+ */
|
|
|
+function ParseRaces(inputLines: string[]): Race[] {
|
|
|
+ const races: Race[] = [];
|
|
|
+
|
|
|
+ const times = ExtractNumbers(inputLines.shift() || "");
|
|
|
+ const distances = ExtractNumbers(inputLines.shift() || "");
|
|
|
+
|
|
|
+ do {
|
|
|
+ races.push({
|
|
|
+ Duration: times.shift() || -1,
|
|
|
+ RecordDistance: distances.shift() || -1,
|
|
|
+ WinningTimes: [],
|
|
|
+ });
|
|
|
+ } while (times.length);
|
|
|
+
|
|
|
+ return races;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Find all possible winning times for a given race
|
|
|
+ *
|
|
|
+ * @param {Race} race The race to find winning times for
|
|
|
+ */
|
|
|
+function FindWinningTimes(race: Race) {
|
|
|
+ // For our sake, flip the sign on the RecordDistance to create a floor for the parabola
|
|
|
+ let [lowerBounds, upperBounds] = FindQuadraticRoots(-1, race.Duration, (race.RecordDistance * -1));
|
|
|
+
|
|
|
+ // Exclusively bind the two bounds to integers
|
|
|
+ // Add/subtract 0.01 to force integer roots to their next whole number
|
|
|
+ lowerBounds = Math.ceil(lowerBounds + 0.01);
|
|
|
+ upperBounds = Math.floor(upperBounds - 0.01);
|
|
|
+
|
|
|
+ for(let i = lowerBounds; i <= upperBounds; i++) { race.WinningTimes.push(i); }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Find the quadratic roots of a parabola
|
|
|
+ *
|
|
|
+ * @param a
|
|
|
+ * @param b
|
|
|
+ * @param c
|
|
|
+ * @returns The quadratic roots of a parabola
|
|
|
+ */
|
|
|
+function FindQuadraticRoots(a: number, b: number, c: number): number[] {
|
|
|
+ if (a == 0) { return []; }
|
|
|
+
|
|
|
+ // Solve for the discriminant -- sqrt(b^2 - 4ac)
|
|
|
+ const discriminant = Math.sqrt(Math.pow(b, 2) - (4 * a * c));
|
|
|
+
|
|
|
+ return [
|
|
|
+ ((b * -1) + discriminant) / (2 * a),
|
|
|
+ ((b * -1) - discriminant) / (2 * a),
|
|
|
+ ];
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Information regarding a boat race
|
|
|
+ */
|
|
|
+type Race = {
|
|
|
+ /** The total duration of the race in milliseconds */
|
|
|
+ Duration: number,
|
|
|
+ /** The current record holder for boat distance */
|
|
|
+ RecordDistance: number,
|
|
|
+ /** A list of times the boat's button could be held that would beat the RecordDistance */
|
|
|
+ WinningTimes: number[]
|
|
|
+};
|