Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

📝 Advent of PBT, Day 23 #5553

Merged
merged 3 commits into from
Dec 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions website/blog/2024-12-23-advent-of-pbt-day-23/AdventOfTheDay.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import adventBuggy from './buggy.mjs';
import { buildAdventOfTheDay } from '../2024-12-01-advent-of-pbt-day-1/AdventOfTheDayBuilder';

const { AdventPlaygroundOfTheDay, FormOfTheDay } = buildAdventOfTheDay({
day: 23,
buildBuggyAdvent: adventBuggy,
referenceAdvent: () => true,
buggyAdventSurcharged: (...args: Parameters<ReturnType<typeof adventBuggy>>) => {
const expected = payslipContentFor(...args);
const out = adventBuggy()(...args);
const [availableCoins, amountToBePaid] = args;
if (out === null) {
return expected === null ? true : 'not supposed to find anything';
}
if (out.reduce((acc, v) => acc + v, 0) !== amountToBePaid) {
return 'bad amount';
}
const coins = [...availableCoins];
for (const coinValue of out) {
const index = coins.indexOf(coinValue);
if (index === -1) {
return 'no such coin';
}
coins.splice(index, 1);
}
return true;
},
parser,
placeholderForm: '7?\n1,1,2,5,10',
functionName: 'payslipContentFor',
signature: 'payslipContentFor(availableCoins: Coin[], amountToBePaid: number): Coin[] | null;',
signatureExtras: ['type Coin = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10;'],
});

export { AdventPlaygroundOfTheDay, FormOfTheDay };

// Reference implementation

function payslipContentFor(availableCoins, amountToBePaid) {
const coins = [...availableCoins].sort((a, b) => b - a);
function helper(target, index) {
if (target === 0) {
return [];
}
if (target < 0 || index >= coins.length) {
return null;
}
const withCurrent = helper(target - coins[index], index + 1);
if (withCurrent !== null) {
return [coins[index], ...withCurrent];
}
return helper(target, index + 1);
}
return helper(amountToBePaid, 0);
}

// Inputs parser

function parser(answer: string): unknown[] | undefined {
const lines = answer.split('\n');
if (lines.length !== 2) {
throw new Error('Expected to receive two lines one for the amount to be paid, another one for the coins');
}
if (lines[0].at(-1) !== '?') {
throw new Error(`First line must end by ?, got: ${lines[0]}.`);
}
const amount = Number(lines[0].slice(0, -1));
if (!Number.isInteger(amount) || amount < 0 || amount > 2 ** 31 - 1) {
throw new Error(`Invalid amount received, must be a positive integer value below 2**31-1, got: ${lines[0]}.`);
}
const coins: number[] =
lines[1] === ''
? []
: lines[1].split(',').map((v) => {
const n = Number(v);
if (!Number.isInteger(n) || n < 1 || n > 10) {
throw new Error(`Invalid coin value received, got: ${v}.`);
}
return n;
});
return [coins, amount];
}
35 changes: 35 additions & 0 deletions website/blog/2024-12-23-advent-of-pbt-day-23/buggy.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// @ts-check

export default function advent() {
/** @typedef {1|2|3|4|5|6|7|8|9|10} Coin */

/**
* @param {Coin[]} availableCoins
* @param {number} amountToBePaid
* @returns {Coin[] | null}
*/
return function payslipContentFor(availableCoins, amountToBePaid) {
const coins = [...availableCoins].sort((a, b) => b - a);
const memo = Array.from({ length: coins.length }, () => undefined);
function helper(target, index) {
if (target === 0) {
return [];
}
if (target < 0 || index >= coins.length) {
return null;
}
if (memo[index] !== undefined) {
return memo[index];
}
const withCurrent = helper(target - coins[index], index + 1);
if (withCurrent !== null) {
memo[index] = [coins[index], ...withCurrent];
return [coins[index], ...withCurrent];
}
const withoutCurrent = helper(target, index + 1);
memo[index] = withoutCurrent;
return withoutCurrent;
}
return helper(amountToBePaid, 0);
};
}
51 changes: 51 additions & 0 deletions website/blog/2024-12-23-advent-of-pbt-day-23/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
title: Advent of PBT 2024 · Day 23
authors: [dubzzz]
tags: [advent-of-pbt, advent-of-pbt-2024]
image: ./social.png
---

import {AdventPlaygroundOfTheDay,FormOfTheDay} from './AdventOfTheDay';
import BlueskyComments from '../2024-12-01-advent-of-pbt-day-1/BlueskyComments';

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. This time, it’s not Santa but Emma who needs your help: she suspects her coin-payment algorithm might have bugs. Can you uncover any issues and ensure every elf gets paid on time for years to come? 🎄✨

<!--truncate-->

## Money day

In Santa's world, money works just like in ours. At the end of each month, elves and other inhabitants receive a payslip reflecting their contributions. However, Santa has a habit of delaying payments in December, claiming he needs to withdraw coins since he only pays in cash.

Last year’s drama prompted Emma, one of the elves, to take action. She designed an algorithm to ensure smooth payouts. Her algorithm works like this:

- **Input:** A list of coins Santa has in hand and the exact amount he needs to pay a given elf.
- **Output:** Either an array containing the values of the coins that sum up to the exact amount or `null` if it’s impossible to make the payment.

For example:

- If Santa has coins `[1, 1, 2, 5, 10]` and needs to pay `7`, the algorithm might return `[2, 5]`.
- If Santa has coins `[3, 4, 5]` and needs to pay `2`, it would return `null`.

## Hands on

This time, it’s not Santa calling you — it’s Emma. She’s concerned her algorithm might contain errors. If the payouts are delayed again this year, it could damage elf morale and break their motivation for next year.

Emma shared one important detail before leaving you to test her algorithm: in Santa’s world, the coins available are always `[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]`.

Your mission: Use property-based testing to check Emma’s algorithm for bugs and ensure it works flawlessly.

You’ve already saved Christmas this year; now it’s time to ensure smooth payouts for years to come! 🎄✨

<AdventPlaygroundOfTheDay />

## Your answer

<FormOfTheDay />

## Comments

<BlueskyComments url="" />
3 changes: 3 additions & 0 deletions website/blog/2024-12-23-advent-of-pbt-day-23/social.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading