Skip to content

Commit

Permalink
📝 Advent Of PBT Day 12 (#5507)
Browse files Browse the repository at this point in the history
  • Loading branch information
dubzzz authored Dec 12, 2024
1 parent d786ec6 commit 414b491
Show file tree
Hide file tree
Showing 3 changed files with 208 additions and 0 deletions.
105 changes: 105 additions & 0 deletions website/blog/2024-12-12-advent-of-pbt-day-12/AdventOfTheDay.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import adventBuggy from './buggy.mjs';
import { buildAdventOfTheDay } from '../2024-12-01-advent-of-pbt-day-1/AdventOfTheDayBuilder';

const { AdventPlaygroundOfTheDay, FormOfTheDay } = buildAdventOfTheDay({
day: 12,
buildBuggyAdvent: adventBuggy,
referenceAdvent: planFastTravel,
postAdvent: (route: Track[] | undefined) =>
route !== undefined ? route.reduce((acc, track) => acc + track.distance, 0) : undefined,
parser,
placeholderForm: 'a>b=6\nb>c=8\nc>b=6\na>c?',
functionName: 'planFastTravel',
signature: 'planFastTravel(departure: string, destination: string, tracks: Track[]): Track[] | undefined;',
signatureExtras: ['type Track = { from: string; to: string; distance: number };'],
});

export { AdventPlaygroundOfTheDay, FormOfTheDay };

// Reference implementation

type Track = { from: string; to: string; distance: number };

function planFastTravel(departure: string, destination: string, tracks: Track[]): Track[] | undefined {
const distanceToNode = new Map<string, { distance: number; edges: Track[] }>(
[departure, destination, ...tracks.map((t) => t.from), ...tracks.map((t) => t.to)].map((node) => [
node,
{ distance: Number.POSITIVE_INFINITY, edges: [] },
]),
);
if (distanceToNode.has(departure)) {
distanceToNode.set(departure, { distance: 0, edges: [] });
}
while (true) {
const nextNode = findRemainingNodeWithMinimalDistance(distanceToNode);
if (nextNode === undefined) {
return undefined; // no path found
}
const data = distanceToNode.get(nextNode)!;
if (nextNode === destination) {
return data.edges;
}
distanceToNode.delete(nextNode);
for (const e of tracks) {
if (
e.from === nextNode &&
distanceToNode.has(e.to) &&
distanceToNode.get(e.to)!.distance > data.distance + e.distance
) {
distanceToNode.set(e.to, {
distance: data.distance + e.distance,
edges: [...data.edges, e],
});
}
}
}
}

function findRemainingNodeWithMinimalDistance(
distanceToNode: Map<string, { distance: number; edges: Track[] }>,
): string | undefined {
let minNode: string | undefined = undefined;
let minDistance = Number.POSITIVE_INFINITY;
for (const [node, { distance }] of distanceToNode) {
if (distance < minDistance) {
minNode = node;
minDistance = distance;
}
}
return minNode;
}

// Inputs parser

const routeRegex = /^([a-z])>([a-z])=(\d+)$/;
const queryRegex = /^([a-z])>([a-z])\?$/;

function parser(answer: string): unknown[] | undefined {
const lines = answer.trim().split('\n');
if (lines.length < 1) {
throw new Error(`Your answer should be made of at least one line`);
}
const tracks: Track[] = [];
for (let i = 0; i < lines.length - 1; ++i) {
const m = routeRegex.exec(lines[i]);
if (m === null) {
throw new Error(
`All lines except the last one should declare edges of the form: a>b=distance. Received: ${lines[i]}.`,
);
}
const distance = Number(m[3]);
if (distance <= 0 || distance > 2 ** 31 - 1 || Number.isNaN(distance) || !Number.isInteger(distance)) {
throw new Error(
`All lines except the last one should declare edges with distance in [1, 2**31-1]. Received: ${lines[i]}.`,
);
}
tracks.push({ from: m[1], to: m[2], distance });
}
const m = queryRegex.exec(lines[lines.length - 1]);
if (m === null) {
throw new Error(
`The last line must be a query for a route of the form: a>b?. Received: ${lines[lines.length - 1]}.`,
);
}
return [m[1], m[2], tracks];
}
51 changes: 51 additions & 0 deletions website/blog/2024-12-12-advent-of-pbt-day-12/buggy.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// @ts-check

export default function advent() {
/** @typedef {{ from: string; to: string; distance: number }} Track */

/**
* @param {string} departure
* @param {string} destination
* @param {Track[]} tracks
* @returns {Track[]|undefined}
*/
return function planFastTravel(departure, destination, tracks) {
const distanceToNode = Object.fromEntries(
[departure, destination, ...tracks.map((t) => t.from), ...tracks.map((t) => t.to)].map((node) => [
node,
{ distance: Number.POSITIVE_INFINITY, edges: [] },
]),
);
if (distanceToNode[departure]) {
distanceToNode[departure] = { distance: 0, edges: [] };
}
while (true) {
const nextNode = findRemainingNodeWithMinimalDistance(distanceToNode);
if (nextNode === undefined) {
return undefined; // no path found
}
const data = distanceToNode[nextNode];
if (nextNode === destination) {
return data.edges;
}
delete distanceToNode[nextNode];
for (const e of tracks) {
if (e.from === nextNode && distanceToNode[e.to]) {
distanceToNode[e.to] = { distance: data.distance + e.distance, edges: [...data.edges, e] };
}
}
}
};

function findRemainingNodeWithMinimalDistance(distanceToNode) {
let minNode = undefined;
let minDistance = Number.POSITIVE_INFINITY;
for (const [node, { distance }] of Object.entries(distanceToNode)) {
if (distance < minDistance) {
minNode = node;
minDistance = distance;
}
}
return minNode;
}
}
52 changes: 52 additions & 0 deletions website/blog/2024-12-12-advent-of-pbt-day-12/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
title: Advent of PBT 2024 · Day 12
authors: [dubzzz]
tags: [advent-of-pbt, advent-of-pbt-2024]
---

import {AdventPlaygroundOfTheDay,FormOfTheDay} from './AdventOfTheDay';

Christmas is at risk! In their rush to meet tight deadlines, Santa’s elves accidentally introduced bugs into critical algorithms. If these issues aren’t discovered in time, Christmas could be delayed for everyone worldwide!

Your mission is to troubleshoot these black-box algorithms using the power of fast-check.

The clock is ticking. Santa just pinged you with your next challenge: the elves’ newly released routing system for the sleigh might have issues. Can you uncover potential flaws and ensure Santa reaches his destination in record time? 🎄✨

<!--truncate-->

## Fast Travel Planner

_"Tomorrow is the big day!"_ Santa announces with excitement.

_"What big day?"_ you wonder, slightly puzzled.

It turns out Santa has been eagerly awaiting React Day Berlin! A fan of cutting-edge dev techniques and knowledge sharing, he’s been counting down to this conference since last year. It’s his ideal last-minute break to explore the latest React trends before the Christmas rush.

This morning, Santa’s elves proudly unveiled the latest iteration of the sleigh’s routing system — a sophisticated algorithm designed to calculate the fastest route for delivering gifts to children worldwide. But Santa has another plan: to test the system before Christmas during his trip to the conference.

The algorithm operates on a list of all known routes in Santa’s network, with each route defined as a directed edge::

- `from`: The starting point of the route, represented as a string consisting of a single lowercase letter (`a` to `z`).
- `to`: The destination of the route, represented as a string consisting of a single lowercase letter (`a` to `z`).
- `distance`: The time it takes to travel, expressed as a strictly positive integer being less than `2**31-1`.

Given a starting location and a desired destination, the algorithm either:

- Returns the routes to take for the fastest journey, or
- Indicates that no path exists to the destination.

## Hands on

There’s just one problem. While the algorithm was released this morning, it’s still in its testing phase. Santa, however, insists on using it now and absolutely cannot be late for React Day Berlin.

That’s where you come in!

Your mission: rigorously test the sleigh’s routing algorithm to ensure it finds the most efficient path from start to destination.

Christmas — and Santa’s conference dreams — are counting on you! Don’t let him down. 🎄✨

<AdventPlaygroundOfTheDay />

## Your answer

<FormOfTheDay />

0 comments on commit 414b491

Please sign in to comment.