-
-
Notifications
You must be signed in to change notification settings - Fork 186
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
184 additions
and
0 deletions.
There are no files selected for viewing
91 changes: 91 additions & 0 deletions
91
website/blog/2024-12-04-advent-of-pbt-day-4/AdventOfTheDay.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import adventBuggy from './buggy.mjs'; | ||
import { buildAdventOfTheDay } from '../2024-12-01-advent-of-pbt-day-1/AdventOfTheDayBuilder'; | ||
|
||
const { AdventPlaygroundOfTheDay, FormOfTheDay } = buildAdventOfTheDay({ | ||
day: 4, | ||
buildBuggyAdvent: adventBuggy, | ||
referenceAdvent: fastPostOfficeFinderEmulator, | ||
postAdvent: (value) => Number(value) >= 0 && Number(value) <= 14, | ||
parser, | ||
placeholderForm: 'initial:0,0\nbox:0,0', | ||
functionName: 'fastPostOfficeFinderEmulator', | ||
signature: 'function fastPostOfficeFinderEmulator(initialPosition: Position, targetPosition: Position): number;', | ||
signatureExtras: ['type Position = { x: number; y: number };'], | ||
}); | ||
|
||
export { AdventPlaygroundOfTheDay, FormOfTheDay }; | ||
|
||
// Reference implementation | ||
|
||
const SizeX = 10000; | ||
const SizeY = 1000; | ||
|
||
type Position = { x: number; y: number }; | ||
|
||
function fastPostOfficeFinderEmulator(initialPosition: Position, targetPosition: Position): number { | ||
let xMin = 0; | ||
let xMax = SizeX; | ||
let yMin = 0; | ||
let yMax = SizeY; | ||
let x = initialPosition.x; | ||
let y = initialPosition.y; | ||
let numMoves = 0; | ||
while (x !== targetPosition.x || y !== targetPosition.y) { | ||
if (xMin >= xMax || yMin >= yMax) { | ||
return Number.POSITIVE_INFINITY; // error | ||
} | ||
const prevX = x; | ||
const prevY = y; | ||
if (targetPosition.y < y) { | ||
yMax = y; | ||
y = Math.floor((yMax + yMin) / 2); | ||
} else if (targetPosition.y > y) { | ||
yMin = y + 1; | ||
y = Math.floor((yMax + yMin) / 2); | ||
} | ||
if (targetPosition.x < x) { | ||
xMax = x; | ||
x = Math.floor((xMax + xMin) / 2); | ||
} else if (targetPosition.x > x) { | ||
xMin = x + 1; | ||
x = Math.floor((xMax + xMin) / 2); | ||
} | ||
if (prevX !== x || prevY !== y) { | ||
++numMoves; | ||
if (numMoves > 1000) { | ||
return Number.POSITIVE_INFINITY; // probably an error somewhere | ||
} | ||
} | ||
} | ||
return numMoves; | ||
} | ||
|
||
// Inputs parser | ||
|
||
const initialRegex = /^initial\s*:\s*(\d{1,4})\s*,\s*(\d{1,3})$/; | ||
const boxRegex = /^box\s*:\s*(\d{1,4})\s*,\s*(\d{1,3})$/; | ||
|
||
function parser(answer: string): unknown[] | undefined { | ||
const lines = answer.trim().split('\n'); | ||
if (lines.length !== 2) { | ||
throw new Error( | ||
`Your answer should be made of two distinct lines: the first line for the initial location, the second one for the box`, | ||
); | ||
} | ||
const mInit = initialRegex.exec(lines[0]); | ||
if (mInit === null) { | ||
throw new Error( | ||
'The initial location should be of the form: `initial:x,y` with x between 0 and 9999 and y between 0 and 999', | ||
); | ||
} | ||
const mBox = boxRegex.exec(lines[1]); | ||
if (mBox === null) { | ||
throw new Error( | ||
'The box location should be of the form: `box:x,y` with x between 0 and 9999 and y between 0 and 999', | ||
); | ||
} | ||
return [ | ||
{ x: Number(mInit[1]), y: Number(mInit[2]) }, | ||
{ x: Number(mBox[1]), y: Number(mBox[2]) }, | ||
]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// @ts-check | ||
|
||
export default function advent() { | ||
/** @typedef {{x: number; y: number;}} Position */ | ||
|
||
const SizeX = 10000; | ||
const SizeY = 1000; | ||
|
||
/** | ||
* @param {Position} initialPosition | ||
* @param {Position} targetPosition | ||
* @returns {number} Number of moves to find the targetPosition | ||
*/ | ||
return function fastPostOfficeFinderEmulator(initialPosition, targetPosition) { | ||
let xMin = 0; | ||
let xMax = SizeX; | ||
let yMin = 0; | ||
let yMax = SizeY; | ||
let x = initialPosition.x; | ||
let y = initialPosition.y; | ||
let numMoves = 0; | ||
while (x !== targetPosition.x || y !== targetPosition.y) { | ||
if (xMin >= xMax || yMin >= yMax) { | ||
return Number.POSITIVE_INFINITY; // error | ||
} | ||
const prevX = x; | ||
const prevY = y; | ||
if (targetPosition.y < y) { | ||
yMax = y - 1; | ||
y = Math.floor((yMax + yMin) / 2); | ||
} else if (targetPosition.y > y) { | ||
yMin = y + 1; | ||
y = Math.floor((yMax + yMin) / 2); | ||
} | ||
if (targetPosition.x < x) { | ||
xMax = x - 1; | ||
x = Math.floor((xMax + xMin) / 2); | ||
} else if (targetPosition.x > x) { | ||
xMin = x + 1; | ||
x = Math.floor((xMax + xMin) / 2); | ||
} | ||
if (prevX !== x || prevY !== y) { | ||
++numMoves; | ||
if (numMoves > 1000) { | ||
return Number.POSITIVE_INFINITY; // probably an error somewhere | ||
} | ||
} | ||
} | ||
return numMoves; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
--- | ||
title: Advent of PBT 2024 · Day 4 | ||
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: he’s struggling with a slow system for locating letters on his massive grid of post office boxes. The elves proposed a faster method, but Santa suspects it might not work as intended. Can you make sure their implementation is up to the task? 🎄🔧 | ||
|
||
<!--truncate--> | ||
|
||
## Post Office finder | ||
|
||
Each post office has a direct connection to Santa’s land. Whenever someone sends a letter to Santa, the post office forwards it to Santa’s massive wall of boxes. This wall is a 10,000 (width) by 1,000 (height) grid, where each box corresponds to a specific post office. When a letter arrives, the corresponding box starts beeping, and Santa has to locate and open it. | ||
|
||
Today, when a box starts beeping, Santa uses an elevator to move one box at a time across the massive grid to locate the source of the sound. Watching how painful and slow this process was, the elves stepped in with a suggestion to make it faster while keeping the elevator in place. | ||
|
||
Instead of moving box by box, they proposed that Santa use directional arrows — <kbd>←</kbd>, <kbd>→</kbd>, <kbd>↑</kbd>, <kbd>↓</kbd>, <kbd>↖</kbd>, <kbd>↗</kbd>, <kbd>↘</kbd>, <kbd>↙</kbd> — to tell the elevator where the sound is coming from. Based on this input, the elevator would immediately jump to a new location. If it lands directly on the correct box, the process ends. Otherwise, Santa repeats the process by providing another direction until the target is reached. | ||
|
||
## Hands on | ||
|
||
The elves claimed that their system can reduce the search from 10,000,000 moves to at most 14 moves (not one more). However, Santa isn’t fully convinced. He asked the elves to create an emulator that simulates the process. This emulator takes: | ||
|
||
- An initial position (x, y) where elevator starts. | ||
- The target box position (x, y) where the beep originates. | ||
|
||
The emulator outputs the number of moves required for the elevator to reach the beeping box. In simpler terms, the elves provided a function to compute the number of moves needed to navigate Santa’s 10,000 by 1,000 grid from one coordinate `{x, y}` to another. Santa now needs your help to test if this function works correctly—or if the elves made a mistake. | ||
|
||
Using the property-based testing features of fast-check, your task is to find a combination of initial position and box position that breaks the elves’ implementation. | ||
|
||
You are Santa’s last hope to ensure Christmas happens this year — don’t let him down! 🎄🔧 | ||
|
||
<AdventPlaygroundOfTheDay /> | ||
|
||
## Your answer | ||
|
||
<FormOfTheDay /> |