feat(curriculum): daily challenges 90-99 (#62925)

Co-authored-by: Ilenia <26656284+ilenia-magoni@users.noreply.github.com>
Co-authored-by: Huyen Nguyen <25715018+huyenltnguyen@users.noreply.github.com>
This commit is contained in:
Tom
2025-11-03 10:41:36 -06:00
committed by GitHub
parent 5124412827
commit cf9a19746d
23 changed files with 1782 additions and 1 deletions

View File

@@ -0,0 +1,59 @@
---
id: 68f6587287ad1f4ad39b0c7c
title: "Challenge 90: Character Limit"
challengeType: 28
dashedName: challenge-90
---
# --description--
In this challenge, you are given a string and need to determine if it fits in a social media post. Return the following strings based on the rules given:
- `"short post"` if it fits within a 40-character limit.
- `"long post"` if it's greater than 40 characters and fits within an 80-character limit.
- `"invalid post"` if it's too long to fit within either limit.
# --hints--
`canPost("Hello world")` should return `"short post"`.
```js
assert.equal(canPost("Hello world"), "short post");
```
`canPost("This is a longer message but still under eighty characters.")` should return `"long post"`.
```js
assert.equal(canPost("This is a longer message but still under eighty characters."), "long post");
```
`canPost("This message is too long to fit into either of the character limits for a social media post.")` should return `"invalid post"`.
```js
assert.equal(canPost("This message is too long to fit into either of the character limits for a social media post."), "invalid post");
```
# --seed--
## --seed-contents--
```js
function canPost(message) {
return message;
}
```
# --solutions--
```js
function canPost(message) {
if (message.length <= 40) {
return "short post"
} else if (message.length <= 80) {
return "long post"
} else {
return "invalid post"
}
}
```

View File

@@ -0,0 +1,112 @@
---
id: 68f6587287ad1f4ad39b0c7d
title: "Challenge 91: Word Search"
challengeType: 28
dashedName: challenge-91
---
# --description--
Given a matrix (an array of arrays) of single letters and a word to find, return the start and end indices of the word in the matrix.
- The given matrix will be filled with all lowercase letters (`a-z`).
- The word to find will always be in the matrix exactly once.
- The word to find will always be in a straight line in one of these directions:
- left to right
- right to left
- top to bottom
- bottom to top
For example, given the matrix:
```md
[
["a", "c", "t"],
["t", "a", "t"],
["c", "t", "c"]
]
```
And the word `"cat"`, return:
```md
[[0, 1], [2, 1]]
```
Where `[0, 1]` are the indices for the `"c"` (start of the word), and `[2, 1]` are the indices for the `"t"` (end of the word).
# --hints--
`findWord([["a", "c", "t"], ["t", "a", "t"], ["c", "t", "c"]], "cat")` should return `[[0, 1], [2, 1]]`.
```js
assert.deepEqual(findWord([["a", "c", "t"], ["t", "a", "t"], ["c", "t", "c"]], "cat"), [[0, 1], [2, 1]]);
```
`findWord([["d", "o", "g"], ["o", "g", "d"], ["d", "g", "o"]], "dog")` should return `[[0, 0], [0, 2]]`.
```js
assert.deepEqual(findWord([["d", "o", "g"], ["o", "g", "d"], ["d", "g", "o"]], "dog"), [[0, 0], [0, 2]]);
```
`findWord([["h", "i", "s", "h"], ["i", "s", "f", "s"], ["f", "s", "i", "i"], ["s", "h", "i", "f"]], "fish")` should return `[[3, 3], [0, 3]]`.
```js
assert.deepEqual(findWord([["h", "i", "s", "h"], ["i", "s", "f", "s"], ["f", "s", "i", "i"], ["s", "h", "i", "f"]], "fish"), [[3, 3], [0, 3]]);
```
`findWord([["f", "x", "o", "x"], ["o", "x", "o", "f"], ["f", "o", "f", "x"], ["f", "x", "x", "o"]], "fox")` should return `[[1, 3], [1, 1]]`.
```js
assert.deepEqual(findWord([["f", "x", "o", "x"], ["o", "x", "o", "f"], ["f", "o", "f", "x"], ["f", "x", "x", "o"]], "fox"), [[1, 3], [1, 1]]);
```
# --seed--
## --seed-contents--
```js
function findWord(matrix, word) {
return matrix;
}
```
# --solutions--
```js
function findWord(matrix, word) {
const rows = matrix.length;
const cols = matrix[0].length;
const len = word.length;
const directions = [
[0, 1],
[0, -1],
[1, 0],
[-1, 0]
];
for (let r = 0; r < rows; r++) {
for (let c = 0; c < cols; c++) {
for (let [dr, dc] of directions) {
let match = true;
for (let i = 0; i < len; i++) {
const nr = r + dr * i;
const nc = c + dc * i;
if (nr < 0 || nr >= rows || nc < 0 || nc >= cols || matrix[nr][nc] !== word[i]) {
match = false;
break;
}
}
if (match) {
return [
[r, c],
[r + dr * (len - 1), c + dc * (len - 1)]
];
}
}
}
}
}
```

View File

@@ -0,0 +1,77 @@
---
id: 68f6587287ad1f4ad39b0c7e
title: "Challenge 92: Extension Extractor"
challengeType: 28
dashedName: challenge-92
---
# --description--
Given a string representing a filename, return the extension of the file.
- The extension is the part of the filename that comes after the last period (`.`).
- If the filename does not contain a period or ends with a period, return `"none"`.
- The extension should be returned as-is, preserving case.
# --hints--
`getExtension("document.txt")` should return `"txt"`.
```js
assert.equal(getExtension("document.txt"), "txt");
```
`getExtension("README")` should return `"none"`.
```js
assert.equal(getExtension("README"), "none");
```
`getExtension("image.PNG")` should return `"PNG"`.
```js
assert.equal(getExtension("image.PNG"), "PNG");
```
`getExtension(".gitignore")` should return `"gitignore"`.
```js
assert.equal(getExtension(".gitignore"), "gitignore");
```
`getExtension("archive.tar.gz")` should return `"gz"`.
```js
assert.equal(getExtension("archive.tar.gz"), "gz");
```
`getExtension("final.draft.")` should return `"none"`.
```js
assert.equal(getExtension("final.draft."), "none");
```
# --seed--
## --seed-contents--
```js
function getExtension(filename) {
return filename;
}
```
# --solutions--
```js
function getExtension(filename) {
const lastDot = filename.lastIndexOf('.');
if (lastDot === -1 || lastDot === filename.length - 1) {
return "none";
}
return filename.slice(lastDot + 1);
}
```

View File

@@ -0,0 +1,86 @@
---
id: 68f6587287ad1f4ad39b0c7f
title: "Challenge 93: Vowels and Consonants"
challengeType: 28
dashedName: challenge-93
---
# --description--
Given a string, return an array with the number of vowels and number of consonants in the string.
- Vowels consist of `a`, `e`, `i`, `o`, `u` in any case.
- Consonants consist of all other letters in any case.
- Ignore any non-letter characters.
For example, given `"Hello World"`, return `[3, 7]`.
# --hints--
`count("Hello World")` should return `[3, 7]`.
```js
assert.deepEqual(count("Hello World"), [3, 7]);
```
`count("JavaScript")` should return `[3, 7]`.
```js
assert.deepEqual(count("JavaScript"), [3, 7]);
```
`count("Python")` should return `[1, 5]`.
```js
assert.deepEqual(count("Python"), [1, 5]);
```
`count("freeCodeCamp")` should return `[5, 7]`.
```js
assert.deepEqual(count("freeCodeCamp"), [5, 7]);
```
`count("Hello, World!")` should return `[3, 7]`.
```js
assert.deepEqual(count("Hello, World!"), [3, 7]);
```
`count("The quick brown fox jumps over the lazy dog.")` should return `[11, 24]`.
```js
assert.deepEqual(count("The quick brown fox jumps over the lazy dog."), [11, 24]);
```
# --seed--
## --seed-contents--
```js
function count(str) {
return str;
}
```
# --solutions--
```js
function count(str) {
const vowels = 'aeiou';
const consonants = 'bcdfghjklmnpqrstvwxyz';
let v = 0, c = 0;
for (let i=0; i<str.length; i++) {
if (vowels.includes(str[i].toLowerCase())) {
v++;
}
if (consonants.includes(str[i].toLowerCase())) {
c++;
}
}
return [v, c];
}
```

View File

@@ -0,0 +1,80 @@
---
id: 68f6587287ad1f4ad39b0c80
title: "Challenge 94: Email Signature Generator"
challengeType: 28
dashedName: challenge-94
---
# --description--
Given strings for a person's name, title, and company, return an email signature as a single string using the following rules:
- The name should appear first, preceded by a prefix that depends on the first letter of the name. For names starting with (case-insensitive):
- `A-I`: Use `>>` as the prefix.
- `J-R`: Use `--` as the prefix.
- `S-Z`: Use `::` as the prefix.
- A comma and space (`, `) should follow the name.
- The title and company should follow the comma and space, separated by `" at "` (with spaces around it).
For example, given `"Quinn Waverly"`, `"Founder and CEO"`, and `"TechCo"` return `"--Quinn Waverly, Founder and CEO at TechCo"`.
# --hints--
`generateSignature("Quinn Waverly", "Founder and CEO", "TechCo")` should return `"--Quinn Waverly, Founder and CEO at TechCo"`.
```js
assert.equal(generateSignature("Quinn Waverly", "Founder and CEO", "TechCo"), "--Quinn Waverly, Founder and CEO at TechCo");
```
`generateSignature("Alice Reed", "Engineer", "TechCo")` should return `">>Alice Reed, Engineer at TechCo"`.
```js
assert.equal(generateSignature("Alice Reed", "Engineer", "TechCo"), ">>Alice Reed, Engineer at TechCo");
```
`generateSignature("Tina Vaughn", "Developer", "example.com")` should return `"::Tina Vaughn,Developer at example.com"`.
```js
assert.equal(generateSignature("Tina Vaughn", "Developer", "example.com"), "::Tina Vaughn, Developer at example.com");
```
`generateSignature("B. B.", "Product Tester", "AcmeCorp")` should return `">>B. B., Product Tester at AcmeCorp"`.
```js
assert.equal(generateSignature("B. B.", "Product Tester", "AcmeCorp"), ">>B. B., Product Tester at AcmeCorp");
```
`generateSignature("windstorm", "Cloud Architect", "Atmospheronics")` should return `"::windstorm, Cloud Architect at Atmospheronics"`.
```js
assert.equal(generateSignature("windstorm", "Cloud Architect", "Atmospheronics"), "::windstorm, Cloud Architect at Atmospheronics");
```
# --seed--
## --seed-contents--
```js
function generateSignature(name, title, company) {
return name;
}
```
# --solutions--
```js
function generateSignature(name, title, company) {
const firstLetter = name[0].toUpperCase();
let prefix;
if ("ABCDEFGHI".includes(firstLetter)) {
prefix = ">>";
} else if ("JKLMNOPQR".includes(firstLetter)) {
prefix = "--";
} else {
prefix = "::";
}
return `${prefix}${name}, ${title} at ${company}`;
}
```

View File

@@ -0,0 +1,71 @@
---
id: 68f6587287ad1f4ad39b0c81
title: "Challenge 95: Array Shift"
challengeType: 28
dashedName: challenge-95
---
# --description--
Given an array and an integer representing how many positions to shift the array, return the shifted array.
- A positive integer shifts the array to the left.
- A negative integer shifts the array to the right.
- The shift wraps around the array.
For example, given `[1, 2, 3]` and `1`, shift the array 1 to the left, returning `[2, 3, 1]`.
# --hints--
`shiftArray([1, 2, 3], 1)` should return `[2, 3, 1]`.
```js
assert.deepEqual(shiftArray([1, 2, 3], 1), [2, 3, 1]);
```
`shiftArray([1, 2, 3], -1)` should return `[3, 1, 2]`.
```js
assert.deepEqual(shiftArray([1, 2, 3], -1), [3, 1, 2]);
```
`shiftArray(["alpha", "bravo", "charlie"], 5)` should return `["charlie", "alpha", "bravo"]`.
```js
assert.deepEqual(shiftArray(["alpha", "bravo", "charlie"], 5), ["charlie", "alpha", "bravo"]);
```
`shiftArray(["alpha", "bravo", "charlie"], -11)` should return `["bravo", "charlie", "alpha"]`.
```js
assert.deepEqual(shiftArray(["alpha", "bravo", "charlie"], -11), ["bravo", "charlie", "alpha"]);
```
`shiftArray([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 15)` should return `[5, 6, 7, 8, 9, 0, 1, 2, 3, 4]`.
```js
assert.deepEqual(shiftArray([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 15), [5, 6, 7, 8, 9, 0, 1, 2, 3, 4]);
```
# --seed--
## --seed-contents--
```js
function shiftArray(arr, n) {
return arr;
}
```
# --solutions--
```js
function shiftArray(arr, n) {
const len = arr.length;
n = n % len;
if (n < 0) n += len;
return arr.slice(n).concat(arr.slice(0, n));
}
```

View File

@@ -0,0 +1,83 @@
---
id: 68f6587287ad1f4ad39b0c82
title: "Challenge 96: Is It the Weekend?"
challengeType: 28
dashedName: challenge-96
---
# --description--
Given a date in the format `"YYYY-MM-DD"`, return the number of days left until the weekend.
- The weekend starts on Saturday.
- If the given date is Saturday or Sunday, return `"It's the weekend!"`.
- Otherwise, return `"X days until the weekend."`, where `X` is the number of days until Saturday.
- If `X` is `1`, use `"day"` (singular) instead of `"days"` (plural).
- Make sure the calculation ignores your local timezone.
# --hints--
`daysUntilWeekend("2025-11-14")` should return `"1 day until the weekend."`.
```js
assert.equal(daysUntilWeekend("2025-11-14"), "1 day until the weekend.");
```
`daysUntilWeekend("2025-01-01")` should return `"3 days until the weekend."`.
```js
assert.equal(daysUntilWeekend("2025-01-01"), "3 days until the weekend.");
```
`daysUntilWeekend("2025-12-06")` should return `"It's the weekend!"`.
```js
assert.equal(daysUntilWeekend("2025-12-06"), "It's the weekend!");
```
`daysUntilWeekend("2026-01-27")` should return `"4 days until the weekend."`.
```js
assert.equal(daysUntilWeekend("2026-01-27"), "4 days until the weekend.");
```
`daysUntilWeekend("2026-09-07")` should return `"5 days until the weekend."`.
```js
assert.equal(daysUntilWeekend("2026-09-07"), "5 days until the weekend.");
```
`daysUntilWeekend("2026-11-29")` should return `"It's the weekend!"`.
```js
assert.equal(daysUntilWeekend("2026-11-29"), "It's the weekend!");
```
# --seed--
## --seed-contents--
```js
function daysUntilWeekend(dateString) {
return dateString;
}
```
# --solutions--
```js
function daysUntilWeekend(dateString) {
const [year, month, day] = dateString.split("-").map(Number);
const date = new Date(Date.UTC(year, month - 1, day));
const dayOfWeek = date.getUTCDay();
if (dayOfWeek === 6 || dayOfWeek === 0) {
return "It's the weekend!";
}
const daysUntilSaturday = (6 - dayOfWeek);
return `${daysUntilSaturday} day${daysUntilSaturday === 1 ? "" : "s"} until the weekend.`;
}
```

View File

@@ -0,0 +1,70 @@
---
id: 68f6587287ad1f4ad39b0c83
title: "Challenge 97: GCD"
challengeType: 28
dashedName: challenge-97
---
# --description--
Given two positive integers, return their greatest common divisor (GCD).
- The GCD of two integers is the largest number that divides evenly into both numbers without leaving a remainder.
For example, the divisors of `4` are `1`, `2`, and `4`. The divisors of `6` are `1`, `2`, `3`, and `6`. So given `4` and `6`, return `2`, the largest number that appears in both sets of divisors.
# --hints--
`gcd(4, 6)` should return `2`.
```js
assert.equal(gcd(4, 6), 2);
```
`gcd(20, 15)` should return `5`.
```js
assert.equal(gcd(20, 15), 5);
```
`gcd(13, 17)` should return `1`.
```js
assert.equal(gcd(13, 17), 1);
```
`gcd(654, 456)` should return `6`.
```js
assert.equal(gcd(654, 456), 6);
```
`gcd(3456, 4320)` should return `864`.
```js
assert.equal(gcd(3456, 4320), 864);
```
# --seed--
## --seed-contents--
```js
function gcd(x, y) {
return x;
}
```
# --solutions--
```js
function gcd(x, y) {
while (y !== 0) {
const temp = y;
y = x % y;
x = temp;
}
return x;
}
```

View File

@@ -0,0 +1,73 @@
---
id: 68f6587287ad1f4ad39b0c84
title: "Challenge 98: Rectangle Count"
challengeType: 28
dashedName: challenge-98
---
# --description--
Given two positive integers representing the width and height of a rectangle, determine how many rectangles can fit in the given one.
- Only count rectangles with integer width and height.
For example, given `1` and `3`, return `6`. Three 1x1 rectangles, two 1x2 rectangles, and one 1x3 rectangle.
# --hints--
`countRectangles(1, 3)` should return `6`.
```js
assert.equal(countRectangles(1, 3), 6);
```
`countRectangles(3, 2)` should return `18`.
```js
assert.equal(countRectangles(3, 2), 18);
```
`countRectangles(1, 2)` should return `3`.
```js
assert.equal(countRectangles(1, 2), 3);
```
`countRectangles(5, 4)` should return `150`.
```js
assert.equal(countRectangles(5, 4), 150);
```
`countRectangles(11, 19)` should return `12540`.
```js
assert.equal(countRectangles(11, 19), 12540);
```
# --seed--
## --seed-contents--
```js
function countRectangles(width, height) {
return width;
}
```
# --solutions--
```js
function countRectangles(width, height) {
let count = 0;
for (let w = 1; w <= width; w++) {
for (let h = 1; h <= height; h++) {
count += (width - w + 1) * (height - h + 1);
}
}
return count;
}
```

View File

@@ -0,0 +1,84 @@
---
id: 68f6587287ad1f4ad39b0c85
title: "Challenge 99: Fingerprint Test"
challengeType: 28
dashedName: challenge-99
---
# --description--
Given two strings representing fingerprints, determine if they are a match using the following rules:
- Each fingerprint will consist only of lowercase letters (`a-z`).
- Two fingerprints are considered a match if:
- They are the same length.
- The number of differing characters does not exceded 10% of the fingerprint length.
# --hints--
`isMatch("helloworld", "helloworld")` should return `true`.
```js
assert.isTrue(isMatch("helloworld", "helloworld"));
```
`isMatch("helloworld", "helloworlds")` should return `false`.
```js
assert.isFalse(isMatch("helloworld", "helloworlds"));
```
`isMatch("helloworld", "jelloworld")` should return `true`.
```js
assert.isTrue(isMatch("helloworld", "jelloworld"));
```
`isMatch("thequickbrownfoxjumpsoverthelazydog", "thequickbrownfoxjumpsoverthelazydog")` should return `true`.
```js
assert.isTrue(isMatch("thequickbrownfoxjumpsoverthelazydog", "thequickbrownfoxjumpsoverthelazydog"));
```
`isMatch("theslickbrownfoxjumpsoverthelazydog", "thequickbrownfoxjumpsoverthehazydog")` should return `true`.
```js
assert.isTrue(isMatch("theslickbrownfoxjumpsoverthelazydog", "thequickbrownfoxjumpsoverthehazydog"));
```
`isMatch("thequickbrownfoxjumpsoverthelazydog", "thequickbrownfoxjumpsoverthehazycat")` should return `false`.
```js
assert.isFalse(isMatch("thequickbrownfoxjumpsoverthelazydog", "thequickbrownfoxjumpsoverthehazycat"));
```
# --seed--
## --seed-contents--
```js
function isMatch(fingerprintA, fingerprintB) {
return fingerprintA;
}
```
# --solutions--
```js
function isMatch(fingerprintA, fingerprintB) {
if (fingerprintA.length !== fingerprintB.length) return false;
const length = fingerprintA.length;
let mismatches = 0;
for (let i = 0; i < length; i++) {
if (fingerprintA[i] !== fingerprintB[i]) {
mismatches++;
if (mismatches > length * 0.1) return false;
}
}
return true;
}
```

View File

@@ -0,0 +1,65 @@
---
id: 68f6587287ad1f4ad39b0c7c
title: "Challenge 90: Character Limit"
challengeType: 29
dashedName: challenge-90
---
# --description--
In this challenge, you are given a string and need to determine if it fits in a social media post. Return the following strings based on the rules given:
- `"short post"` if it fits within a 40-character limit.
- `"long post"` if it's greater than 40 characters and fits within an 80-character limit.
- `"invalid post"` if it's too long to fit within either limit.
# --hints--
`can_post("Hello world")` should return `"short post"`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(can_post("Hello world"), "short post")`)
}})
```
`can_post("This is a longer message but still under eighty characters.")` should return `"long post"`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(can_post("This is a longer message but still under eighty characters."), "long post")`)
}})
```
`can_post("This message is too long to fit into either of the character limits for a social media post.")` should return `"invalid post"`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(can_post("This message is too long to fit into either of the character limits for a social media post."), "invalid post")`)
}})
```
# --seed--
## --seed-contents--
```py
def can_post(message):
return message
```
# --solutions--
```py
def can_post(message):
if len(message) <= 40:
return "short post"
elif len(message) <= 80:
return "long post"
else:
return "invalid post"
```

View File

@@ -0,0 +1,113 @@
---
id: 68f6587287ad1f4ad39b0c7d
title: "Challenge 91: Word Search"
challengeType: 29
dashedName: challenge-91
---
# --description--
Given a matrix (an array of arrays) of single letters and a word to find, return the start and end indices of the word in the matrix.
- The given matrix will be filled with all lowercase letters (`a-z`).
- The word to find will always be in the matrix exactly once.
- The word to find will always be in a straight line in one of these directions:
- left to right
- right to left
- top to bottom
- bottom to top
For example, given the matrix:
```md
[
["a", "c", "t"],
["t", "a", "t"],
["c", "t", "c"]
]
```
And the word `"cat"`, return:
```md
[[0, 1], [2, 1]]
```
Where `[0, 1]` are the indices for the `"c"` (start of the word), and `[2, 1]` are the indices for the `"t"` (end of the word).
# --hints--
`find_word([["a", "c", "t"], ["t", "a", "t"], ["c", "t", "c"]], "cat")` should return `[[0, 1], [2, 1]]`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(find_word([["a", "c", "t"], ["t", "a", "t"], ["c", "t", "c"]], "cat"), [[0, 1], [2, 1]])`)
}})
```
`find_word([["d", "o", "g"], ["o", "g", "d"], ["d", "g", "o"]], "dog")` should return `[[0, 0], [0, 2]]`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(find_word([["d", "o", "g"], ["o", "g", "d"], ["d", "g", "o"]], "dog"), [[0, 0], [0, 2]])`)
}})
```
`find_word([["h", "i", "s", "h"], ["i", "s", "f", "s"], ["f", "s", "i", "i"], ["s", "h", "i", "f"]], "fish")` should return `[[3, 3], [0, 3]]`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(find_word([["h", "i", "s", "h"], ["i", "s", "f", "s"], ["f", "s", "i", "i"], ["s", "h", "i", "f"]], "fish"), [[3, 3], [0, 3]])`)
}})
```
`find_word([["f", "x", "o", "x"], ["o", "x", "o", "f"], ["f", "o", "f", "x"], ["f", "x", "x", "o"]], "fox")` should return `[[1, 3], [1, 1]]`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(find_word([["f", "x", "o", "x"], ["o", "x", "o", "f"], ["f", "o", "f", "x"], ["f", "x", "x", "o"]], "fox"), [[1, 3], [1, 1]])`)
}})
```
# --seed--
## --seed-contents--
```py
def find_word(matrix, word):
return matrix
```
# --solutions--
```py
def find_word(matrix, word):
rows = len(matrix)
cols = len(matrix[0])
length = len(word)
directions = [
(0, 1),
(0, -1),
(1, 0),
(-1, 0)
]
for r in range(rows):
for c in range(cols):
for dr, dc in directions:
match = True
for i in range(length):
nr = r + dr * i
nc = c + dc * i
if nr < 0 or nr >= rows or nc < 0 or nc >= cols or matrix[nr][nc] != word[i]:
match = False
break
if match:
return [[r, c], [r + dr * (length - 1), c + dc * (length - 1)]]
```

View File

@@ -0,0 +1,92 @@
---
id: 68f6587287ad1f4ad39b0c7e
title: "Challenge 92: Extension Extractor"
challengeType: 29
dashedName: challenge-92
---
# --description--
Given a string representing a filename, return the extension of the file.
- The extension is the part of the filename that comes after the last period (`.`).
- If the filename does not contain a period or ends with a period, return `"none"`.
- The extension should be returned as-is, preserving case.
# --hints--
`get_extension("document.txt")` should return `"txt"`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(get_extension("document.txt"), "txt")`)
}})
```
`get_extension("README")` should return `"none"`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(get_extension("README"), "none")`)
}})
```
`get_extension("image.PNG")` should return `"PNG"`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(get_extension("image.PNG"), "PNG")`)
}})
```
`get_extension(".gitignore")` should return `"gitignore"`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(get_extension(".gitignore"), "gitignore")`)
}})
```
`get_extension("archive.tar.gz")` should return `"gz"`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(get_extension("archive.tar.gz"), "gz")`)
}})
```
`get_extension("final.draft.")` should return `"none"`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(get_extension("final.draft."), "none")`)
}})
```
# --seed--
## --seed-contents--
```py
def get_extension(filename):
return filename
```
# --solutions--
```py
def get_extension(filename):
last_dot = filename.rfind('.')
if last_dot == -1 or last_dot == len(filename) - 1:
return "none"
return filename[last_dot + 1:]
```

View File

@@ -0,0 +1,101 @@
---
id: 68f6587287ad1f4ad39b0c7f
title: "Challenge 93: Vowels and Consonants"
challengeType: 29
dashedName: challenge-93
---
# --description--
Given a string, return an array with the number of vowels and number of consonants in the string.
- Vowels consist of `a`, `e`, `i`, `o`, `u` in any case.
- Consonants consist of all other letters in any case.
- Ignore any non-letter characters.
For example, given `"Hello World"`, return `[3, 7]`.
# --hints--
`count("Hello World")` should return `[3, 7]`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(count("Hello World"), [3, 7])`)
}})
```
`count("JavaScript")` should return `[3, 7]`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(count("JavaScript"), [3, 7])`)
}})
```
`count("Python")` should return `[1, 5]`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(count("Python"), [1, 5])`)
}})
```
`count("freeCodeCamp")` should return `[5, 7]`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(count("freeCodeCamp"), [5, 7])`)
}})
```
`count("Hello, World!")` should return `[3, 7]`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(count("Hello World"), [3, 7])`)
}})
```
`count("The quick brown fox jumps over the lazy dog.")` should return `[11, 24]`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(count("Hello World"), [3, 7])`)
}})
```
# --seed--
## --seed-contents--
```py
def count(s):
return s
```
# --solutions--
```py
def count(s):
vowels = "aeiou"
consonants = "bcdfghjklmnpqrstvwxyz"
v = 0
c = 0
for char in s:
ch = char.lower()
if ch in vowels:
v += 1
if ch in consonants:
c += 1
return [v, c]
```

View File

@@ -0,0 +1,91 @@
---
id: 68f6587287ad1f4ad39b0c80
title: "Challenge 94: Email Signature Generator"
challengeType: 29
dashedName: challenge-94
---
# --description--
Given strings for a person's name, title, and company, return an email signature as a single string using the following rules:
- The name should appear first, preceded by a prefix that depends on the first letter of the name. For names starting with (case-insensitive):
- `A-I`: Use `>>` as the prefix.
- `J-R`: Use `--` as the prefix.
- `S-Z`: Use `::` as the prefix.
- A comma and space (`, `) should follow the name.
- The title and company should follow the comma and space, separated by `" at "` (with spaces around it).
For example, given `"Quinn Waverly"`, `"Founder and CEO"`, and `"TechCo"` return `"--Quinn Waverly, Founder and CEO at TechCo"`.
# --hints--
`generate_signature("Quinn Waverly", "Founder and CEO", "TechCo")` should return `"--Quinn Waverly, Founder and CEO at TechCo"`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(generate_signature("Quinn Waverly", "Founder and CEO", "TechCo"), "--Quinn Waverly, Founder and CEO at TechCo")`)
}})
```
`generate_signature("Alice Reed", "Engineer", "TechCo")` should return `">>Alice Reed, Engineer at TechCo"`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(generate_signature("Alice Reed", "Engineer", "TechCo"), ">>Alice Reed, Engineer at TechCo")`)
}})
```
`generate_signature("Tina Vaughn", "Developer", "example.com")` should return `"::Tina Vaughn, Developer at example.com"`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(generate_signature("Tina Vaughn", "Developer", "example.com"), "::Tina Vaughn, Developer at example.com")`)
}})
```
`generate_signature("B. B.", "Product Tester", "AcmeCorp")` should return `">>B. B., Product Tester at AcmeCorp"`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(generate_signature("B. B.", "Product Tester", "AcmeCorp"), ">>B. B., Product Tester at AcmeCorp")`)
}})
```
`generate_signature("windstorm", "Cloud Architect", "Atmospheronics")` should return `"::windstorm, Cloud Architect at Atmospheronics"`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(generate_signature("windstorm", "Cloud Architect", "Atmospheronics"), "::windstorm, Cloud Architect at Atmospheronics")`)
}})
```
# --seed--
## --seed-contents--
```py
def generate_signature(name, title, company):
return name
```
# --solutions--
```py
def generate_signature(name, title, company):
first_letter = name[0].upper()
if first_letter in "ABCDEFGHI":
prefix = ">>"
elif first_letter in "JKLMNOPQR":
prefix = "--"
else:
prefix = "::"
return f"{prefix}{name}, {title} at {company}"
```

View File

@@ -0,0 +1,85 @@
---
id: 68f6587287ad1f4ad39b0c81
title: "Challenge 95: Array Shift"
challengeType: 29
dashedName: challenge-95
---
# --description--
Given an array and an integer representing how many positions to shift the array, return the shifted array.
- A positive integer shifts the array to the left.
- A negative integer shifts the array to the right.
- The shift wraps around the array.
For example, given `[1, 2, 3]` and `1`, shift the array 1 to the left, returning `[2, 3, 1]`.
# --hints--
`shift_array([1, 2, 3], 1)` should return `[2, 3, 1]`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(shift_array([1, 2, 3], 1), [2, 3, 1])`)
}})
```
`shift_array([1, 2, 3], -1)` should return `[3, 1, 2]`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(shift_array([1, 2, 3], -1), [3, 1, 2])`)
}})
```
`shift_array(["alpha", "bravo", "charlie"], 5)` should return `["charlie", "alpha", "bravo"]`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(shift_array(["alpha", "bravo", "charlie"], 5), ["charlie", "alpha", "bravo"])`)
}})
```
`shift_array(["alpha", "bravo", "charlie"], -11)` should return `["bravo", "charlie", "alpha"]`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(shift_array(["alpha", "bravo", "charlie"], -11), ["bravo", "charlie", "alpha"])`)
}})
```
`shift_array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 15)` should return `[5, 6, 7, 8, 9, 0, 1, 2, 3, 4]`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(shift_array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 15), [5, 6, 7, 8, 9, 0, 1, 2, 3, 4])`)
}})
```
# --seed--
## --seed-contents--
```py
def shift_array(arr, n):
return arr
```
# --solutions--
```py
def shift_array(arr, n):
length = len(arr)
n = n % length
if n < 0:
n += length
return arr[n:] + arr[:n]
```

View File

@@ -0,0 +1,98 @@
---
id: 68f6587287ad1f4ad39b0c82
title: "Challenge 96: Is It the Weekend?"
challengeType: 29
dashedName: challenge-96
---
# --description--
Given a date in the format `"YYYY-MM-DD"`, return the number of days left until the weekend.
- The weekend starts on Saturday.
- If the given date is Saturday or Sunday, return `"It's the weekend!"`.
- Otherwise, return `"X days until the weekend."`, where `X` is the number of days until Saturday.
- If `X` is `1`, use `"day"` (singular) instead of `"days"` (plural).
- Make sure the calculation ignores your local timezone.
# --hints--
`days_until_weekend("2025-11-14")` should return `"1 day until the weekend."`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(days_until_weekend("2025-11-14"), "1 day until the weekend.")`)
}})
```
`days_until_weekend("2025-01-01")` should return `"3 days until the weekend."`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(days_until_weekend("2025-01-01"), "3 days until the weekend.")`)
}})
```
`days_until_weekend("2025-12-06")` should return `"It's the weekend!"`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(days_until_weekend("2025-12-06"), "It's the weekend!")`)
}})
```
`days_until_weekend("2026-01-27")` should return `"4 days until the weekend."`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(days_until_weekend("2026-01-27"), "4 days until the weekend.")`)
}})
```
`days_until_weekend("2026-09-07")` should return `"5 days until the weekend."`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(days_until_weekend("2026-09-07"), "5 days until the weekend.")`)
}})
```
`days_until_weekend("2026-11-29")` should return `"It's the weekend!"`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(days_until_weekend("2026-11-29"), "It's the weekend!")`)
}})
```
# --seed--
## --seed-contents--
```py
def days_until_weekend(date_string):
return date_string
```
# --solutions--
```py
from datetime import datetime
def days_until_weekend(date_string):
date = datetime.strptime(date_string, "%Y-%m-%d").date()
day_of_week = date.weekday()
if day_of_week == 5 or day_of_week == 6:
return "It's the weekend!"
days_until_saturday = 5 - day_of_week
return f"{days_until_saturday} day{'s' if days_until_saturday != 1 else ''} until the weekend."
```

View File

@@ -0,0 +1,80 @@
---
id: 68f6587287ad1f4ad39b0c83
title: "Challenge 97: GCD"
challengeType: 29
dashedName: challenge-97
---
# --description--
Given two positive integers, return their greatest common divisor (GCD).
- The GCD of two integers is the largest number that divides evenly into both numbers without leaving a remainder.
For example, the divisors of `4` are `1`, `2`, and `4`. The divisors of `6` are `1`, `2`, `3`, and `6`. So given `4` and `6`, return `2`, the largest number that appears in both sets of divisors.
# --hints--
`gcd(4, 6)` should return `2`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(gcd(4, 6), 2)`)
}})
```
`gcd(20, 15)` should return `5`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(gcd(20, 15), 5)`)
}})
```
`gcd(13, 17)` should return `1`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(gcd(13, 17), 1)`)
}})
```
`gcd(654, 456)` should return `6`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(gcd(654, 456), 6)`)
}})
```
`gcd(3456, 4320)` should return `864`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(gcd(3456, 4320), 864)`)
}})
```
# --seed--
## --seed-contents--
```py
def gcd(x, y):
return x
```
# --solutions--
```py
def gcd(x, y):
while y != 0:
x, y = y, x % y
return x
```

View File

@@ -0,0 +1,82 @@
---
id: 68f6587287ad1f4ad39b0c84
title: "Challenge 98: Rectangle Count"
challengeType: 29
dashedName: challenge-98
---
# --description--
Given two positive integers representing the width and height of a rectangle, determine how many rectangles can fit in the given one.
- Only count rectangles with integer width and height.
For example, given `1` and `3`, return `6`. Three 1x1 rectangles, two 1x2 rectangles, and one 1x3 rectangle.
# --hints--
`count_rectangles(1, 3)` should return `6`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(count_rectangles(1, 3), 6)`)
}})
```
`count_rectangles(3, 2)` should return `18`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(count_rectangles(3, 2), 18)`)
}})
```
`count_rectangles(1, 2)` should return `3`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(count_rectangles(1, 2), 3)`)
}})
```
`count_rectangles(5, 4)` should return `150`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(count_rectangles(5, 4), 150)`)
}})
```
`count_rectangles(11, 19)` should return `12540`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertEqual(count_rectangles(11, 19), 12540)`)
}})
```
# --seed--
## --seed-contents--
```py
def count_rectangles(width, height):
return width
```
# --solutions--
```py
def count_rectangles(width, height):
total = 0
for w in range(1, width + 1):
for h in range(1, height + 1):
total += (width - w + 1) * (height - h + 1)
return total
```

View File

@@ -0,0 +1,99 @@
---
id: 68f6587287ad1f4ad39b0c85
title: "Challenge 99: Fingerprint Test"
challengeType: 29
dashedName: challenge-99
---
# --description--
Given two strings representing fingerprints, determine if they are a match using the following rules:
- Each fingerprint will consist only of lowercase letters (`a-z`).
- Two fingerprints are considered a match if:
- They are the same length.
- The number of differing characters does not exceded 10% of the fingerprint length.
# --hints--
`is_match("helloworld", "helloworld")` should return `True`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertIs(is_match("helloworld", "helloworld"), True)`)
}})
```
`is_match("helloworld", "helloworlds")` should return `False`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertIs(is_match("helloworld", "helloworlds"), False)`)
}})
```
`is_match("helloworld", "jelloworld")` should return `True`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertIs(is_match("helloworld", "jelloworld"), True)`)
}})
```
`is_match("thequickbrownfoxjumpsoverthelazydog", "thequickbrownfoxjumpsoverthelazydog")` should return `True`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertIs(is_match("thequickbrownfoxjumpsoverthelazydog", "thequickbrownfoxjumpsoverthelazydog"), True)`)
}})
```
`is_match("theslickbrownfoxjumpsoverthelazydog", "thequickbrownfoxjumpsoverthehazydog")` should return `True`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertIs(is_match("theslickbrownfoxjumpsoverthelazydog", "thequickbrownfoxjumpsoverthehazydog"), True)`)
}})
```
`is_match("thequickbrownfoxjumpsoverthelazydog", "thequickbrownfoxjumpsoverthehazycat")` should return `False`.
```js
({test: () => { runPython(`
from unittest import TestCase
TestCase().assertIs(is_match("thequickbrownfoxjumpsoverthelazydog", "thequickbrownfoxjumpsoverthehazycat"), False)`)
}})
```
# --seed--
## --seed-contents--
```py
def is_match(fingerprint_a, fingerprint_b):
return fingerprint_a
```
# --solutions--
```py
def is_match(fingerprint_a, fingerprint_b):
if len(fingerprint_a) != len(fingerprint_b):
return False
mismatches = 0
for c1, c2 in zip(fingerprint_a, fingerprint_b):
if c1 != c2:
mismatches += 1
if mismatches > len(fingerprint_a) // 10:
return False
return True
```

View File

@@ -362,6 +362,46 @@
{
"id": "68ee9e3066cfd4eb2328e8a8",
"title": "Challenge 89: Counting Cards"
},
{
"id": "68f6587287ad1f4ad39b0c7c",
"title": "Challenge 90: Character Limit"
},
{
"id": "68f6587287ad1f4ad39b0c7d",
"title": "Challenge 91: Word Search"
},
{
"id": "68f6587287ad1f4ad39b0c7e",
"title": "Challenge 92: Extension Extractor"
},
{
"id": "68f6587287ad1f4ad39b0c7f",
"title": "Challenge 93: Vowels and Consonants"
},
{
"id": "68f6587287ad1f4ad39b0c80",
"title": "Challenge 94: Email Signature Generator"
},
{
"id": "68f6587287ad1f4ad39b0c81",
"title": "Challenge 95: Array Shift"
},
{
"id": "68f6587287ad1f4ad39b0c82",
"title": "Challenge 96: Is It the Weekend?"
},
{
"id": "68f6587287ad1f4ad39b0c83",
"title": "Challenge 97: GCD"
},
{
"id": "68f6587287ad1f4ad39b0c84",
"title": "Challenge 98: Rectangle Count"
},
{
"id": "68f6587287ad1f4ad39b0c85",
"title": "Challenge 99: Fingerprint Test"
}
]
}

View File

@@ -361,6 +361,46 @@
{
"id": "68ee9e3066cfd4eb2328e8a8",
"title": "Challenge 89: Counting Cards"
},
{
"id": "68f6587287ad1f4ad39b0c7c",
"title": "Challenge 90: Character Limit"
},
{
"id": "68f6587287ad1f4ad39b0c7d",
"title": "Challenge 91: Word Search"
},
{
"id": "68f6587287ad1f4ad39b0c7e",
"title": "Challenge 92: Extension Extractor"
},
{
"id": "68f6587287ad1f4ad39b0c7f",
"title": "Challenge 93: Vowels and Consonants"
},
{
"id": "68f6587287ad1f4ad39b0c80",
"title": "Challenge 94: Email Signature Generator"
},
{
"id": "68f6587287ad1f4ad39b0c81",
"title": "Challenge 95: Array Shift"
},
{
"id": "68f6587287ad1f4ad39b0c82",
"title": "Challenge 96: Is It the Weekend?"
},
{
"id": "68f6587287ad1f4ad39b0c83",
"title": "Challenge 97: GCD"
},
{
"id": "68f6587287ad1f4ad39b0c84",
"title": "Challenge 98: Rectangle Count"
},
{
"id": "68f6587287ad1f4ad39b0c85",
"title": "Challenge 99: Fingerprint Test"
}
]
}

View File

@@ -13,7 +13,7 @@ const { MONGOHQ_URL } = process.env;
// Number challenges in the dev-playground blocks
// Update this if the number of challenges changes
const EXPECTED_CHALLENGE_COUNT = 89;
const EXPECTED_CHALLENGE_COUNT = 99;
// Date to set for the first challenge, second challenge will be one day later, etc...
// **DO NOT CHANGE THIS AFTER RELEASE (if seeding production - okay for local dev)**