From 5f5dee3c713492edd443b20d70b3c0ad8ca79dde Mon Sep 17 00:00:00 2001 From: J R M Date: Wed, 18 Jun 2025 07:40:05 +0200 Subject: [PATCH 01/50] Create captains-log.js Stub for new Concept exercise --- .../concept/captains-log/captains-log.js | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 exercises/concept/captains-log/captains-log.js diff --git a/exercises/concept/captains-log/captains-log.js b/exercises/concept/captains-log/captains-log.js new file mode 100644 index 0000000000..e4baa0c16d --- /dev/null +++ b/exercises/concept/captains-log/captains-log.js @@ -0,0 +1,30 @@ +/// +// @ts-check + +/** + * Generates a random starship registry number. + * + * @returns {string} the generated registry number. + */ +export function randomShipRegistryNumber() { + throw new Error("Please remove this line and implement the randomShipRegistryNumber() function"); +} + +/** + * Generates a random stardate. + * + * @returns {number} a stardate between 41000 (inclusive) and 42000 (exclusive). + */ +export function randomStardate() { + throw new Error("Please remove this line and implement the randomStardate() function"); +} + + +/** + * Generates a random planet class. + * + * @returns {string} a one-letter planet class. + */ +export function randomPlanetClass() { + throw new Error("Please remove this line and implement the randomStardate() function"); +} From 784ab069fe77e4f26ae34331c985e5bfb2f1957f Mon Sep 17 00:00:00 2001 From: J R M Date: Wed, 18 Jun 2025 07:40:35 +0200 Subject: [PATCH 02/50] Create captains-log.spec.js --- .../concept/captains-log/captains-log.spec.js | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 exercises/concept/captains-log/captains-log.spec.js diff --git a/exercises/concept/captains-log/captains-log.spec.js b/exercises/concept/captains-log/captains-log.spec.js new file mode 100644 index 0000000000..fa448cf8ba --- /dev/null +++ b/exercises/concept/captains-log/captains-log.spec.js @@ -0,0 +1,33 @@ +import { describe, expect, test } from '@jest/globals'; +import { randomShipRegistryNumber, randomStardate, randomPlanetClass } from './captains-log'; +describe('randomShipRegistryNumber',() => { + test('registry numbers are valid',() => { + expect(randomShipRegistryNumber().test(/NCC-[1-9][0-9]{3}/)).toBe(true); + expect(randomShipRegistryNumber().test(/NCC-[1-9][0-9]{3}/)).toBe(true); + expect(randomShipRegistryNumber().test(/NCC-[1-9][0-9]{3}/)).toBe(true); + }); + test('returns a random registry number',() => { + expect(randomShipRegistryNumber()).not.toEqual(randomShipRegistryNumber()) + }); +}); +describe('randomStardate',() => { + test('stardates are valid',() => { + expect(41000<=randomStardate()<42000).toBe(true); + expect(41000<=randomStardate()<42000).toBe(true); + expect(41000<=randomStardate()<42000).toBe(true); + }); + test('returns a random stardate',() => { + expect(randomStardate()).not.toEqual(randomStardate()) + }); +}); +describe('randomPlanetClass', () => { + test('planet classes are valid', () => { + const planetClasses = ['D', 'H', 'J', 'K', 'L', 'M', 'N', 'R', 'T', 'Y']; + expect(planetClasses.includes(randomPlanetClass())).toBe(true) + expect(planetClasses.includes(randomPlanetClass())).toBe(true) + expect(planetClasses.includes(randomPlanetClass())).toBe(true) + }); + test('returns a random planet class',() => { + expect(randomPlanetClass()).not.toEqual(randomPlanetClass()) + }); +}); From 839ff5df0a1dfec74458a3db19af1c94865208b7 Mon Sep 17 00:00:00 2001 From: J R M Date: Wed, 18 Jun 2025 07:42:20 +0200 Subject: [PATCH 03/50] Create config.json Still need an uuid, no idea how to generate one --- .../concept/captains-log /.meta /config.json | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 exercises/concept/captains-log /.meta /config.json diff --git a/exercises/concept/captains-log /.meta /config.json b/exercises/concept/captains-log /.meta /config.json new file mode 100644 index 0000000000..3e3b83cfcc --- /dev/null +++ b/exercises/concept/captains-log /.meta /config.json @@ -0,0 +1,22 @@ +{ + "authors": [ + "SneakyMallard" + ], + "contributors": [], + "forked-from": ["java/captains-log"], + "concept": [ + { + "uuid": "need-to-generate", + "slug": "captains-log", + "name": "Captain's Log", + "concepts": ["randomness"], + "prerequisites": ["numbers", "arithmetic-operators"] + } + ], + "files": { + "solution": ["captains-log.js"], + "test": ["captains-log.spec.js"], + "exemplar": [".meta/exemplar.js"] + }, + "blurb": "Learn about randomness and the Math.random() function while helping Mary generate stardates and starship registry numbers for her Star Trek roleplay." +} From 9660cf4b93feb7cb4f873a6896f7f49acc3fa458 Mon Sep 17 00:00:00 2001 From: J R M Date: Wed, 18 Jun 2025 07:43:49 +0200 Subject: [PATCH 04/50] Rename config.json to config.json --- .../{captains-log /.meta => captains-log/.meta}/config.json | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename exercises/concept/{captains-log /.meta => captains-log/.meta}/config.json (100%) diff --git a/exercises/concept/captains-log /.meta /config.json b/exercises/concept/captains-log/.meta/config.json similarity index 100% rename from exercises/concept/captains-log /.meta /config.json rename to exercises/concept/captains-log/.meta/config.json From aeaa04eb94143bc8a9e1fe4d4478dfa610f41317 Mon Sep 17 00:00:00 2001 From: J R M Date: Wed, 18 Jun 2025 07:44:35 +0200 Subject: [PATCH 05/50] Create design.md --- .../concept/captains-log/.meta/design.md | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 exercises/concept/captains-log/.meta/design.md diff --git a/exercises/concept/captains-log/.meta/design.md b/exercises/concept/captains-log/.meta/design.md new file mode 100644 index 0000000000..d21c6d99bc --- /dev/null +++ b/exercises/concept/captains-log/.meta/design.md @@ -0,0 +1,27 @@ +# Design + +## Goal + +The goal of this exercise is to teach the student how to generate psuedorandom numbers in JavaScript. + +## Learning objectives + +- Know how to generate a random number with `Math.random()` +- Know how to generate a random number in a range. +- Know how to generate a random integer. + +## Out of scope + +- Details of pseudorandom number generation in general. +- Different algorithms for pseudorandom number generation. + + +## Concepts + +The Concepts this exercise unlocks are: + +- `randomness`: Know of the `Math.random()` function and know how to use it to generate random numbers. + +## Prerequisites + +- `numbers`: Know how numbers work in JavaScript. Know some number methods. From fe7da9a307f10bf31c43ae243a4f57117e95b211 Mon Sep 17 00:00:00 2001 From: J R M Date: Wed, 18 Jun 2025 07:45:18 +0200 Subject: [PATCH 06/50] Create exemplar.js --- exercises/concept/captains-log/.meta/exemplar.js | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 exercises/concept/captains-log/.meta/exemplar.js diff --git a/exercises/concept/captains-log/.meta/exemplar.js b/exercises/concept/captains-log/.meta/exemplar.js new file mode 100644 index 0000000000..83e830a8e5 --- /dev/null +++ b/exercises/concept/captains-log/.meta/exemplar.js @@ -0,0 +1,10 @@ +export function randomShipRegistryNumber() { + return "NCC-"+Math.floor(1000 + Math.random()*9000) +} +export function randomStardate() { + return 41000 + Math.random() * 1000 +} +export function randomPlanetClass() { + const planetClasses = ['D', 'H', 'J', 'K', 'L', 'M', 'N', 'R', 'T', 'Y'] + return planetClasses[Math.floor(Math.random() * 10)] +} From 365d8ccfe7ac8ddab18cd65a5d556cd7b44b589c Mon Sep 17 00:00:00 2001 From: J R M Date: Wed, 18 Jun 2025 07:46:01 +0200 Subject: [PATCH 07/50] Update exemplar.js Added stub file's comments for task #1 --- exercises/concept/captains-log/.meta/exemplar.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/exercises/concept/captains-log/.meta/exemplar.js b/exercises/concept/captains-log/.meta/exemplar.js index 83e830a8e5..73e2640431 100644 --- a/exercises/concept/captains-log/.meta/exemplar.js +++ b/exercises/concept/captains-log/.meta/exemplar.js @@ -1,3 +1,11 @@ +/// +// @ts-check + +/** + * Generates a random starship registry number. + * + * @returns {string} the generated registry number. + */ export function randomShipRegistryNumber() { return "NCC-"+Math.floor(1000 + Math.random()*9000) } From 580e1a9539acf95fe81061ac17ac22a187021c6a Mon Sep 17 00:00:00 2001 From: J R M Date: Wed, 18 Jun 2025 07:46:24 +0200 Subject: [PATCH 08/50] Update exemplar.js --- exercises/concept/captains-log/.meta/exemplar.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/exercises/concept/captains-log/.meta/exemplar.js b/exercises/concept/captains-log/.meta/exemplar.js index 73e2640431..e47ed7121d 100644 --- a/exercises/concept/captains-log/.meta/exemplar.js +++ b/exercises/concept/captains-log/.meta/exemplar.js @@ -9,6 +9,11 @@ export function randomShipRegistryNumber() { return "NCC-"+Math.floor(1000 + Math.random()*9000) } +/** + * Generates a random stardate. + * + * @returns {number} a stardate between 41000 (inclusive) and 42000 (exclusive). + */ export function randomStardate() { return 41000 + Math.random() * 1000 } From 77af0d8f4a1dd8723394ff9b75c1e79d8f639c02 Mon Sep 17 00:00:00 2001 From: J R M Date: Wed, 18 Jun 2025 07:46:58 +0200 Subject: [PATCH 09/50] Update exemplar.js Added stub file's comments for task #3 --- exercises/concept/captains-log/.meta/exemplar.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/exercises/concept/captains-log/.meta/exemplar.js b/exercises/concept/captains-log/.meta/exemplar.js index e47ed7121d..0c6900c9a6 100644 --- a/exercises/concept/captains-log/.meta/exemplar.js +++ b/exercises/concept/captains-log/.meta/exemplar.js @@ -9,6 +9,7 @@ export function randomShipRegistryNumber() { return "NCC-"+Math.floor(1000 + Math.random()*9000) } + /** * Generates a random stardate. * @@ -17,6 +18,12 @@ export function randomShipRegistryNumber() { export function randomStardate() { return 41000 + Math.random() * 1000 } + +/** + * Generates a random planet class. + * + * @returns {string} a one-letter planet class. + */ export function randomPlanetClass() { const planetClasses = ['D', 'H', 'J', 'K', 'L', 'M', 'N', 'R', 'T', 'Y'] return planetClasses[Math.floor(Math.random() * 10)] From f2a7ef8a72258ba6c96735840a7ac0fe71a52e0d Mon Sep 17 00:00:00 2001 From: J R M Date: Wed, 18 Jun 2025 07:47:52 +0200 Subject: [PATCH 10/50] Create hints.md --- exercises/concept/captains-log/docs/hints.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 exercises/concept/captains-log/docs/hints.md diff --git a/exercises/concept/captains-log/docs/hints.md b/exercises/concept/captains-log/docs/hints.md new file mode 100644 index 0000000000..2bc6f2fb01 --- /dev/null +++ b/exercises/concept/captains-log/docs/hints.md @@ -0,0 +1,11 @@ +# Hints + +## 1. Generate a random starship registry number + - To generate a random number in the range _min_ (inclusive) to _max_ (exclusive) you can use the snippet `min + Math.random()*(max - min)`. + - There is a [built in function][floor] for turning a floating point number into an integer. +## 2.Generate a random stardate + - To generate a random number in the range _min_ (inclusive) to _max_ (exclusive) you can use the snippet `min + Math.random()*(max - min)`. +## 3. Generate a random planet +- You can use a randomly generated integer as an array index. + +[floor]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/floor From 91e048fd8a1b7fee97f370e91b20606d334afd87 Mon Sep 17 00:00:00 2001 From: J R M Date: Wed, 18 Jun 2025 07:48:27 +0200 Subject: [PATCH 11/50] Create instructions.md --- .../concept/captains-log/docs/instructions.md | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 exercises/concept/captains-log/docs/instructions.md diff --git a/exercises/concept/captains-log/docs/instructions.md b/exercises/concept/captains-log/docs/instructions.md new file mode 100644 index 0000000000..223d282a61 --- /dev/null +++ b/exercises/concept/captains-log/docs/instructions.md @@ -0,0 +1,37 @@ +## Instructions + +Mary is a big fan of the TV series Star Trek: The Next Generation. She often plays pen-and-paper role playing games, where she and her friends pretend to be the crew of the Starship Enterprise. Mary's character is Captain Picard, which means she has to keep the captain's log. She loves the creative part of the game, but doesn't like to generate random data on the spot. + +Help Mary by creating random generators for data commonly appearing in the captain's log. +### 1. Generate a random starship registry number + +Enterprise (registry number NCC-1701) is not the only starship flying around! When it rendezvous with another starship, Mary needs to log the registry number of that starship. + +Registry numbers start with the prefix "NCC-" and then use a number from 1000 to 9999 (both inclusive). + +Implement the randomShipRegistryNumber() function that returns a random starship registry number. +```javascript +randomShipRegistryNumber() +// => "NCC-1947" +``` +### 2. Generate a random stardate + +What's the use of a log if it doesn't include dates? + +A stardate is a floating point number. The adventures of the Starship Enterprise from the first season of The Next Generation take place between the stardates 41000.0 and 42000.0. The "4" stands for the 24th century, the "1" for the first season. + +Implement the function randomStardate that returns a floating point number between 41000.0 (inclusive) and 42000.0 (exclusive). + +```javascript +randomStardate() +// => 41458.15721310934 +``` +### 3. Generate a random planet + +The Starship Enterprise encounters many planets in its travels. Planets in the Star Trek universe are split into categories based on their properties. For example, Earth is a class M planet. All possible planetary classes are: D, H, J, K, L, M, N, R, T, and Y. + +Implement the randomPlanetClassfunction. It should return one of the planetary classes at random. +```javascript +randomPlanetClass() +// => "K" +``` From 5ba9ac2e091022fb68314189bd675d2e090efc2c Mon Sep 17 00:00:00 2001 From: J R M Date: Wed, 18 Jun 2025 07:49:21 +0200 Subject: [PATCH 12/50] Create introduction.md --- .../concept/captains-log/docs/introduction.md | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 exercises/concept/captains-log/docs/introduction.md diff --git a/exercises/concept/captains-log/docs/introduction.md b/exercises/concept/captains-log/docs/introduction.md new file mode 100644 index 0000000000..be8d2e9606 --- /dev/null +++ b/exercises/concept/captains-log/docs/introduction.md @@ -0,0 +1,35 @@ +# Introduction + +Many programs need (apparently) random values to simulate real-world events. + +Common, familiar examples include: + + - A coin toss: a random value from ('H', 'T'). + - The roll of a die: a random integer from 1 to 6. + - Shuffling a deck of cards: a random ordering of a card list. + - The creation of trees and bushes in a 3-D graphics simulation. + +Generating truly random values with a computer is a [surprisingly difficult technical challenge][why-randomness-is-hard], so you may see these results referred to as "pseudorandom". +## Generating random numbers +In Javascript, you can generate psuedorandom numbers using the [`Math.random()`][Math.random] function. +It will return a psuedorandom floating-point number between 0 (inclusive), and 1 (exclusive). + +To get a random number between _min_ (inclusive) and _max_ (exclusive) you can use a function something like this: +```javascript +function getRandomInRange(min, max) { + return min + Math.random() * (max - min) ; +} +getRandomInRange(4, 10) +// => 5.72 +``` +## Generating random integers +To generate a random integer, you can use `Math.floor()` or `Math.ceil()` to turn a randomly generated number into an integer. +~~~~exercism/caution + +The `Math.random()` function should NOT be used for security and cryptographic applications!! + +Instead, you can use the Web Crypto API, which provides various cryptographic functions. +~~~~ + +[why-randomness-is-hard]: https://www.malwarebytes.com/blog/news/2013/09/in-computers-are-random-numbers-really-random +[Math.random]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random From 1de010d8e01e3d517584340c0deef68bece1e828 Mon Sep 17 00:00:00 2001 From: J R M Date: Wed, 18 Jun 2025 14:33:35 +0200 Subject: [PATCH 13/50] Modified tests in captains-log.spec.js --- .../concept/captains-log/captains-log.spec.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/exercises/concept/captains-log/captains-log.spec.js b/exercises/concept/captains-log/captains-log.spec.js index fa448cf8ba..7d24cdcf4b 100644 --- a/exercises/concept/captains-log/captains-log.spec.js +++ b/exercises/concept/captains-log/captains-log.spec.js @@ -2,9 +2,9 @@ import { describe, expect, test } from '@jest/globals'; import { randomShipRegistryNumber, randomStardate, randomPlanetClass } from './captains-log'; describe('randomShipRegistryNumber',() => { test('registry numbers are valid',() => { - expect(randomShipRegistryNumber().test(/NCC-[1-9][0-9]{3}/)).toBe(true); - expect(randomShipRegistryNumber().test(/NCC-[1-9][0-9]{3}/)).toBe(true); - expect(randomShipRegistryNumber().test(/NCC-[1-9][0-9]{3}/)).toBe(true); + for (let i=0;i<4; i++){ + expect(randomShipRegistryNumber()).toMatch(/NCC-[1-9][0-9]{3}/)) + } }); test('returns a random registry number',() => { expect(randomShipRegistryNumber()).not.toEqual(randomShipRegistryNumber()) @@ -12,9 +12,9 @@ describe('randomShipRegistryNumber',() => { }); describe('randomStardate',() => { test('stardates are valid',() => { - expect(41000<=randomStardate()<42000).toBe(true); - expect(41000<=randomStardate()<42000).toBe(true); - expect(41000<=randomStardate()<42000).toBe(true); + for (let i=0;i<4; i++){ + expect(randomStardate()>=41000 && randomStardate()<42000).toBe(true); + } }); test('returns a random stardate',() => { expect(randomStardate()).not.toEqual(randomStardate()) @@ -23,9 +23,9 @@ describe('randomStardate',() => { describe('randomPlanetClass', () => { test('planet classes are valid', () => { const planetClasses = ['D', 'H', 'J', 'K', 'L', 'M', 'N', 'R', 'T', 'Y']; - expect(planetClasses.includes(randomPlanetClass())).toBe(true) - expect(planetClasses.includes(randomPlanetClass())).toBe(true) - expect(planetClasses.includes(randomPlanetClass())).toBe(true) + for (let i=0;i<4; i++){ + expect(planetClasses.includes(randomPlanetClass())).toBe(true) + } }); test('returns a random planet class',() => { expect(randomPlanetClass()).not.toEqual(randomPlanetClass()) From c334b74a0037fb477a203440a83015eb32126423 Mon Sep 17 00:00:00 2001 From: J R M Date: Wed, 18 Jun 2025 15:03:14 +0200 Subject: [PATCH 14/50] Update captains-log.spec.js --- .../concept/captains-log/captains-log.spec.js | 39 ++++++++++++++----- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/exercises/concept/captains-log/captains-log.spec.js b/exercises/concept/captains-log/captains-log.spec.js index 7d24cdcf4b..a8bc6d0db3 100644 --- a/exercises/concept/captains-log/captains-log.spec.js +++ b/exercises/concept/captains-log/captains-log.spec.js @@ -10,21 +10,42 @@ describe('randomShipRegistryNumber',() => { expect(randomShipRegistryNumber()).not.toEqual(randomShipRegistryNumber()) }); }); +function loadDie(...values) { + const originalRandom = Math.random() + + Math.random = function loadedDie { + if (values.length === 0) { + return originalRandom(); + } + return values.shift(); + } + return () => { + Math.random = originalRandom; + } +} describe('randomStardate',() => { - test('stardates are valid',() => { - for (let i=0;i<4; i++){ - expect(randomStardate()>=41000 && randomStardate()<42000).toBe(true); + test('stardate is between 41000 and 42000',() => { + const restore = loadDie( + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5 + ); + + // 6 * 0, 6 * 1, 6 * 0.5 and everything else random + + for (let i = 0; i < 10_000; i++) { + const starDate = randomStardate() + expect(starDate).toBeGreaterThanOrEqual(41_000); + expect(starDate).toBeLessThan(42_000); } - }); - test('returns a random stardate',() => { - expect(randomStardate()).not.toEqual(randomStardate()) - }); -}); + restore(); + } +} describe('randomPlanetClass', () => { test('planet classes are valid', () => { const planetClasses = ['D', 'H', 'J', 'K', 'L', 'M', 'N', 'R', 'T', 'Y']; for (let i=0;i<4; i++){ - expect(planetClasses.includes(randomPlanetClass())).toBe(true) + expect(planetClasses).toContain(randomPlanetClass()) } }); test('returns a random planet class',() => { From b9d179f7753ce3cb46b21abc533c744d29ad3fa6 Mon Sep 17 00:00:00 2001 From: J R M Date: Wed, 18 Jun 2025 15:33:05 +0200 Subject: [PATCH 15/50] Update config.json --- exercises/concept/captains-log/.meta/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/concept/captains-log/.meta/config.json b/exercises/concept/captains-log/.meta/config.json index 3e3b83cfcc..81a226005a 100644 --- a/exercises/concept/captains-log/.meta/config.json +++ b/exercises/concept/captains-log/.meta/config.json @@ -6,7 +6,7 @@ "forked-from": ["java/captains-log"], "concept": [ { - "uuid": "need-to-generate", + "uuid": "65cf28ab-243c-41cb-a720-f324f2cabe28", "slug": "captains-log", "name": "Captain's Log", "concepts": ["randomness"], From 06a5d0553c91cca382fb0e787de5ad53557332d4 Mon Sep 17 00:00:00 2001 From: J R M Date: Wed, 18 Jun 2025 15:35:41 +0200 Subject: [PATCH 16/50] Update captains-log.spec.js --- .../concept/captains-log/captains-log.spec.js | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/exercises/concept/captains-log/captains-log.spec.js b/exercises/concept/captains-log/captains-log.spec.js index a8bc6d0db3..54483abe3c 100644 --- a/exercises/concept/captains-log/captains-log.spec.js +++ b/exercises/concept/captains-log/captains-log.spec.js @@ -30,9 +30,6 @@ describe('randomStardate',() => { 1, 1, 1, 1, 1, 1, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5 ); - - // 6 * 0, 6 * 1, 6 * 0.5 and everything else random - for (let i = 0; i < 10_000; i++) { const starDate = randomStardate() expect(starDate).toBeGreaterThanOrEqual(41_000); @@ -43,12 +40,20 @@ describe('randomStardate',() => { } describe('randomPlanetClass', () => { test('planet classes are valid', () => { - const planetClasses = ['D', 'H', 'J', 'K', 'L', 'M', 'N', 'R', 'T', 'Y']; - for (let i=0;i<4; i++){ - expect(planetClasses).toContain(randomPlanetClass()) + const expected = 'DHJKLMNRTY' + const seen = {} + for (let i=0; i < 1_000; i++){ + const actual = randomPlanetClass() + expect(expected).toContain(actual) } - }); - test('returns a random planet class',() => { - expect(randomPlanetClass()).not.toEqual(randomPlanetClass()) - }); -}); + }) + test('all planet classes can be returned', () => { + const expected = 'DHJKLMNRTY' + const seen = {} + for (let i=0; i < 1_000; i++){ + const actual = randomPlanetClass() + seen[actual] = true + } + expected(Object.keys(seen).length).toBe(expected.length); + }) +}) From 87ef708aae8263742643a293bbc74397b2b8b7d3 Mon Sep 17 00:00:00 2001 From: J R M Date: Wed, 18 Jun 2025 15:39:17 +0200 Subject: [PATCH 17/50] Removed extra parenthesis --- exercises/concept/captains-log/captains-log.spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exercises/concept/captains-log/captains-log.spec.js b/exercises/concept/captains-log/captains-log.spec.js index 54483abe3c..a2d5bc2aec 100644 --- a/exercises/concept/captains-log/captains-log.spec.js +++ b/exercises/concept/captains-log/captains-log.spec.js @@ -3,11 +3,11 @@ import { randomShipRegistryNumber, randomStardate, randomPlanetClass } from './c describe('randomShipRegistryNumber',() => { test('registry numbers are valid',() => { for (let i=0;i<4; i++){ - expect(randomShipRegistryNumber()).toMatch(/NCC-[1-9][0-9]{3}/)) + expect(randomShipRegistryNumber()).toMatch(/NCC-[1-9][0-9]{3}/) } }); test('returns a random registry number',() => { - expect(randomShipRegistryNumber()).not.toEqual(randomShipRegistryNumber()) + expect(randomShipRegistryNumber()).not.toEqual(randomShipRegistryNumber()) }); }); function loadDie(...values) { From a84402bc78dac1aa314d521ba1cb939f490e8b7a Mon Sep 17 00:00:00 2001 From: J R M Date: Wed, 18 Jun 2025 15:44:02 +0200 Subject: [PATCH 18/50] Added captains-log to config.json Added captains-log to config.json --- config.json | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/config.json b/config.json index e6ec3b62a1..bc732de017 100644 --- a/config.json +++ b/config.json @@ -422,7 +422,22 @@ "type-conversion" ], "status": "beta" - } + }, + { + "uuid": "65cf28ab-243c-41cb-a720-f324f2cabe28", + "slug": "captains-log", + "name": "Captain's Log", + "concepts": ["randomness"], + "prerequisites": ["numbers", "arithmetic-operators"] + } + ], + "files": { + "solution": ["captains-log.js"], + "test": ["captains-log.spec.js"], + "exemplar": [".meta/exemplar.js"] + }, + "blurb": "Learn about randomness and the Math.random() function while helping Mary generate stardates and starship registry numbers for her Star Trek roleplay." +} ], "practice": [ { From a249a0687c55603ac06ac524b968bcd8203d8cf0 Mon Sep 17 00:00:00 2001 From: J R M Date: Wed, 18 Jun 2025 15:45:08 +0200 Subject: [PATCH 19/50] Update captains-log.spec.js --- exercises/concept/captains-log/captains-log.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/concept/captains-log/captains-log.spec.js b/exercises/concept/captains-log/captains-log.spec.js index a2d5bc2aec..3828958ae0 100644 --- a/exercises/concept/captains-log/captains-log.spec.js +++ b/exercises/concept/captains-log/captains-log.spec.js @@ -13,7 +13,7 @@ describe('randomShipRegistryNumber',() => { function loadDie(...values) { const originalRandom = Math.random() - Math.random = function loadedDie { + Math.random = function loadedDie() { if (values.length === 0) { return originalRandom(); } From ef7aa466e81a495a0e654dea0ebc64994c52c1c7 Mon Sep 17 00:00:00 2001 From: J R M Date: Wed, 18 Jun 2025 15:47:52 +0200 Subject: [PATCH 20/50] Update config.json --- config.json | 8 -------- 1 file changed, 8 deletions(-) diff --git a/config.json b/config.json index bc732de017..75e9b4b638 100644 --- a/config.json +++ b/config.json @@ -430,14 +430,6 @@ "concepts": ["randomness"], "prerequisites": ["numbers", "arithmetic-operators"] } - ], - "files": { - "solution": ["captains-log.js"], - "test": ["captains-log.spec.js"], - "exemplar": [".meta/exemplar.js"] - }, - "blurb": "Learn about randomness and the Math.random() function while helping Mary generate stardates and starship registry numbers for her Star Trek roleplay." -} ], "practice": [ { From 5fbe8cf9c7c8706f19ac133b2a74d68c06c5e372 Mon Sep 17 00:00:00 2001 From: J R M Date: Wed, 18 Jun 2025 15:51:11 +0200 Subject: [PATCH 21/50] Update captains-log.spec.js --- .../concept/captains-log/captains-log.spec.js | 70 +++++++++++-------- 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/exercises/concept/captains-log/captains-log.spec.js b/exercises/concept/captains-log/captains-log.spec.js index 3828958ae0..bd2a5396db 100644 --- a/exercises/concept/captains-log/captains-log.spec.js +++ b/exercises/concept/captains-log/captains-log.spec.js @@ -1,59 +1,69 @@ import { describe, expect, test } from '@jest/globals'; import { randomShipRegistryNumber, randomStardate, randomPlanetClass } from './captains-log'; -describe('randomShipRegistryNumber',() => { - test('registry numbers are valid',() => { - for (let i=0;i<4; i++){ - expect(randomShipRegistryNumber()).toMatch(/NCC-[1-9][0-9]{3}/) + +describe('randomShipRegistryNumber', () => { + test('registry numbers are valid', () => { + for (let i = 0; i < 4; i++) { + expect(randomShipRegistryNumber()).toMatch(/NCC-[1-9][0-9]{3}/); } }); - test('returns a random registry number',() => { - expect(randomShipRegistryNumber()).not.toEqual(randomShipRegistryNumber()) + + test('returns a random registry number', () => { + expect(randomShipRegistryNumber()).not.toEqual(randomShipRegistryNumber()); }); }); + function loadDie(...values) { - const originalRandom = Math.random() + const originalRandom = Math.random(); Math.random = function loadedDie() { if (values.length === 0) { return originalRandom(); } return values.shift(); - } + }; + return () => { Math.random = originalRandom; - } + }; } -describe('randomStardate',() => { - test('stardate is between 41000 and 42000',() => { + +describe('randomStardate', () => { + test('stardate is between 41000 and 42000', () => { const restore = loadDie( 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5 ); + for (let i = 0; i < 10_000; i++) { - const starDate = randomStardate() + const starDate = randomStardate(); expect(starDate).toBeGreaterThanOrEqual(41_000); expect(starDate).toBeLessThan(42_000); } + restore(); - } -} + }); +}); + describe('randomPlanetClass', () => { - test('planet classes are valid', () => { - const expected = 'DHJKLMNRTY' - const seen = {} - for (let i=0; i < 1_000; i++){ - const actual = randomPlanetClass() - expect(expected).toContain(actual) + test('planet classes are valid', () => { + const expected = 'DHJKLMNRTY'; + for (let i = 0; i < 1_000; i++) { + const actual = randomPlanetClass(); + expect(expected).toContain(actual); } - }) - test('all planet classes can be returned', () => { - const expected = 'DHJKLMNRTY' - const seen = {} - for (let i=0; i < 1_000; i++){ - const actual = randomPlanetClass() - seen[actual] = true + }); + + test('all planet classes can be returned', () => { + const expected = 'DHJKLMNRTY'; + const seen = {}; + + for (let i = 0; i < 1_000; i++) { + const actual = randomPlanetClass(); + seen[actual] = true; } - expected(Object.keys(seen).length).toBe(expected.length); - }) -}) + + expect(Object.keys(seen).length).toBe(expected.length); + }); +}); From 9a07643a3d38153680acf0ae023c5590c4b32f1a Mon Sep 17 00:00:00 2001 From: J R M Date: Wed, 18 Jun 2025 17:01:45 +0200 Subject: [PATCH 22/50] Added randomness to concepts list --- config.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/config.json b/config.json index 75e9b4b638..bab7f5187b 100644 --- a/config.json +++ b/config.json @@ -2858,6 +2858,11 @@ "uuid": "4e68e39a-e36c-4d2d-8714-eb6482e31ff5", "slug": "while-loops", "name": "While Loops" + }, + { + "uuid": "65cf28ab-243c-41cb-a720-f324f2cabe28", + "slug": "randomness", + "name": "Randomness", } ], "key_features": [ From eac687310b1c6027a73e6cd1b2c2af59944c6df6 Mon Sep 17 00:00:00 2001 From: J R M Date: Wed, 18 Jun 2025 17:02:27 +0200 Subject: [PATCH 23/50] Rename docs to .docs --- exercises/concept/captains-log/{docs => .docs}/hints.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename exercises/concept/captains-log/{docs => .docs}/hints.md (100%) diff --git a/exercises/concept/captains-log/docs/hints.md b/exercises/concept/captains-log/.docs/hints.md similarity index 100% rename from exercises/concept/captains-log/docs/hints.md rename to exercises/concept/captains-log/.docs/hints.md From d9adf15c6eb21465e3b7657c479071935bda7b43 Mon Sep 17 00:00:00 2001 From: J R M Date: Wed, 18 Jun 2025 17:02:44 +0200 Subject: [PATCH 24/50] Rename instructions.md to instructions.md --- exercises/concept/captains-log/{docs => .docs}/instructions.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename exercises/concept/captains-log/{docs => .docs}/instructions.md (100%) diff --git a/exercises/concept/captains-log/docs/instructions.md b/exercises/concept/captains-log/.docs/instructions.md similarity index 100% rename from exercises/concept/captains-log/docs/instructions.md rename to exercises/concept/captains-log/.docs/instructions.md From b068bfc5721d76a04ef5265966a3c88e5550cd20 Mon Sep 17 00:00:00 2001 From: J R M Date: Wed, 18 Jun 2025 17:03:12 +0200 Subject: [PATCH 25/50] Rename introduction.md to introduction.md --- exercises/concept/captains-log/{docs => .docs}/introduction.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename exercises/concept/captains-log/{docs => .docs}/introduction.md (100%) diff --git a/exercises/concept/captains-log/docs/introduction.md b/exercises/concept/captains-log/.docs/introduction.md similarity index 100% rename from exercises/concept/captains-log/docs/introduction.md rename to exercises/concept/captains-log/.docs/introduction.md From f03e1e789ce4a65256a504a2c34af419240d5846 Mon Sep 17 00:00:00 2001 From: J R M Date: Thu, 19 Jun 2025 08:56:28 +0200 Subject: [PATCH 26/50] Update config.json --- config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.json b/config.json index bab7f5187b..3417ed6bb3 100644 --- a/config.json +++ b/config.json @@ -2862,7 +2862,7 @@ { "uuid": "65cf28ab-243c-41cb-a720-f324f2cabe28", "slug": "randomness", - "name": "Randomness", + "name": "Randomness" } ], "key_features": [ From 47f5e27674875a943562b4a67c1268ec3c092cde Mon Sep 17 00:00:00 2001 From: J R M Date: Thu, 19 Jun 2025 08:57:41 +0200 Subject: [PATCH 27/50] Update config.json --- config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.json b/config.json index 3417ed6bb3..4e3cca228d 100644 --- a/config.json +++ b/config.json @@ -2860,7 +2860,7 @@ "name": "While Loops" }, { - "uuid": "65cf28ab-243c-41cb-a720-f324f2cabe28", + "uuid": "ca322d6f-0f7e-4a2d-a058-e98a59cdae93", "slug": "randomness", "name": "Randomness" } From b3cd46f1ae4815441eb7943751af1a27d54ff2cf Mon Sep 17 00:00:00 2001 From: J R M Date: Thu, 19 Jun 2025 09:00:23 +0200 Subject: [PATCH 28/50] Create config.json in concepts --- concepts/randomness/config.json | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 concepts/randomness/config.json diff --git a/concepts/randomness/config.json b/concepts/randomness/config.json new file mode 100644 index 0000000000..725f65388c --- /dev/null +++ b/concepts/randomness/config.json @@ -0,0 +1,5 @@ +{ + "blurb": "Random number generation using Math.random()", + "authors": ["SneakyMallard"], + "contributors":[""], +} From d2436ae254f5b04a1f56b540c0a2c014e1a54c24 Mon Sep 17 00:00:00 2001 From: J R M Date: Thu, 19 Jun 2025 09:00:44 +0200 Subject: [PATCH 29/50] Rename concepts/randomness/config.json to concepts/randomness/.meta/config.json --- concepts/randomness/{ => .meta}/config.json | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename concepts/randomness/{ => .meta}/config.json (100%) diff --git a/concepts/randomness/config.json b/concepts/randomness/.meta/config.json similarity index 100% rename from concepts/randomness/config.json rename to concepts/randomness/.meta/config.json From 6d25bfb49a41d895a7580dadaa3a2447b23f4a28 Mon Sep 17 00:00:00 2001 From: J R M Date: Thu, 19 Jun 2025 09:02:23 +0200 Subject: [PATCH 30/50] Create about.md --- concepts/randomness/about.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 concepts/randomness/about.md diff --git a/concepts/randomness/about.md b/concepts/randomness/about.md new file mode 100644 index 0000000000..be8d2e9606 --- /dev/null +++ b/concepts/randomness/about.md @@ -0,0 +1,35 @@ +# Introduction + +Many programs need (apparently) random values to simulate real-world events. + +Common, familiar examples include: + + - A coin toss: a random value from ('H', 'T'). + - The roll of a die: a random integer from 1 to 6. + - Shuffling a deck of cards: a random ordering of a card list. + - The creation of trees and bushes in a 3-D graphics simulation. + +Generating truly random values with a computer is a [surprisingly difficult technical challenge][why-randomness-is-hard], so you may see these results referred to as "pseudorandom". +## Generating random numbers +In Javascript, you can generate psuedorandom numbers using the [`Math.random()`][Math.random] function. +It will return a psuedorandom floating-point number between 0 (inclusive), and 1 (exclusive). + +To get a random number between _min_ (inclusive) and _max_ (exclusive) you can use a function something like this: +```javascript +function getRandomInRange(min, max) { + return min + Math.random() * (max - min) ; +} +getRandomInRange(4, 10) +// => 5.72 +``` +## Generating random integers +To generate a random integer, you can use `Math.floor()` or `Math.ceil()` to turn a randomly generated number into an integer. +~~~~exercism/caution + +The `Math.random()` function should NOT be used for security and cryptographic applications!! + +Instead, you can use the Web Crypto API, which provides various cryptographic functions. +~~~~ + +[why-randomness-is-hard]: https://www.malwarebytes.com/blog/news/2013/09/in-computers-are-random-numbers-really-random +[Math.random]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random From 9c2a8492c9161433dab1273ed479a7cebfb2836a Mon Sep 17 00:00:00 2001 From: J R M Date: Thu, 19 Jun 2025 09:02:44 +0200 Subject: [PATCH 31/50] Create introduction.md --- concepts/randomness/introduction.md | 35 +++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 concepts/randomness/introduction.md diff --git a/concepts/randomness/introduction.md b/concepts/randomness/introduction.md new file mode 100644 index 0000000000..be8d2e9606 --- /dev/null +++ b/concepts/randomness/introduction.md @@ -0,0 +1,35 @@ +# Introduction + +Many programs need (apparently) random values to simulate real-world events. + +Common, familiar examples include: + + - A coin toss: a random value from ('H', 'T'). + - The roll of a die: a random integer from 1 to 6. + - Shuffling a deck of cards: a random ordering of a card list. + - The creation of trees and bushes in a 3-D graphics simulation. + +Generating truly random values with a computer is a [surprisingly difficult technical challenge][why-randomness-is-hard], so you may see these results referred to as "pseudorandom". +## Generating random numbers +In Javascript, you can generate psuedorandom numbers using the [`Math.random()`][Math.random] function. +It will return a psuedorandom floating-point number between 0 (inclusive), and 1 (exclusive). + +To get a random number between _min_ (inclusive) and _max_ (exclusive) you can use a function something like this: +```javascript +function getRandomInRange(min, max) { + return min + Math.random() * (max - min) ; +} +getRandomInRange(4, 10) +// => 5.72 +``` +## Generating random integers +To generate a random integer, you can use `Math.floor()` or `Math.ceil()` to turn a randomly generated number into an integer. +~~~~exercism/caution + +The `Math.random()` function should NOT be used for security and cryptographic applications!! + +Instead, you can use the Web Crypto API, which provides various cryptographic functions. +~~~~ + +[why-randomness-is-hard]: https://www.malwarebytes.com/blog/news/2013/09/in-computers-are-random-numbers-really-random +[Math.random]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random From 37794741f739e548c2968726bb74f93ec9f4c14f Mon Sep 17 00:00:00 2001 From: J R M Date: Thu, 19 Jun 2025 09:03:37 +0200 Subject: [PATCH 32/50] Update config.json --- concepts/randomness/.meta/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/randomness/.meta/config.json b/concepts/randomness/.meta/config.json index 725f65388c..426ece4dd8 100644 --- a/concepts/randomness/.meta/config.json +++ b/concepts/randomness/.meta/config.json @@ -1,5 +1,5 @@ { "blurb": "Random number generation using Math.random()", "authors": ["SneakyMallard"], - "contributors":[""], + "contributors":[""] } From 855ccd20daab02f2b73541a7979ad3650e91915b Mon Sep 17 00:00:00 2001 From: J R M Date: Thu, 19 Jun 2025 09:05:08 +0200 Subject: [PATCH 33/50] Create links.json --- concepts/randomness/links.json | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 concepts/randomness/links.json diff --git a/concepts/randomness/links.json b/concepts/randomness/links.json new file mode 100644 index 0000000000..e399a92daa --- /dev/null +++ b/concepts/randomness/links.json @@ -0,0 +1,4 @@ +{ + "url":"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random", + "description": "MDN: The Math.random() function" +} From fe381c710d25bfbc1d2e8487ac5d69c2d8447d8c Mon Sep 17 00:00:00 2001 From: J R M Date: Thu, 19 Jun 2025 09:05:59 +0200 Subject: [PATCH 34/50] Update config.json --- concepts/randomness/.meta/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/randomness/.meta/config.json b/concepts/randomness/.meta/config.json index 426ece4dd8..942b99ea09 100644 --- a/concepts/randomness/.meta/config.json +++ b/concepts/randomness/.meta/config.json @@ -1,5 +1,5 @@ { "blurb": "Random number generation using Math.random()", "authors": ["SneakyMallard"], - "contributors":[""] + "contributors":[] } From 173333d13bd879dd1999711ebc3c20af938fce71 Mon Sep 17 00:00:00 2001 From: J R M Date: Thu, 19 Jun 2025 09:06:42 +0200 Subject: [PATCH 35/50] Update links.json --- concepts/randomness/links.json | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/concepts/randomness/links.json b/concepts/randomness/links.json index e399a92daa..c13c2dcb62 100644 --- a/concepts/randomness/links.json +++ b/concepts/randomness/links.json @@ -1,4 +1,6 @@ -{ - "url":"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random", - "description": "MDN: The Math.random() function" -} +[ + { + "url":"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random", + "description": "MDN: The Math.random() function" + } +] From f946ae5122c15c6870c9ea4dd2ce7f86efa34c56 Mon Sep 17 00:00:00 2001 From: J R M Date: Thu, 19 Jun 2025 09:10:23 +0200 Subject: [PATCH 36/50] Update exercises/concept/captains-log/captains-log.spec.js Co-authored-by: Derk-Jan Karrenbeld --- exercises/concept/captains-log/captains-log.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/concept/captains-log/captains-log.spec.js b/exercises/concept/captains-log/captains-log.spec.js index bd2a5396db..9900f133d3 100644 --- a/exercises/concept/captains-log/captains-log.spec.js +++ b/exercises/concept/captains-log/captains-log.spec.js @@ -14,7 +14,7 @@ describe('randomShipRegistryNumber', () => { }); function loadDie(...values) { - const originalRandom = Math.random(); + const originalRandom = Math.random; Math.random = function loadedDie() { if (values.length === 0) { From 0cdd9acee293d50cd50231fde40de2f48d46845c Mon Sep 17 00:00:00 2001 From: Derk-Jan Karrenbeld Date: Thu, 19 Jun 2025 12:42:04 +0200 Subject: [PATCH 37/50] Fix tests --- exercises/concept/captains-log/captains-log.spec.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/exercises/concept/captains-log/captains-log.spec.js b/exercises/concept/captains-log/captains-log.spec.js index 9900f133d3..1fa43afa5c 100644 --- a/exercises/concept/captains-log/captains-log.spec.js +++ b/exercises/concept/captains-log/captains-log.spec.js @@ -30,9 +30,13 @@ function loadDie(...values) { describe('randomStardate', () => { test('stardate is between 41000 and 42000', () => { + const min = 0; + const max = 1 - Number.EPSILON; + + // prettier-ignore const restore = loadDie( - 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, + min, min, min, min, min, min, + max, max, max, max, max, max, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5 ); From ac1d8da81494ac03c5fdcea5ca4ba9392df1ff64 Mon Sep 17 00:00:00 2001 From: J R M Date: Thu, 19 Jun 2025 14:47:57 +0200 Subject: [PATCH 38/50] Format 12 files --- concepts/randomness/about.md | 24 ++++++++++++------- concepts/randomness/introduction.md | 24 ++++++++++++------- concepts/randomness/links.json | 2 +- config.json | 19 +++++++++------ exercises/concept/captains-log/.docs/hints.md | 15 ++++++++---- .../captains-log/.docs/instructions.md | 11 ++++++--- .../captains-log/.docs/introduction.md | 24 ++++++++++++------- .../concept/captains-log/.meta/config.json | 23 +++++++----------- .../concept/captains-log/.meta/design.md | 1 - .../concept/captains-log/.meta/exemplar.js | 8 +++---- .../concept/captains-log/captains-log.js | 13 ++++++---- .../concept/captains-log/captains-log.spec.js | 24 +++++++++++-------- 12 files changed, 112 insertions(+), 76 deletions(-) diff --git a/concepts/randomness/about.md b/concepts/randomness/about.md index be8d2e9606..bae9d8d195 100644 --- a/concepts/randomness/about.md +++ b/concepts/randomness/about.md @@ -4,32 +4,38 @@ Many programs need (apparently) random values to simulate real-world events. Common, familiar examples include: - - A coin toss: a random value from ('H', 'T'). - - The roll of a die: a random integer from 1 to 6. - - Shuffling a deck of cards: a random ordering of a card list. - - The creation of trees and bushes in a 3-D graphics simulation. +- A coin toss: a random value from ('H', 'T'). +- The roll of a die: a random integer from 1 to 6. +- Shuffling a deck of cards: a random ordering of a card list. +- The creation of trees and bushes in a 3-D graphics simulation. Generating truly random values with a computer is a [surprisingly difficult technical challenge][why-randomness-is-hard], so you may see these results referred to as "pseudorandom". + ## Generating random numbers + In Javascript, you can generate psuedorandom numbers using the [`Math.random()`][Math.random] function. It will return a psuedorandom floating-point number between 0 (inclusive), and 1 (exclusive). -To get a random number between _min_ (inclusive) and _max_ (exclusive) you can use a function something like this: +To get a random number between _min_ (inclusive) and _max_ (exclusive) you can use a function something like this: + ```javascript function getRandomInRange(min, max) { - return min + Math.random() * (max - min) ; + return min + Math.random() * (max - min); } -getRandomInRange(4, 10) +getRandomInRange(4, 10); // => 5.72 ``` + ## Generating random integers + To generate a random integer, you can use `Math.floor()` or `Math.ceil()` to turn a randomly generated number into an integer. -~~~~exercism/caution + +```exercism/caution The `Math.random()` function should NOT be used for security and cryptographic applications!! Instead, you can use the Web Crypto API, which provides various cryptographic functions. -~~~~ +``` [why-randomness-is-hard]: https://www.malwarebytes.com/blog/news/2013/09/in-computers-are-random-numbers-really-random [Math.random]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random diff --git a/concepts/randomness/introduction.md b/concepts/randomness/introduction.md index be8d2e9606..bae9d8d195 100644 --- a/concepts/randomness/introduction.md +++ b/concepts/randomness/introduction.md @@ -4,32 +4,38 @@ Many programs need (apparently) random values to simulate real-world events. Common, familiar examples include: - - A coin toss: a random value from ('H', 'T'). - - The roll of a die: a random integer from 1 to 6. - - Shuffling a deck of cards: a random ordering of a card list. - - The creation of trees and bushes in a 3-D graphics simulation. +- A coin toss: a random value from ('H', 'T'). +- The roll of a die: a random integer from 1 to 6. +- Shuffling a deck of cards: a random ordering of a card list. +- The creation of trees and bushes in a 3-D graphics simulation. Generating truly random values with a computer is a [surprisingly difficult technical challenge][why-randomness-is-hard], so you may see these results referred to as "pseudorandom". + ## Generating random numbers + In Javascript, you can generate psuedorandom numbers using the [`Math.random()`][Math.random] function. It will return a psuedorandom floating-point number between 0 (inclusive), and 1 (exclusive). -To get a random number between _min_ (inclusive) and _max_ (exclusive) you can use a function something like this: +To get a random number between _min_ (inclusive) and _max_ (exclusive) you can use a function something like this: + ```javascript function getRandomInRange(min, max) { - return min + Math.random() * (max - min) ; + return min + Math.random() * (max - min); } -getRandomInRange(4, 10) +getRandomInRange(4, 10); // => 5.72 ``` + ## Generating random integers + To generate a random integer, you can use `Math.floor()` or `Math.ceil()` to turn a randomly generated number into an integer. -~~~~exercism/caution + +```exercism/caution The `Math.random()` function should NOT be used for security and cryptographic applications!! Instead, you can use the Web Crypto API, which provides various cryptographic functions. -~~~~ +``` [why-randomness-is-hard]: https://www.malwarebytes.com/blog/news/2013/09/in-computers-are-random-numbers-really-random [Math.random]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random diff --git a/concepts/randomness/links.json b/concepts/randomness/links.json index c13c2dcb62..5d949ca1a5 100644 --- a/concepts/randomness/links.json +++ b/concepts/randomness/links.json @@ -1,6 +1,6 @@ [ { - "url":"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random", + "url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random", "description": "MDN: The Math.random() function" } ] diff --git a/config.json b/config.json index 4e3cca228d..9dedc8f3ff 100644 --- a/config.json +++ b/config.json @@ -424,12 +424,17 @@ "status": "beta" }, { - "uuid": "65cf28ab-243c-41cb-a720-f324f2cabe28", - "slug": "captains-log", - "name": "Captain's Log", - "concepts": ["randomness"], - "prerequisites": ["numbers", "arithmetic-operators"] - } + "slug": "captains-log", + "name": "Captain's Log", + "uuid": "65cf28ab-243c-41cb-a720-f324f2cabe28", + "concepts": [ + "randomness" + ], + "prerequisites": [ + "numbers", + "arithmetic-operators" + ] + } ], "practice": [ { @@ -2859,7 +2864,7 @@ "slug": "while-loops", "name": "While Loops" }, - { + { "uuid": "ca322d6f-0f7e-4a2d-a058-e98a59cdae93", "slug": "randomness", "name": "Randomness" diff --git a/exercises/concept/captains-log/.docs/hints.md b/exercises/concept/captains-log/.docs/hints.md index 2bc6f2fb01..ee4730cc40 100644 --- a/exercises/concept/captains-log/.docs/hints.md +++ b/exercises/concept/captains-log/.docs/hints.md @@ -1,11 +1,16 @@ # Hints ## 1. Generate a random starship registry number - - To generate a random number in the range _min_ (inclusive) to _max_ (exclusive) you can use the snippet `min + Math.random()*(max - min)`. - - There is a [built in function][floor] for turning a floating point number into an integer. -## 2.Generate a random stardate - - To generate a random number in the range _min_ (inclusive) to _max_ (exclusive) you can use the snippet `min + Math.random()*(max - min)`. + +- To generate a random number in the range _min_ (inclusive) to _max_ (exclusive) you can use the snippet `min + Math.random()*(max - min)`. +- There is a [built in function][floor] for turning a floating point number into an integer. + +## 2.Generate a random stardate + +- To generate a random number in the range _min_ (inclusive) to _max_ (exclusive) you can use the snippet `min + Math.random()*(max - min)`. + ## 3. Generate a random planet + - You can use a randomly generated integer as an array index. - + [floor]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/floor diff --git a/exercises/concept/captains-log/.docs/instructions.md b/exercises/concept/captains-log/.docs/instructions.md index 223d282a61..e7d765c39c 100644 --- a/exercises/concept/captains-log/.docs/instructions.md +++ b/exercises/concept/captains-log/.docs/instructions.md @@ -3,6 +3,7 @@ Mary is a big fan of the TV series Star Trek: The Next Generation. She often plays pen-and-paper role playing games, where she and her friends pretend to be the crew of the Starship Enterprise. Mary's character is Captain Picard, which means she has to keep the captain's log. She loves the creative part of the game, but doesn't like to generate random data on the spot. Help Mary by creating random generators for data commonly appearing in the captain's log. + ### 1. Generate a random starship registry number Enterprise (registry number NCC-1701) is not the only starship flying around! When it rendezvous with another starship, Mary needs to log the registry number of that starship. @@ -10,10 +11,12 @@ Enterprise (registry number NCC-1701) is not the only starship flying around! Wh Registry numbers start with the prefix "NCC-" and then use a number from 1000 to 9999 (both inclusive). Implement the randomShipRegistryNumber() function that returns a random starship registry number. + ```javascript -randomShipRegistryNumber() +randomShipRegistryNumber(); // => "NCC-1947" ``` + ### 2. Generate a random stardate What's the use of a log if it doesn't include dates? @@ -23,15 +26,17 @@ A stardate is a floating point number. The adventures of the Starship Enterprise Implement the function randomStardate that returns a floating point number between 41000.0 (inclusive) and 42000.0 (exclusive). ```javascript -randomStardate() +randomStardate(); // => 41458.15721310934 ``` + ### 3. Generate a random planet The Starship Enterprise encounters many planets in its travels. Planets in the Star Trek universe are split into categories based on their properties. For example, Earth is a class M planet. All possible planetary classes are: D, H, J, K, L, M, N, R, T, and Y. Implement the randomPlanetClassfunction. It should return one of the planetary classes at random. + ```javascript -randomPlanetClass() +randomPlanetClass(); // => "K" ``` diff --git a/exercises/concept/captains-log/.docs/introduction.md b/exercises/concept/captains-log/.docs/introduction.md index be8d2e9606..bae9d8d195 100644 --- a/exercises/concept/captains-log/.docs/introduction.md +++ b/exercises/concept/captains-log/.docs/introduction.md @@ -4,32 +4,38 @@ Many programs need (apparently) random values to simulate real-world events. Common, familiar examples include: - - A coin toss: a random value from ('H', 'T'). - - The roll of a die: a random integer from 1 to 6. - - Shuffling a deck of cards: a random ordering of a card list. - - The creation of trees and bushes in a 3-D graphics simulation. +- A coin toss: a random value from ('H', 'T'). +- The roll of a die: a random integer from 1 to 6. +- Shuffling a deck of cards: a random ordering of a card list. +- The creation of trees and bushes in a 3-D graphics simulation. Generating truly random values with a computer is a [surprisingly difficult technical challenge][why-randomness-is-hard], so you may see these results referred to as "pseudorandom". + ## Generating random numbers + In Javascript, you can generate psuedorandom numbers using the [`Math.random()`][Math.random] function. It will return a psuedorandom floating-point number between 0 (inclusive), and 1 (exclusive). -To get a random number between _min_ (inclusive) and _max_ (exclusive) you can use a function something like this: +To get a random number between _min_ (inclusive) and _max_ (exclusive) you can use a function something like this: + ```javascript function getRandomInRange(min, max) { - return min + Math.random() * (max - min) ; + return min + Math.random() * (max - min); } -getRandomInRange(4, 10) +getRandomInRange(4, 10); // => 5.72 ``` + ## Generating random integers + To generate a random integer, you can use `Math.floor()` or `Math.ceil()` to turn a randomly generated number into an integer. -~~~~exercism/caution + +```exercism/caution The `Math.random()` function should NOT be used for security and cryptographic applications!! Instead, you can use the Web Crypto API, which provides various cryptographic functions. -~~~~ +``` [why-randomness-is-hard]: https://www.malwarebytes.com/blog/news/2013/09/in-computers-are-random-numbers-really-random [Math.random]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random diff --git a/exercises/concept/captains-log/.meta/config.json b/exercises/concept/captains-log/.meta/config.json index 81a226005a..205abf7f2e 100644 --- a/exercises/concept/captains-log/.meta/config.json +++ b/exercises/concept/captains-log/.meta/config.json @@ -2,21 +2,16 @@ "authors": [ "SneakyMallard" ], - "contributors": [], - "forked-from": ["java/captains-log"], - "concept": [ - { - "uuid": "65cf28ab-243c-41cb-a720-f324f2cabe28", - "slug": "captains-log", - "name": "Captain's Log", - "concepts": ["randomness"], - "prerequisites": ["numbers", "arithmetic-operators"] - } - ], "files": { - "solution": ["captains-log.js"], - "test": ["captains-log.spec.js"], - "exemplar": [".meta/exemplar.js"] + "solution": [ + "captains-log.js" + ], + "test": [ + "captains-log.spec.js" + ], + "exemplar": [ + ".meta/exemplar.js" + ] }, "blurb": "Learn about randomness and the Math.random() function while helping Mary generate stardates and starship registry numbers for her Star Trek roleplay." } diff --git a/exercises/concept/captains-log/.meta/design.md b/exercises/concept/captains-log/.meta/design.md index d21c6d99bc..63a5f94e50 100644 --- a/exercises/concept/captains-log/.meta/design.md +++ b/exercises/concept/captains-log/.meta/design.md @@ -15,7 +15,6 @@ The goal of this exercise is to teach the student how to generate psuedorandom n - Details of pseudorandom number generation in general. - Different algorithms for pseudorandom number generation. - ## Concepts The Concepts this exercise unlocks are: diff --git a/exercises/concept/captains-log/.meta/exemplar.js b/exercises/concept/captains-log/.meta/exemplar.js index 0c6900c9a6..7d48ea4b41 100644 --- a/exercises/concept/captains-log/.meta/exemplar.js +++ b/exercises/concept/captains-log/.meta/exemplar.js @@ -7,7 +7,7 @@ * @returns {string} the generated registry number. */ export function randomShipRegistryNumber() { - return "NCC-"+Math.floor(1000 + Math.random()*9000) + return 'NCC-' + Math.floor(1000 + Math.random() * 9000); } /** @@ -16,7 +16,7 @@ export function randomShipRegistryNumber() { * @returns {number} a stardate between 41000 (inclusive) and 42000 (exclusive). */ export function randomStardate() { - return 41000 + Math.random() * 1000 + return 41000 + Math.random() * 1000; } /** @@ -25,6 +25,6 @@ export function randomStardate() { * @returns {string} a one-letter planet class. */ export function randomPlanetClass() { - const planetClasses = ['D', 'H', 'J', 'K', 'L', 'M', 'N', 'R', 'T', 'Y'] - return planetClasses[Math.floor(Math.random() * 10)] + const planetClasses = ['D', 'H', 'J', 'K', 'L', 'M', 'N', 'R', 'T', 'Y']; + return planetClasses[Math.floor(Math.random() * 10)]; } diff --git a/exercises/concept/captains-log/captains-log.js b/exercises/concept/captains-log/captains-log.js index e4baa0c16d..b6bb7610f3 100644 --- a/exercises/concept/captains-log/captains-log.js +++ b/exercises/concept/captains-log/captains-log.js @@ -7,7 +7,9 @@ * @returns {string} the generated registry number. */ export function randomShipRegistryNumber() { - throw new Error("Please remove this line and implement the randomShipRegistryNumber() function"); + throw new Error( + 'Please remove this line and implement the randomShipRegistryNumber() function', + ); } /** @@ -16,15 +18,18 @@ export function randomShipRegistryNumber() { * @returns {number} a stardate between 41000 (inclusive) and 42000 (exclusive). */ export function randomStardate() { - throw new Error("Please remove this line and implement the randomStardate() function"); + throw new Error( + 'Please remove this line and implement the randomStardate() function', + ); } - /** * Generates a random planet class. * * @returns {string} a one-letter planet class. */ export function randomPlanetClass() { - throw new Error("Please remove this line and implement the randomStardate() function"); + throw new Error( + 'Please remove this line and implement the randomStardate() function', + ); } diff --git a/exercises/concept/captains-log/captains-log.spec.js b/exercises/concept/captains-log/captains-log.spec.js index 1fa43afa5c..f68fb9da1d 100644 --- a/exercises/concept/captains-log/captains-log.spec.js +++ b/exercises/concept/captains-log/captains-log.spec.js @@ -1,5 +1,9 @@ import { describe, expect, test } from '@jest/globals'; -import { randomShipRegistryNumber, randomStardate, randomPlanetClass } from './captains-log'; +import { + randomShipRegistryNumber, + randomStardate, + randomPlanetClass, +} from './captains-log'; describe('randomShipRegistryNumber', () => { test('registry numbers are valid', () => { @@ -15,14 +19,14 @@ describe('randomShipRegistryNumber', () => { function loadDie(...values) { const originalRandom = Math.random; - - Math.random = function loadedDie() { + + Math.random = function loadedDie() { if (values.length === 0) { return originalRandom(); } return values.shift(); }; - + return () => { Math.random = originalRandom; }; @@ -32,22 +36,22 @@ describe('randomStardate', () => { test('stardate is between 41000 and 42000', () => { const min = 0; const max = 1 - Number.EPSILON; - + // prettier-ignore const restore = loadDie( min, min, min, min, min, min, max, max, max, max, max, max, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5 ); - + for (let i = 0; i < 10_000; i++) { const starDate = randomStardate(); expect(starDate).toBeGreaterThanOrEqual(41_000); expect(starDate).toBeLessThan(42_000); } - + restore(); - }); + }); }); describe('randomPlanetClass', () => { @@ -62,12 +66,12 @@ describe('randomPlanetClass', () => { test('all planet classes can be returned', () => { const expected = 'DHJKLMNRTY'; const seen = {}; - + for (let i = 0; i < 1_000; i++) { const actual = randomPlanetClass(); seen[actual] = true; } - + expect(Object.keys(seen).length).toBe(expected.length); }); }); From 2d17cba465e15b6a048dc342982c4637daceac8c Mon Sep 17 00:00:00 2001 From: J R M Date: Thu, 19 Jun 2025 17:52:20 +0200 Subject: [PATCH 39/50] Fix broken test If `max` is 1 - Math.epsilon, the result is indistinguishable from 42000, and the tests fail. To fix this, Math.epsilon must be multiplied by more than 16. --- exercises/concept/captains-log/captains-log.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/concept/captains-log/captains-log.spec.js b/exercises/concept/captains-log/captains-log.spec.js index f68fb9da1d..5cfd79d0bb 100644 --- a/exercises/concept/captains-log/captains-log.spec.js +++ b/exercises/concept/captains-log/captains-log.spec.js @@ -35,7 +35,7 @@ function loadDie(...values) { describe('randomStardate', () => { test('stardate is between 41000 and 42000', () => { const min = 0; - const max = 1 - Number.EPSILON; + const max = 1 - Number.EPSILON * 32; // prettier-ignore const restore = loadDie( From 8c7d877664a02a9e0e17981e63679d2b92386b17 Mon Sep 17 00:00:00 2001 From: J R M Date: Fri, 20 Jun 2025 09:01:06 +0200 Subject: [PATCH 40/50] Create .gitignore --- exercises/concept/captains-log/.gitignore | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 exercises/concept/captains-log/.gitignore diff --git a/exercises/concept/captains-log/.gitignore b/exercises/concept/captains-log/.gitignore new file mode 100644 index 0000000000..0c88ff6ec3 --- /dev/null +++ b/exercises/concept/captains-log/.gitignore @@ -0,0 +1,5 @@ +/node_modules +/bin/configlet +/bin/configlet.exe +/package-lock.json +/yarn.lock From 4d943eb82797ddad5043ef26054f223fb207c386 Mon Sep 17 00:00:00 2001 From: J R M Date: Fri, 20 Jun 2025 09:01:31 +0200 Subject: [PATCH 41/50] Create .npmrc --- exercises/concept/captains-log/.npmrc | 1 + 1 file changed, 1 insertion(+) create mode 100644 exercises/concept/captains-log/.npmrc diff --git a/exercises/concept/captains-log/.npmrc b/exercises/concept/captains-log/.npmrc new file mode 100644 index 0000000000..d26df800bb --- /dev/null +++ b/exercises/concept/captains-log/.npmrc @@ -0,0 +1 @@ +audit=false From 8bdd28b72a77c5767c1f800898772e473ca5d090 Mon Sep 17 00:00:00 2001 From: J R M Date: Fri, 20 Jun 2025 09:02:18 +0200 Subject: [PATCH 42/50] Create LICENSE --- exercises/concept/captains-log/LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 exercises/concept/captains-log/LICENSE diff --git a/exercises/concept/captains-log/LICENSE b/exercises/concept/captains-log/LICENSE new file mode 100644 index 0000000000..90e73be03b --- /dev/null +++ b/exercises/concept/captains-log/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Exercism + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 65b9982b7df54f966274741957fe19dded9d647d Mon Sep 17 00:00:00 2001 From: J R M Date: Fri, 20 Jun 2025 09:02:54 +0200 Subject: [PATCH 43/50] Create babel.config.js --- exercises/concept/captains-log/babel.config.js | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 exercises/concept/captains-log/babel.config.js diff --git a/exercises/concept/captains-log/babel.config.js b/exercises/concept/captains-log/babel.config.js new file mode 100644 index 0000000000..a638497df1 --- /dev/null +++ b/exercises/concept/captains-log/babel.config.js @@ -0,0 +1,4 @@ +module.exports = { + presets: [['@exercism/babel-preset-javascript', { corejs: '3.40' }]], + plugins: [], +}; From a786e471b033c8946efd100df60ad3d49b8e136c Mon Sep 17 00:00:00 2001 From: J R M Date: Fri, 20 Jun 2025 09:03:37 +0200 Subject: [PATCH 44/50] Create eslint.config.mjs --- .../concept/captains-log/eslint.config.mjs | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 exercises/concept/captains-log/eslint.config.mjs diff --git a/exercises/concept/captains-log/eslint.config.mjs b/exercises/concept/captains-log/eslint.config.mjs new file mode 100644 index 0000000000..ca517111ed --- /dev/null +++ b/exercises/concept/captains-log/eslint.config.mjs @@ -0,0 +1,45 @@ +// @ts-check + +import config from '@exercism/eslint-config-javascript'; +import maintainersConfig from '@exercism/eslint-config-javascript/maintainers.mjs'; + +import globals from 'globals'; + +export default [ + ...config, + ...maintainersConfig, + { + files: maintainersConfig[1].files, + rules: { + 'jest/expect-expect': ['warn', { assertFunctionNames: ['expect*'] }], + }, + }, + { + files: ['scripts/**/*.mjs'], + languageOptions: { + globals: { + ...globals.node, + }, + }, + }, + // <> + { + ignores: [ + // # Protected or generated + '/.appends/**/*', + '/.github/**/*', + '/.vscode/**/*', + + // # Binaries + '/bin/*', + + // # Configuration + '/config', + '/babel.config.js', + + // # Typings + '/exercises/**/global.d.ts', + '/exercises/**/env.d.ts', + ], + }, +]; From e15e8627058b3b62899568ca666d1c5be1c55007 Mon Sep 17 00:00:00 2001 From: J R M Date: Fri, 20 Jun 2025 09:04:08 +0200 Subject: [PATCH 45/50] Create jest.config.js --- exercises/concept/captains-log/jest.config.js | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 exercises/concept/captains-log/jest.config.js diff --git a/exercises/concept/captains-log/jest.config.js b/exercises/concept/captains-log/jest.config.js new file mode 100644 index 0000000000..ec8e908127 --- /dev/null +++ b/exercises/concept/captains-log/jest.config.js @@ -0,0 +1,22 @@ +module.exports = { + verbose: true, + projects: [''], + testMatch: [ + '**/__tests__/**/*.[jt]s?(x)', + '**/test/**/*.[jt]s?(x)', + '**/?(*.)+(spec|test).[jt]s?(x)', + ], + testPathIgnorePatterns: [ + '/(?:production_)?node_modules/', + '.d.ts$', + '/test/fixtures', + '/test/helpers', + '__mocks__', + ], + transform: { + '^.+\\.[jt]sx?$': 'babel-jest', + }, + moduleNameMapper: { + '^(\\.\\/.+)\\.js$': '$1', + }, +}; From 8e45315234a7a8a3f0f52fc244448a4e075cec12 Mon Sep 17 00:00:00 2001 From: J R M Date: Fri, 20 Jun 2025 09:12:32 +0200 Subject: [PATCH 46/50] Create package.json Not sure if I got this one entirely right. --- exercises/concept/captains-log/package.json | 38 +++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 exercises/concept/captains-log/package.json diff --git a/exercises/concept/captains-log/package.json b/exercises/concept/captains-log/package.json new file mode 100644 index 0000000000..8436edb585 --- /dev/null +++ b/exercises/concept/captains-log/package.json @@ -0,0 +1,38 @@ +{ + "name": "@exercism/javascript-captains-log", + "description": "Exercism concept exercise on randomness", + "author": "J R M (https://github.com/quintuple-mallard)", + "contributors": [ + "Derk-Jan Karrenbeld (https://derk-jan.com)", + "Cool-Katt (https://github.com/Cool-Katt)" + ], + "private": true, + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/exercism/javascript", + "directory": "exercises/concept/captains-log" + }, + "devDependencies": { + "@exercism/babel-preset-javascript": "^0.5.1", + "@exercism/eslint-config-javascript": "^0.8.1", + "@jest/globals": "^29.7.0", + "@types/node": "^22.15.29", + "@types/shelljs": "^0.8.16", + "babel-jest": "^29.7.0", + "core-js": "~3.42.0", + "diff": "^8.0.2", + "eslint": "^9.28.0", + "expect": "^29.7.0", + "globals": "^16.2.0", + "jest": "^29.7.0" + }, + "dependencies": {}, + "scripts": { + "lint": "corepack pnpm eslint .", + "test": "corepack pnpm jest", + "watch": "corepack pnpm jest --watch", + "format": "corepack pnpm prettier -w ." + }, + "packageManager": "pnpm@9.15.2" +} From 10f181e266446f3fdba80645e53b9e8a3ecc5ed7 Mon Sep 17 00:00:00 2001 From: J R M Date: Fri, 20 Jun 2025 20:21:39 +0200 Subject: [PATCH 47/50] Add line break in exercises/concept/captains-log/.docs/instructions.md Co-authored-by: Victor Goff --- exercises/concept/captains-log/.docs/instructions.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/exercises/concept/captains-log/.docs/instructions.md b/exercises/concept/captains-log/.docs/instructions.md index e7d765c39c..4f251dabcb 100644 --- a/exercises/concept/captains-log/.docs/instructions.md +++ b/exercises/concept/captains-log/.docs/instructions.md @@ -34,7 +34,8 @@ randomStardate(); The Starship Enterprise encounters many planets in its travels. Planets in the Star Trek universe are split into categories based on their properties. For example, Earth is a class M planet. All possible planetary classes are: D, H, J, K, L, M, N, R, T, and Y. -Implement the randomPlanetClassfunction. It should return one of the planetary classes at random. +Implement the randomPlanetClassfunction. + It should return one of the planetary classes at random. ```javascript randomPlanetClass(); From 4c3e7470c6fc96fd93f07952d8642793e51d262e Mon Sep 17 00:00:00 2001 From: J R M Date: Fri, 20 Jun 2025 20:27:22 +0200 Subject: [PATCH 48/50] Added line breaks to instructions.md --- .../captains-log/.docs/instructions.md | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/exercises/concept/captains-log/.docs/instructions.md b/exercises/concept/captains-log/.docs/instructions.md index 4f251dabcb..61fdb8c056 100644 --- a/exercises/concept/captains-log/.docs/instructions.md +++ b/exercises/concept/captains-log/.docs/instructions.md @@ -1,12 +1,16 @@ ## Instructions -Mary is a big fan of the TV series Star Trek: The Next Generation. She often plays pen-and-paper role playing games, where she and her friends pretend to be the crew of the Starship Enterprise. Mary's character is Captain Picard, which means she has to keep the captain's log. She loves the creative part of the game, but doesn't like to generate random data on the spot. +Mary is a big fan of the TV series Star Trek: The Next Generation. +She often plays pen-and-paper role playing games, where she and her friends pretend to be the crew of the Starship Enterprise. +Mary's character is Captain Picard, which means she has to keep the captain's log. +She loves the creative part of the game, but doesn't like to generate random data on the spot. Help Mary by creating random generators for data commonly appearing in the captain's log. ### 1. Generate a random starship registry number -Enterprise (registry number NCC-1701) is not the only starship flying around! When it rendezvous with another starship, Mary needs to log the registry number of that starship. +Enterprise (registry number NCC-1701) is not the only starship flying around! +When it rendezvous with another starship, Mary needs to log the registry number of that starship. Registry numbers start with the prefix "NCC-" and then use a number from 1000 to 9999 (both inclusive). @@ -21,7 +25,9 @@ randomShipRegistryNumber(); What's the use of a log if it doesn't include dates? -A stardate is a floating point number. The adventures of the Starship Enterprise from the first season of The Next Generation take place between the stardates 41000.0 and 42000.0. The "4" stands for the 24th century, the "1" for the first season. +A stardate is a floating point number. +The adventures of the Starship Enterprise from the first season of The Next Generation take place between the stardates 41000.0 and 42000.0. +The "4" stands for the 24th century, the "1" for the first season. Implement the function randomStardate that returns a floating point number between 41000.0 (inclusive) and 42000.0 (exclusive). @@ -32,10 +38,13 @@ randomStardate(); ### 3. Generate a random planet -The Starship Enterprise encounters many planets in its travels. Planets in the Star Trek universe are split into categories based on their properties. For example, Earth is a class M planet. All possible planetary classes are: D, H, J, K, L, M, N, R, T, and Y. +The Starship Enterprise encounters many planets in its travels. +Planets in the Star Trek universe are split into categories based on their properties. +For example, Earth is a class M planet. +All possible planetary classes are: D, H, J, K, L, M, N, R, T, and Y. Implement the randomPlanetClassfunction. - It should return one of the planetary classes at random. +It should return one of the planetary classes at random. ```javascript randomPlanetClass(); From 1fd3f142ee70d21fd0cd7aa312da46a2d61ad45d Mon Sep 17 00:00:00 2001 From: Derk-Jan Karrenbeld Date: Fri, 20 Jun 2025 22:38:38 +0200 Subject: [PATCH 49/50] Apply suggestions from code review --- concepts/randomness/.meta/config.json | 2 +- concepts/randomness/about.md | 36 ++++++++++++++----- concepts/randomness/introduction.md | 16 ++++----- .../captains-log/.docs/instructions.md | 6 ++-- .../captains-log/.docs/introduction.md | 27 ++++---------- .../concept/captains-log/.meta/config.json | 3 ++ .../concept/captains-log/.meta/exemplar.js | 8 ++--- .../concept/captains-log/captains-log.js | 1 - 8 files changed, 54 insertions(+), 45 deletions(-) diff --git a/concepts/randomness/.meta/config.json b/concepts/randomness/.meta/config.json index 942b99ea09..1b2ce91b6f 100644 --- a/concepts/randomness/.meta/config.json +++ b/concepts/randomness/.meta/config.json @@ -1,5 +1,5 @@ { "blurb": "Random number generation using Math.random()", "authors": ["SneakyMallard"], - "contributors":[] + "contributors": ["SleeplessByte"] } diff --git a/concepts/randomness/about.md b/concepts/randomness/about.md index bae9d8d195..e5f50cfb09 100644 --- a/concepts/randomness/about.md +++ b/concepts/randomness/about.md @@ -1,6 +1,6 @@ # Introduction -Many programs need (apparently) random values to simulate real-world events. +Many programs need (pseudo-)random values to simulate real-world events. Common, familiar examples include: @@ -9,7 +9,25 @@ Common, familiar examples include: - Shuffling a deck of cards: a random ordering of a card list. - The creation of trees and bushes in a 3-D graphics simulation. -Generating truly random values with a computer is a [surprisingly difficult technical challenge][why-randomness-is-hard], so you may see these results referred to as "pseudorandom". +Generating truly random values with a computer is a [surprisingly difficult technical challenge][why-randomness-is-hard], which is why there are also "pseudorandom" generators. + + +~~~exercism/advanced +[The language specification][spec] for JavaScript doesn't force the implementation for random number generation. +All major browsers and JavaScript runtimes implement a PRNG (pseudo-random number generator). +Because the numbers are not cryptographically secure, they should never be used for anything that requires true or at least cryptographically secure random numbers, such as certificate or password generation or operations. + +There is a standard called [Web Cryptography][rfc] which standardizes an interface for doing cryptography in JavaScript. +It is implemented [by Browsers][crypto-web] as well as runtimes such as [Node.JS][crypto-node] and [Deno][crypto-deno]. + +This concept is not about Web Crypto and will restrict itself to pseudo-random number generation. + +[rfc]: https://www.w3.org/TR/webcrypto-2/ +[spec]: https://tc39.es/ecma262/multipage/numbers-and-dates.html#sec-math.random +[crypto-web]: https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues +[crypto-node]: https://nodejs.org/api/webcrypto.html#cryptogetrandomvaluestypedarray +[crypto-deno]: https://docs.deno.com/api/web/~/Crypto +~~~ ## Generating random numbers @@ -26,16 +44,18 @@ getRandomInRange(4, 10); // => 5.72 ``` + +~~~exercism/advanced +Most simple techniques of returning a range of numbers based on the randomly generated number [will introduce bias][bias]. +That means that some numbers will be more likely to be rolled than others. +Using the multiplication technique spreads out the bias over the entire range, so it will be less obvious and in most cases not a big issue, but you should be aware of this. + +[bias]: https://adammil.net/blog/v134_Efficiently_generating_random_numbers_without_bias.html +~~~ ## Generating random integers To generate a random integer, you can use `Math.floor()` or `Math.ceil()` to turn a randomly generated number into an integer. -```exercism/caution - -The `Math.random()` function should NOT be used for security and cryptographic applications!! - -Instead, you can use the Web Crypto API, which provides various cryptographic functions. -``` [why-randomness-is-hard]: https://www.malwarebytes.com/blog/news/2013/09/in-computers-are-random-numbers-really-random [Math.random]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random diff --git a/concepts/randomness/introduction.md b/concepts/randomness/introduction.md index bae9d8d195..fad9bfc26c 100644 --- a/concepts/randomness/introduction.md +++ b/concepts/randomness/introduction.md @@ -1,6 +1,6 @@ # Introduction -Many programs need (apparently) random values to simulate real-world events. +Many programs need (pseudo-)random values to simulate real-world events. Common, familiar examples include: @@ -9,7 +9,13 @@ Common, familiar examples include: - Shuffling a deck of cards: a random ordering of a card list. - The creation of trees and bushes in a 3-D graphics simulation. -Generating truly random values with a computer is a [surprisingly difficult technical challenge][why-randomness-is-hard], so you may see these results referred to as "pseudorandom". +Generating truly random values with a computer is a [surprisingly difficult technical challenge][why-randomness-is-hard], which is why there are also "pseudorandom" generators. + + +~~~exercism/caution +The `Math.random()` function should NOT be used for security and cryptographic applications! +Finish the learning exercise(s) about this concept to learn more +~~~ ## Generating random numbers @@ -30,12 +36,6 @@ getRandomInRange(4, 10); To generate a random integer, you can use `Math.floor()` or `Math.ceil()` to turn a randomly generated number into an integer. -```exercism/caution - -The `Math.random()` function should NOT be used for security and cryptographic applications!! - -Instead, you can use the Web Crypto API, which provides various cryptographic functions. -``` [why-randomness-is-hard]: https://www.malwarebytes.com/blog/news/2013/09/in-computers-are-random-numbers-really-random [Math.random]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random diff --git a/exercises/concept/captains-log/.docs/instructions.md b/exercises/concept/captains-log/.docs/instructions.md index 61fdb8c056..f4a1eea518 100644 --- a/exercises/concept/captains-log/.docs/instructions.md +++ b/exercises/concept/captains-log/.docs/instructions.md @@ -14,7 +14,7 @@ When it rendezvous with another starship, Mary needs to log the registry number Registry numbers start with the prefix "NCC-" and then use a number from 1000 to 9999 (both inclusive). -Implement the randomShipRegistryNumber() function that returns a random starship registry number. +Implement the `randomShipRegistryNumber()` function that returns a random starship registry number. ```javascript randomShipRegistryNumber(); @@ -29,7 +29,7 @@ A stardate is a floating point number. The adventures of the Starship Enterprise from the first season of The Next Generation take place between the stardates 41000.0 and 42000.0. The "4" stands for the 24th century, the "1" for the first season. -Implement the function randomStardate that returns a floating point number between 41000.0 (inclusive) and 42000.0 (exclusive). +Implement the function `randomStardate` that returns a floating point number between 41000.0 (inclusive) and 42000.0 (exclusive). ```javascript randomStardate(); @@ -43,7 +43,7 @@ Planets in the Star Trek universe are split into categories based on their prope For example, Earth is a class M planet. All possible planetary classes are: D, H, J, K, L, M, N, R, T, and Y. -Implement the randomPlanetClassfunction. +Implement the `randomPlanetClass()` function. It should return one of the planetary classes at random. ```javascript diff --git a/exercises/concept/captains-log/.docs/introduction.md b/exercises/concept/captains-log/.docs/introduction.md index bae9d8d195..fc924c790c 100644 --- a/exercises/concept/captains-log/.docs/introduction.md +++ b/exercises/concept/captains-log/.docs/introduction.md @@ -1,6 +1,6 @@ # Introduction -Many programs need (apparently) random values to simulate real-world events. +Many programs need (pseudo-)random values to simulate real-world events. Common, familiar examples include: @@ -9,33 +9,20 @@ Common, familiar examples include: - Shuffling a deck of cards: a random ordering of a card list. - The creation of trees and bushes in a 3-D graphics simulation. -Generating truly random values with a computer is a [surprisingly difficult technical challenge][why-randomness-is-hard], so you may see these results referred to as "pseudorandom". +Generating truly random values with a computer is a [surprisingly difficult technical challenge][why-randomness-is-hard], which is why there are also "pseudorandom" generators. + +~~~exercism/caution +The `Math.random()` function should NOT be used for security and cryptographic applications! +Finish the learning exercise(s) about this concept to learn more +~~~ ## Generating random numbers In Javascript, you can generate psuedorandom numbers using the [`Math.random()`][Math.random] function. It will return a psuedorandom floating-point number between 0 (inclusive), and 1 (exclusive). -To get a random number between _min_ (inclusive) and _max_ (exclusive) you can use a function something like this: -```javascript -function getRandomInRange(min, max) { - return min + Math.random() * (max - min); -} -getRandomInRange(4, 10); -// => 5.72 -``` -## Generating random integers - -To generate a random integer, you can use `Math.floor()` or `Math.ceil()` to turn a randomly generated number into an integer. - -```exercism/caution - -The `Math.random()` function should NOT be used for security and cryptographic applications!! - -Instead, you can use the Web Crypto API, which provides various cryptographic functions. -``` [why-randomness-is-hard]: https://www.malwarebytes.com/blog/news/2013/09/in-computers-are-random-numbers-really-random [Math.random]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random diff --git a/exercises/concept/captains-log/.meta/config.json b/exercises/concept/captains-log/.meta/config.json index 205abf7f2e..9a9cff01f5 100644 --- a/exercises/concept/captains-log/.meta/config.json +++ b/exercises/concept/captains-log/.meta/config.json @@ -2,6 +2,9 @@ "authors": [ "SneakyMallard" ], + "contributors": [ + "SleeplessByte" + ], "files": { "solution": [ "captains-log.js" diff --git a/exercises/concept/captains-log/.meta/exemplar.js b/exercises/concept/captains-log/.meta/exemplar.js index 7d48ea4b41..88566a4fea 100644 --- a/exercises/concept/captains-log/.meta/exemplar.js +++ b/exercises/concept/captains-log/.meta/exemplar.js @@ -1,4 +1,3 @@ -/// // @ts-check /** @@ -7,7 +6,7 @@ * @returns {string} the generated registry number. */ export function randomShipRegistryNumber() { - return 'NCC-' + Math.floor(1000 + Math.random() * 9000); + return `NCC-${Math.floor(1000 + Math.random() * 9000)}`; } /** @@ -19,12 +18,13 @@ export function randomStardate() { return 41000 + Math.random() * 1000; } +const PLANET_CLASSES = 'DHJKLMNRTY'; + /** * Generates a random planet class. * * @returns {string} a one-letter planet class. */ export function randomPlanetClass() { - const planetClasses = ['D', 'H', 'J', 'K', 'L', 'M', 'N', 'R', 'T', 'Y']; - return planetClasses[Math.floor(Math.random() * 10)]; + return PLANET_CLASSES[Math.floor(Math.random() * PLANET_CLASSES.length)]; } diff --git a/exercises/concept/captains-log/captains-log.js b/exercises/concept/captains-log/captains-log.js index b6bb7610f3..978cff64fd 100644 --- a/exercises/concept/captains-log/captains-log.js +++ b/exercises/concept/captains-log/captains-log.js @@ -1,4 +1,3 @@ -/// // @ts-check /** From eebe50a28176a2732ac5084d8c46d42a63c4389b Mon Sep 17 00:00:00 2001 From: Derk-Jan Karrenbeld Date: Fri, 20 Jun 2025 22:42:38 +0200 Subject: [PATCH 50/50] Format --- concepts/randomness/about.md | 2 +- concepts/randomness/introduction.md | 1 - exercises/concept/captains-log/.docs/introduction.md | 4 +--- exercises/concept/captains-log/.meta/exemplar.js | 4 ++-- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/concepts/randomness/about.md b/concepts/randomness/about.md index e5f50cfb09..d09087ffd8 100644 --- a/concepts/randomness/about.md +++ b/concepts/randomness/about.md @@ -52,10 +52,10 @@ Using the multiplication technique spreads out the bias over the entire range, s [bias]: https://adammil.net/blog/v134_Efficiently_generating_random_numbers_without_bias.html ~~~ + ## Generating random integers To generate a random integer, you can use `Math.floor()` or `Math.ceil()` to turn a randomly generated number into an integer. - [why-randomness-is-hard]: https://www.malwarebytes.com/blog/news/2013/09/in-computers-are-random-numbers-really-random [Math.random]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random diff --git a/concepts/randomness/introduction.md b/concepts/randomness/introduction.md index fad9bfc26c..79b03703b6 100644 --- a/concepts/randomness/introduction.md +++ b/concepts/randomness/introduction.md @@ -36,6 +36,5 @@ getRandomInRange(4, 10); To generate a random integer, you can use `Math.floor()` or `Math.ceil()` to turn a randomly generated number into an integer. - [why-randomness-is-hard]: https://www.malwarebytes.com/blog/news/2013/09/in-computers-are-random-numbers-really-random [Math.random]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random diff --git a/exercises/concept/captains-log/.docs/introduction.md b/exercises/concept/captains-log/.docs/introduction.md index fc924c790c..12bf08e3e8 100644 --- a/exercises/concept/captains-log/.docs/introduction.md +++ b/exercises/concept/captains-log/.docs/introduction.md @@ -10,6 +10,7 @@ Common, familiar examples include: - The creation of trees and bushes in a 3-D graphics simulation. Generating truly random values with a computer is a [surprisingly difficult technical challenge][why-randomness-is-hard], which is why there are also "pseudorandom" generators. + ~~~exercism/caution The `Math.random()` function should NOT be used for security and cryptographic applications! @@ -21,8 +22,5 @@ Finish the learning exercise(s) about this concept to learn more In Javascript, you can generate psuedorandom numbers using the [`Math.random()`][Math.random] function. It will return a psuedorandom floating-point number between 0 (inclusive), and 1 (exclusive). - - - [why-randomness-is-hard]: https://www.malwarebytes.com/blog/news/2013/09/in-computers-are-random-numbers-really-random [Math.random]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random diff --git a/exercises/concept/captains-log/.meta/exemplar.js b/exercises/concept/captains-log/.meta/exemplar.js index 88566a4fea..0488199d31 100644 --- a/exercises/concept/captains-log/.meta/exemplar.js +++ b/exercises/concept/captains-log/.meta/exemplar.js @@ -19,12 +19,12 @@ export function randomStardate() { } const PLANET_CLASSES = 'DHJKLMNRTY'; - + /** * Generates a random planet class. * * @returns {string} a one-letter planet class. */ export function randomPlanetClass() { - return PLANET_CLASSES[Math.floor(Math.random() * PLANET_CLASSES.length)]; + return PLANET_CLASSES[Math.floor(Math.random() * PLANET_CLASSES.length)]; }