diff --git a/curriculum/challenges/english/blocks/daily-coding-challenges-javascript/698a1a863194f1f4e63f645e.md b/curriculum/challenges/english/blocks/daily-coding-challenges-javascript/698a1a863194f1f4e63f645e.md index e675a7499b5..eeb9646390c 100644 --- a/curriculum/challenges/english/blocks/daily-coding-challenges-javascript/698a1a863194f1f4e63f645e.md +++ b/curriculum/challenges/english/blocks/daily-coding-challenges-javascript/698a1a863194f1f4e63f645e.md @@ -13,7 +13,7 @@ Given a string, return the substring between the two identical characters that h - The returned substring should exclude the matching characters. - If two or more gaps are the same length, return the characters from the first one. -For example, given `"ABCDAC"`, return `"DA"`. +For example, given `"ABCDAC"`, return `"DA"` because: - Only `"A"` and `"C"` repeat in the string. - The number of characters between the two `"A"` characters is 3, and between the `"C"` characters is 2. diff --git a/curriculum/challenges/english/blocks/daily-coding-challenges-javascript/69a890af247de743333bd4cc.md b/curriculum/challenges/english/blocks/daily-coding-challenges-javascript/69a890af247de743333bd4cc.md new file mode 100644 index 00000000000..f6d82a0263e --- /dev/null +++ b/curriculum/challenges/english/blocks/daily-coding-challenges-javascript/69a890af247de743333bd4cc.md @@ -0,0 +1,145 @@ +--- +id: 69a890af247de743333bd4cc +title: "Challenge 223: QR Decoder" +challengeType: 28 +dashedName: challenge-223 +--- + +# --description-- + +Given a 6x6 matrix (array of arrays), representing a QR code, return the string of binary data in the code. + +- The QR code may be given in any rotation of 90 degree increments. +- A correctly oriented code has a 2x2 group of `1`'s (orientation markers) in the bottom-left, top-left, and top-right corners. +- The three 2x2 orientation markers are not part of the binary data. +- The binary data is read left-to-right, top-to-bottom (like a book) when the QR code is correctly oriented. +- A code will always have exactly one valid orientation. + +For example, given: + +```js +[ + "110011", + "110011", + "000000", + "000000", + "110000", + "110001" +] +``` + +or given the same code with a different orientation: + +```js +[ + "110011", + "110011", + "000000", + "000000", + "000011", + "100011" +] +``` + +Return `"000000000000000000000001"`, all the binary data excluding the three 2x2 orientation markers. + +# --hints-- + +`decodeQr(["110011", "110011", "000000", "000000", "110000", "110001"])` should return `"000000000000000000000001"`. + +```js +assert.equal(decodeQr(["110011", "110011", "000000", "000000", "110000", "110001"]), "000000000000000000000001"); +``` + +`decodeQr(["100011", "000011", "000000", "000000", "110011", "110011"])` should return `"000000000000000000000001"`. + +```js +assert.equal(decodeQr(["100011", "000011", "000000", "000000", "110011", "110011"]), "000000000000000000000001"); +``` + +`decodeQr(["110011", "111111", "010000", "110000", "110011", "110100"])` should return `"001101000011000000110100"`. + +```js +assert.equal(decodeQr(["110011", "111111", "010000", "110000", "110011", "110100"]), "001101000011000000110100"); +``` + +`decodeQr(["011011", "101011", "101000", "100010", "110011", "111011"])` should return `"010001000100010101010110"`. + +```js +assert.equal(decodeQr(["011011", "101011", "101000", "100010", "110011", "111011"]), "010001000100010101010110"); +``` + +`decodeQr(["111100", "110001", "100011", "001101", "110011", "110011"])` should return `"010000100100100101001110"`. + +```js +assert.equal(decodeQr(["111100", "110001", "100011", "001101", "110011", "110011"]), "010000100100100101001110"); +``` + +# --seed-- + +## --seed-contents-- + +```js +function decodeQr(qrCode) { + + return qrCode; +} +``` + +# --solutions-- + +```js +function isOriented(code) { + const markerIndices = [ + [0, 0], + [0, 1], + [0, 4], + [0, 5], + [1, 0], + [1, 1], + [1, 4], + [1, 5], + [4, 0], + [4, 1], + [5, 0], + [5, 1] + ]; + + for(const [row, col] of markerIndices) { + if (code[row][col] !== '1') return false; + } + + return true; +} + +function rotate(code) { + const newCode = ['', '', '', '', '', '']; + for (let i = 0; i < 6; i++) { + for (let j = 5; j >= 0; j--) { + newCode[i] += code[j][i]; + } + } + return newCode; +} + +function getData(code) { + let data = ''; + data += code[0].substring(2, 4) + data += code[1].substring(2, 4) + data += code[2] + data += code[3] + data += code[4].substring(2) + data += code[5].substring(2) + return data; +} + +function decodeQr(qrCode) { + let code = [...qrCode]; + + while(!isOriented(code)) { + code = rotate(code); + } + + return getData(code); +} +``` diff --git a/curriculum/challenges/english/blocks/daily-coding-challenges-javascript/69a890af247de743333bd4cd.md b/curriculum/challenges/english/blocks/daily-coding-challenges-javascript/69a890af247de743333bd4cd.md new file mode 100644 index 00000000000..d4f19f1f4c7 --- /dev/null +++ b/curriculum/challenges/english/blocks/daily-coding-challenges-javascript/69a890af247de743333bd4cd.md @@ -0,0 +1,99 @@ +--- +id: 69a890af247de743333bd4cd +title: "Challenge 224: Coffee Roast Detector" +challengeType: 28 +dashedName: challenge-224 +--- + +# --description-- + +Given a string representing the beans used to make a cup of coffee, determine the roast of the cup. + +- The given string will contain the following characters, each representing a type of bean: + + - An apostrophe (`'`) is a light roast bean worth 1 point each. + - A dash (`-`) is a medium roast bean worth 2 points each. + - A period (`.`) is a dark roast bean worth 3 points each. + +- The roast level is determined by the average of all the beans. + +Return: + +- `"Light"` if the average is less than 1.75. +- `"Medium"` if the average is 1.75 to 2.5. +- `"Dark"` if the average is greater than 2.5. + +# --hints-- + +`detectRoast("''-''''''-'-''--''''")` should return `"Light"`. + +```js +assert.equal(detectRoast("''-''''''-'-''--''''"), "Light"); +``` + +`detectRoast(".'-''-''..'''.-.-''-")` should return `"Medium"`. + +```js +assert.equal(detectRoast(".'-''-''..'''.-.-''-"), "Medium"); +``` + +`detectRoast("--.''--'-''.--..-.--")` should return `"Medium"`. + +```js +assert.equal(detectRoast("--.''--'-''.--..-.--"), "Medium"); +``` + +`detectRoast("-...'-......-..-...-")` should return `"Dark"`. + +```js +assert.equal(detectRoast("-...'-......-..-...-"), "Dark"); +``` + +`detectRoast(".--.-..-......----.'")` should return `"Medium"`. + +```js +assert.equal(detectRoast(".--.-..-......----.'"), "Medium"); +``` + +`detectRoast("..-..-..-..-....-.-.")` should return `"Dark"`. + +```js +assert.equal(detectRoast("..-..-..-..-....-.-."), "Dark"); +``` + +`detectRoast("-'-''''''..-'.''-'.'")` should return `"Light"`. + +```js +assert.equal(detectRoast("-'-''''''..-'.''-'.'"), "Light"); +``` + +# --seed-- + +## --seed-contents-- + +```js +function detectRoast(beans) { + + return beans; +} +``` + +# --solutions-- + +```js +function detectRoast(beans) { + let total = 0; + + for (const bean of beans) { + if (bean === "'") total += 1; + else if (bean === "-") total += 2; + else if (bean === ".") total += 3; + } + + const avg = total / beans.length; + + if (avg < 1.75) return "Light"; + if (avg <= 2.5) return "Medium"; + return "Dark"; +} +``` diff --git a/curriculum/challenges/english/blocks/daily-coding-challenges-javascript/69a890af247de743333bd4ce.md b/curriculum/challenges/english/blocks/daily-coding-challenges-javascript/69a890af247de743333bd4ce.md new file mode 100644 index 00000000000..c4f11150f76 --- /dev/null +++ b/curriculum/challenges/english/blocks/daily-coding-challenges-javascript/69a890af247de743333bd4ce.md @@ -0,0 +1,74 @@ +--- +id: 69a890af247de743333bd4ce +title: "Challenge 225: No Consecutive Repeats" +challengeType: 28 +dashedName: challenge-225 +--- + +# --description-- + +Given a string, determine if it has no repeating characters. + +- A string has no repeats if it does not have the same character two or more times in a row. + +# --hints-- + +`hasNoRepeats("hi world")` should return `true`. + +```js +assert.isTrue(hasNoRepeats("hi world")); +``` + +`hasNoRepeats("hello world")` should return `false`. + +```js +assert.isFalse(hasNoRepeats("hello world")); +``` + +`hasNoRepeats("abcdefghijklmnopqrstuvwxyz")` should return `true`. + +```js +assert.isTrue(hasNoRepeats("abcdefghijklmnopqrstuvwxyz")); +``` + +`hasNoRepeats("freeCodeCamp")` should return `false`. + +```js +assert.isFalse(hasNoRepeats("freeCodeCamp")); +``` + +`hasNoRepeats("The quick brown fox jumped over the lazy dog.")` should return `true`. + +```js +assert.isTrue(hasNoRepeats("The quick brown fox jumped over the lazy dog.")); +``` + +`hasNoRepeats("Mississippi")` should return `false`. + +```js +assert.isFalse(hasNoRepeats("Mississippi")); +``` + +# --seed-- + +## --seed-contents-- + +```js +function hasNoRepeats(str) { + + return str; +} +``` + +# --solutions-- + +```js +function hasNoRepeats(str) { + for (let i = 1; i < str.length; i++) { + if (str[i] === str[i - 1]) { + return false; + } + } + return true; +} +``` diff --git a/curriculum/challenges/english/blocks/daily-coding-challenges-javascript/69a890af247de743333bd4cf.md b/curriculum/challenges/english/blocks/daily-coding-challenges-javascript/69a890af247de743333bd4cf.md new file mode 100644 index 00000000000..1afd853972d --- /dev/null +++ b/curriculum/challenges/english/blocks/daily-coding-challenges-javascript/69a890af247de743333bd4cf.md @@ -0,0 +1,69 @@ +--- +id: 69a890af247de743333bd4cf +title: "Challenge 226: Passing Exam Count" +challengeType: 28 +dashedName: challenge-226 +--- + +# --description-- + +Given an array of student exam scores and the score needed to pass it, return the number of students that passed the exam. + +# --hints-- + +`passingCount([90, 85, 75, 60, 50], 70)` should return `3`. + +```js +assert.equal(passingCount([90, 85, 75, 60, 50], 70), 3); +``` + +`passingCount([100, 80, 75, 88, 72, 74, 79, 71, 60, 92], 75)` should return `6`. + +```js +assert.equal(passingCount([100, 80, 75, 88, 72, 74, 79, 71, 60, 92], 75), 6); +``` + +`passingCount([79, 60, 88, 72, 74, 59, 75, 71, 80, 92], 60)` should return `9`. + +```js +assert.equal(passingCount([79, 60, 88, 72, 74, 59, 75, 71, 80, 92], 60), 9); +``` + +`passingCount([76, 79, 80, 70, 71, 65, 79, 78, 59, 72], 85)` should return `0`. + +```js +assert.equal(passingCount([76, 79, 80, 70, 71, 65, 79, 78, 59, 72], 85), 0); +``` + +`passingCount([84, 65, 98, 53, 58, 71, 91, 80, 92, 70, 73, 83, 86, 69, 84, 77, 72, 58, 69, 75, 66, 68, 72, 96, 90, 63, 88, 63, 80, 67], 60)` should return `27`. + +```js +assert.equal(passingCount([84, 65, 98, 53, 58, 71, 91, 80, 92, 70, 73, 83, 86, 69, 84, 77, 72, 58, 69, 75, 66, 68, 72, 96, 90, 63, 88, 63, 80, 67], 60), 27); +``` + +# --seed-- + +## --seed-contents-- + +```js +function passingCount(scores, passingScore) { + + return scores; +} +``` + +# --solutions-- + +```js +function passingCount(scores, passingScore) { + let count = 0; + + for (const score of scores) { + if (score >= passingScore) { + count++; + } + } + + return count; +} +``` diff --git a/curriculum/challenges/english/blocks/daily-coding-challenges-javascript/69a890af247de743333bd4d0.md b/curriculum/challenges/english/blocks/daily-coding-challenges-javascript/69a890af247de743333bd4d0.md new file mode 100644 index 00000000000..e47129d746f --- /dev/null +++ b/curriculum/challenges/english/blocks/daily-coding-challenges-javascript/69a890af247de743333bd4d0.md @@ -0,0 +1,69 @@ +--- +id: 69a890af247de743333bd4d0 +title: "Challenge 227: Cooldown Time" +challengeType: 28 +dashedName: challenge-227 +--- + +# --description-- + +Given two timestamps, the first representing when a user finished an exam, and the second representing the current time, determine whether the user can take an exam again. + +- Both timestamps will be given the format: `"YYYY-MM-DDTHH:MM:SS"`, for example `"2026-03-25T14:00:00"`. Note that the time is 24-hour clock. +- A user must wait at least 48 hours before retaking an exam. + +# --hints-- + +`canRetake("2026-03-23T08:00:00", "2026-03-25T14:00:00")` should return `true`. + +```js +assert.isTrue(canRetake("2026-03-23T08:00:00", "2026-03-25T14:00:00")); +``` + +`canRetake("2026-03-24T14:00:00", "2026-03-25T10:00:00")` should return `false`. + +```js +assert.isFalse(canRetake("2026-03-24T14:00:00", "2026-03-25T10:00:00")); +``` + +`canRetake("2026-03-23T09:25:00", "2026-03-25T09:25:00")` should return `true`. + +```js +assert.isTrue(canRetake("2026-03-23T09:25:00", "2026-03-25T09:25:00")); +``` + +`canRetake("2026-03-23T11:50:00", "2026-03-25T11:49:59")` should return `false`. + +```js +assert.isFalse(canRetake("2026-03-23T11:50:00", "2026-03-25T11:49:59")); +``` + +# --seed-- + +## --seed-contents-- + +```js +function canRetake(finishTime, currentTime) { + + return finishTime; +} +``` + +# --solutions-- + +```js +function canRetake(finishTime, currentTime) { + function parse(ts) { + const parts = ts.split(/[-T:]/).map(Number); + const [y, m, d, h, min, s] = parts; + return Date.UTC(y, m - 1, d, h, min, s); + } + + const finishMs = parse(finishTime); + const currentMs = parse(currentTime); + + const cooldown = 48 * 60 * 60 * 1000; + + return currentMs - finishMs >= cooldown; +} +``` diff --git a/curriculum/challenges/english/blocks/daily-coding-challenges-javascript/69a890af247de743333bd4d1.md b/curriculum/challenges/english/blocks/daily-coding-challenges-javascript/69a890af247de743333bd4d1.md new file mode 100644 index 00000000000..9e484957987 --- /dev/null +++ b/curriculum/challenges/english/blocks/daily-coding-challenges-javascript/69a890af247de743333bd4d1.md @@ -0,0 +1,118 @@ +--- +id: 69a890af247de743333bd4d1 +title: "Challenge 228: Movie Night" +challengeType: 28 +dashedName: challenge-228 +--- + +# --description-- + +Given a string for the day of the week, another string for a showtime, and an integer number of tickets, return the total cost of the movie tickets for that showing. + +The given day will be one of: + +- `"Monday"` +- `"Tuesday"` +- `"Wednesday"` +- `"Thursday"` +- `"Friday"` +- `"Saturday"` +- `"Sunday"` + +The showtime will be given in the format `"H:MMam"` or `"H:MMpm"`. For example `"10:00am"` or `"10:00pm"`. + +Return the total cost in the format `"$D.CC"` using these rules: + +- Weekend (Friday - Sunday): $12.00 per ticket. +- Weekday (Monday - Thursday): $10.00 per ticket. +- Matinee (before 5:00pm): subtract $2.00 per ticket (except on Tuesdays). +- Tuesdays: all tickets are $5.00 each. + +# --hints-- + +`getMovieNightCost("Saturday", "10:00pm", 1)` should return `"$12.00"`. + +```js +assert.equal(getMovieNightCost("Saturday", "10:00pm", 1), "$12.00"); +``` + +`getMovieNightCost("Sunday", "10:00am", 1)` should return `"$10.00"`. + +```js +assert.equal(getMovieNightCost("Sunday", "10:00am", 1), "$10.00"); +``` + +`getMovieNightCost("Tuesday", "7:20pm", 2)` should return `"$10.00"`. + +```js +assert.equal(getMovieNightCost("Tuesday", "7:20pm", 2), "$10.00"); +``` + +`getMovieNightCost("Wednesday", "5:40pm", 3)` should return `"$30.00"`. + +```js +assert.equal(getMovieNightCost("Wednesday", "5:40pm", 3), "$30.00"); +``` + +`getMovieNightCost("Monday", "11:50am", 4)` should return `"$32.00"`. + +```js +assert.equal(getMovieNightCost("Monday", "11:50am", 4), "$32.00"); +``` + +`getMovieNightCost("Friday", "4:30pm", 5)` should return `"$50.00"`. + +```js +assert.equal(getMovieNightCost("Friday", "4:30pm", 5), "$50.00"); +``` + +`getMovieNightCost("Tuesday", "11:30am", 1)` should return `"$5.00"`. + +```js +assert.equal(getMovieNightCost("Tuesday", "11:30am", 1), "$5.00"); +``` + +# --seed-- + +## --seed-contents-- + +```js +function getMovieNightCost(day, showtime, numberOfTickets) { + + return day; +} +``` + +# --solutions-- + +```js +function getMovieNightCost(day, showtime, numberOfTickets) { + let price; + + if (day === "Tuesday") { + price = 5; + } else { + if (["Friday", "Saturday", "Sunday"].includes(day)) { + price = 12; + } else { + price = 10; + } + + const hour = parseInt(showtime.split(":")[0]); + const period = showtime.slice(-2); + + let hour24 = hour; + + if (period === "pm" && hour !== 12) hour24 += 12; + if (period === "am" && hour === 12) hour24 = 0; + + if (hour24 < 17) { + price -= 2; + } + } + + const total = price * numberOfTickets; + + return `$${total.toFixed(2)}`; +} +``` diff --git a/curriculum/challenges/english/blocks/daily-coding-challenges-javascript/69a890af247de743333bd4d2.md b/curriculum/challenges/english/blocks/daily-coding-challenges-javascript/69a890af247de743333bd4d2.md new file mode 100644 index 00000000000..675478fc3fa --- /dev/null +++ b/curriculum/challenges/english/blocks/daily-coding-challenges-javascript/69a890af247de743333bd4d2.md @@ -0,0 +1,119 @@ +--- +id: 69a890af247de743333bd4d2 +title: "Challenge 229: Truncate the Text 2" +challengeType: 28 +dashedName: challenge-229 +--- + +# --description-- + +Given a string, return a new string that is truncated so that the total width of the characters does not exceed 50 units. + +Each character has a specific width: + +| Letters | Width | +| - | - | +| `"ilI"` | 1 | +| `"fjrt"` | 2 | +| `"abcdeghkmnopqrstuvwxyzJL"` | 3 | +| `"ABCDEFGHKMNOPQRSTUVWXYZ"` | 4 | + +The table above includes all upper and lower case letters. Additionally: + +- Spaces (`" "`) have a width of 2 +- Periods (`"."`) have a width of 1 + +- If the given string is 50 units or less, return the string as-is, otherwise +- Truncate the string and add three periods at the end (`"..."`) so it's total width, including the three periods, is as close as possible to 60 units without going over. + +# --hints-- + +`truncateText("The quick brown fox")` should return `"The quick brown f..."`. + +```js +assert.equal(truncateText("The quick brown fox"), "The quick brown f..."); +``` + +`truncateText("The silky smooth sloth")` should return `"The silky smooth s..."`. + +```js +assert.equal(truncateText("The silky smooth sloth"), "The silky smooth s..."); +``` + +`truncateText("THE LOUD BRIGHT BIRD")` should return `"THE LOUD BRIG..."`. + +```js +assert.equal(truncateText("THE LOUD BRIGHT BIRD"), "THE LOUD BRIG..."); +``` + +`truncateText("The fast striped zebra")` should return `"The fast striped z..."`. + +```js +assert.equal(truncateText("The fast striped zebra"), "The fast striped z..."); +``` + +`truncateText("The big black bear")` should return `"The big black bear"`. + +```js +assert.equal(truncateText("The big black bear"), "The big black bear"); +``` + +# --seed-- + +## --seed-contents-- + +```js +function truncateText(str) { + + return str; +} +``` + +# --solutions-- + +```js +function truncateText(str) { + const MAX_WIDTH = 50; + const ELLIPSIS = "..."; + const ELLIPSIS_WIDTH = 3; + const TRUNCATE_LIMIT = MAX_WIDTH - ELLIPSIS_WIDTH; + + const charGroups = { + 'ilI.': 1, + 'fjrt ': 2, + 'abcdeghkmnopqrstuvwxyzJL': 3, + 'ABCDEFGHKMNOPQRSTUVWXYZ': 4 + }; + + function getCharWidth(char) { + for (const key in charGroups) { + if (key.includes(char)) return charGroups[key]; + } + return 3; + } + + function stringWidth(str) { + let totalWidth = 0; + for (const char of str) { + totalWidth += getCharWidth(char); + } + return totalWidth; + } + + if (stringWidth(str) <= MAX_WIDTH) return str; + + let result = ""; + let totalWidth = 0; + + for (const char of str) { + const charWidth = getCharWidth(char); + + if (totalWidth + charWidth > TRUNCATE_LIMIT) break; + + result += char; + totalWidth += charWidth; + } + + return result + ELLIPSIS; +} +``` diff --git a/curriculum/challenges/english/blocks/daily-coding-challenges-python/698a1a863194f1f4e63f645e.md b/curriculum/challenges/english/blocks/daily-coding-challenges-python/698a1a863194f1f4e63f645e.md index 0cd5e60703e..ddcf5d517eb 100644 --- a/curriculum/challenges/english/blocks/daily-coding-challenges-python/698a1a863194f1f4e63f645e.md +++ b/curriculum/challenges/english/blocks/daily-coding-challenges-python/698a1a863194f1f4e63f645e.md @@ -13,7 +13,7 @@ Given a string, return the substring between the two identical characters that h - The returned substring should exclude the matching characters. - If two or more gaps are the same length, return the characters from the first one. -For example, given `"ABCDAC"`, return `"DA"`. +For example, given `"ABCDAC"`, return `"DA"` because: - Only `"A"` and `"C"` repeat in the string. - The number of characters between the two `"A"` characters is 3, and between the `"C"` characters is 2. diff --git a/curriculum/challenges/english/blocks/daily-coding-challenges-python/69a890af247de743333bd4cc.md b/curriculum/challenges/english/blocks/daily-coding-challenges-python/69a890af247de743333bd4cc.md new file mode 100644 index 00000000000..fb1613358a2 --- /dev/null +++ b/curriculum/challenges/english/blocks/daily-coding-challenges-python/69a890af247de743333bd4cc.md @@ -0,0 +1,155 @@ +--- +id: 69a890af247de743333bd4cc +title: "Challenge 223: QR Decoder" +challengeType: 29 +dashedName: challenge-223 +--- + +# --description-- + +Given a 6x6 matrix (array of arrays), representing a QR code, return the string of binary data in the code. + +- The QR code may be given in any rotation of 90 degree increments. +- A correctly oriented code has a 2x2 group of `1`'s (orientation markers) in the bottom-left, top-left, and top-right corners. +- The three 2x2 orientation markers are not part of the binary data. +- The binary data is read left-to-right, top-to-bottom (like a book) when the QR code is correctly oriented. +- A code will always have exactly one valid orientation. + +For example, given: + +```js +[ + "110011", + "110011", + "000000", + "000000", + "110000", + "110001" +] +``` + +or given the same code with a different orientation: + +```js +[ + "110011", + "110011", + "000000", + "000000", + "000011", + "100011" +] +``` + +Return `"000000000000000000000001"`, all the binary data excluding the three 2x2 orientation markers. + +# --hints-- + +`decode_qr(["110011", "110011", "000000", "000000", "110000", "110001"])` should return `"000000000000000000000001"`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertEqual(decode_qr(["110011", "110011", "000000", "000000", "110000", "110001"]), "000000000000000000000001")`) +}}) +``` + +`decode_qr(["100011", "000011", "000000", "000000", "110011", "110011"])` should return `"000000000000000000000001"`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertEqual(decode_qr(["100011", "000011", "000000", "000000", "110011", "110011"]), "000000000000000000000001")`) +}}) +``` + +`decode_qr(["110011", "111111", "010000", "110000", "110011", "110100"])` should return `"001101000011000000110100"`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertEqual(decode_qr(["110011", "111111", "010000", "110000", "110011", "110100"]), "001101000011000000110100")`) +}}) +``` + +`decode_qr(["011011", "101011", "101000", "100010", "110011", "111011"])` should return `"010001000100010101010110"`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertEqual(decode_qr(["011011", "101011", "101000", "100010", "110011", "111011"]), "010001000100010101010110")`) +}}) +``` + +`decode_qr(["111100", "110001", "100011", "001101", "110011", "110011"])` should return `"010000100100100101001110"`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertEqual(decode_qr(["111100", "110001", "100011", "001101", "110011", "110011"]), "010000100100100101001110")`) +}}) +``` + +# --seed-- + +## --seed-contents-- + +```py +def decode_qr(qr_code): + + return qr_code +``` + +# --solutions-- + +```py +def is_oriented(code): + marker_indices = [ + (0, 0), + (0, 1), + (0, 4), + (0, 5), + (1, 0), + (1, 1), + (1, 4), + (1, 5), + (4, 0), + (4, 1), + (5, 0), + (5, 1) + ] + + for row, col in marker_indices: + if code[row][col] != '1': + return False + + return True + + +def rotate(code): + new_code = ['', '', '', '', '', ''] + for i in range(6): + for j in range(5, -1, -1): + new_code[i] += code[j][i] + return new_code + + +def get_data(code): + data = '' + data += code[0][2:4] + data += code[1][2:4] + data += code[2] + data += code[3] + data += code[4][2:] + data += code[5][2:] + return data + + +def decode_qr(qr_code): + code = qr_code[:] + + while not is_oriented(code): + code = rotate(code) + + return get_data(code) +``` diff --git a/curriculum/challenges/english/blocks/daily-coding-challenges-python/69a890af247de743333bd4cd.md b/curriculum/challenges/english/blocks/daily-coding-challenges-python/69a890af247de743333bd4cd.md new file mode 100644 index 00000000000..41f1aac4daf --- /dev/null +++ b/curriculum/challenges/english/blocks/daily-coding-challenges-python/69a890af247de743333bd4cd.md @@ -0,0 +1,123 @@ +--- +id: 69a890af247de743333bd4cd +title: "Challenge 224: Coffee Roast Detector" +challengeType: 29 +dashedName: challenge-224 +--- + +# --description-- + +Given a string representing the beans used to make a cup of coffee, determine the roast of the cup. + +- The given string will contain the following characters, each representing a type of bean: + + - An apostrophe (`'`) is a light roast bean worth 1 point each. + - A dash (`-`) is a medium roast bean worth 2 points each. + - A period (`.`) is a dark roast bean worth 3 points each. + +- The roast level is determined by the average of all the beans. + +Return: + +- `"Light"` if the average is less than 1.75. +- `"Medium"` if the average is 1.75 to 2.5. +- `"Dark"` if the average is greater than 2.5. + +# --hints-- + +`detect_roast("''-''''''-'-''--''''")` should return `"Light"`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertEqual(detect_roast("''-''''''-'-''--''''"), "Light")`) +}}) +``` + +`detect_roast(".'-''-''..'''.-.-''-")` should return `"Medium"`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertEqual(detect_roast(".'-''-''..'''.-.-''-"), "Medium")`) +}}) +``` + +`detect_roast("--.''--'-''.--..-.--")` should return `"Medium"`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertEqual(detect_roast("--.''--'-''.--..-.--"), "Medium")`) +}}) +``` + +`detect_roast("-...'-......-..-...-")` should return `"Dark"`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertEqual(detect_roast("-...'-......-..-...-"), "Dark")`) +}}) +``` + +`detect_roast(".--.-..-......----.'")` should return `"Medium"`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertEqual(detect_roast(".--.-..-......----.'"), "Medium")`) +}}) +``` + +`detect_roast("..-..-..-..-....-.-.")` should return `"Dark"`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertEqual(detect_roast("..-..-..-..-....-.-."), "Dark")`) +}}) +``` + +`detect_roast("-'-''''''..-'.''-'.'")` should return `"Light"`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertEqual(detect_roast("-'-''''''..-'.''-'.'"), "Light")`) +}}) +``` + +# --seed-- + +## --seed-contents-- + +```py +def detect_roast(beans): + + return beans +``` + +# --solutions-- + +```py +def detect_roast(beans): + total = 0 + + for bean in beans: + if bean == "'": + total += 1 + elif bean == "-": + total += 2 + elif bean == ".": + total += 3 + + avg = total / len(beans) + + if avg < 1.75: + return "Light" + elif avg <= 2.5: + return "Medium" + else: + return "Dark" +``` diff --git a/curriculum/challenges/english/blocks/daily-coding-challenges-python/69a890af247de743333bd4ce.md b/curriculum/challenges/english/blocks/daily-coding-challenges-python/69a890af247de743333bd4ce.md new file mode 100644 index 00000000000..6b2e98cd15e --- /dev/null +++ b/curriculum/challenges/english/blocks/daily-coding-challenges-python/69a890af247de743333bd4ce.md @@ -0,0 +1,88 @@ +--- +id: 69a890af247de743333bd4ce +title: "Challenge 225: No Consecutive Repeats" +challengeType: 29 +dashedName: challenge-225 +--- + +# --description-- + +Given a string, determine if it has no repeating characters. + +- A string has no repeats if it does not have the same character two or more times in a row. + +# --hints-- + +`has_no_repeats("hi world")` should return `True`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertIs(has_no_repeats("hi world"), True)`) +}}) +``` + +`has_no_repeats("hello world")` should return `False`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertIs(has_no_repeats("hello world"), False)`) +}}) +``` + +`has_no_repeats("abcdefghijklmnopqrstuvwxyz")` should return `True`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertIs(has_no_repeats("abcdefghijklmnopqrstuvwxyz"), True)`) +}}) +``` + +`has_no_repeats("freeCodeCamp")` should return `False`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertIs(has_no_repeats("freeCodeCamp"), False)`) +}}) +``` + +`has_no_repeats("The quick brown fox jumped over the lazy dog.")` should return `True`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertIs(has_no_repeats("The quick brown fox jumped over the lazy dog."), True)`) +}}) +``` + +`has_no_repeats("Mississippi")` should return `False`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertIs(has_no_repeats("Mississippi"), False)`) +}}) +``` + +# --seed-- + +## --seed-contents-- + +```py +def has_no_repeats(s): + + return s +``` + +# --solutions-- + +```py +def has_no_repeats(s): + for i in range(1, len(s)): + if s[i] == s[i-1]: + return False + return True +``` diff --git a/curriculum/challenges/english/blocks/daily-coding-challenges-python/69a890af247de743333bd4cf.md b/curriculum/challenges/english/blocks/daily-coding-challenges-python/69a890af247de743333bd4cf.md new file mode 100644 index 00000000000..65f17432fe8 --- /dev/null +++ b/curriculum/challenges/english/blocks/daily-coding-challenges-python/69a890af247de743333bd4cf.md @@ -0,0 +1,80 @@ +--- +id: 69a890af247de743333bd4cf +title: "Challenge 226: Passing Exam Count" +challengeType: 29 +dashedName: challenge-226 +--- + +# --description-- + +Given an array of student exam scores and the score needed to pass it, return the number of students that passed the exam. + +# --hints-- + +`passing_count([90, 85, 75, 60, 50], 70)` should return `3`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertEqual(passing_count([90, 85, 75, 60, 50], 70), 3)`) +}}) +``` + +`passing_count([100, 80, 75, 88, 72, 74, 79, 71, 60, 92], 75)` should return `6`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertEqual(passing_count([100, 80, 75, 88, 72, 74, 79, 71, 60, 92], 75), 6)`) +}}) +``` + +`passing_count([79, 60, 88, 72, 74, 59, 75, 71, 80, 92], 60)` should return `9`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertEqual(passing_count([79, 60, 88, 72, 74, 59, 75, 71, 80, 92], 60), 9)`) +}}) +``` + +`passing_count([76, 79, 80, 70, 71, 65, 79, 78, 59, 72], 85)` should return `0`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertEqual(passing_count([76, 79, 80, 70, 71, 65, 79, 78, 59, 72], 85), 0)`) +}}) +``` + +`passing_count([84, 65, 98, 53, 58, 71, 91, 80, 92, 70, 73, 83, 86, 69, 84, 77, 72, 58, 69, 75, 66, 68, 72, 96, 90, 63, 88, 63, 80, 67], 60)` should return `27`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertEqual(passing_count([84, 65, 98, 53, 58, 71, 91, 80, 92, 70, 73, 83, 86, 69, 84, 77, 72, 58, 69, 75, 66, 68, 72, 96, 90, 63, 88, 63, 80, 67], 60), 27)`) +}}) +``` + +# --seed-- + +## --seed-contents-- + +```py +def passing_count(scores, passing_score): + + return scores +``` + +# --solutions-- + +```py +def passing_count(scores, passing_score): + count = 0 + + for score in scores: + if score >= passing_score: + count += 1 + + return count +``` diff --git a/curriculum/challenges/english/blocks/daily-coding-challenges-python/69a890af247de743333bd4d0.md b/curriculum/challenges/english/blocks/daily-coding-challenges-python/69a890af247de743333bd4d0.md new file mode 100644 index 00000000000..cdd6ec295ed --- /dev/null +++ b/curriculum/challenges/english/blocks/daily-coding-challenges-python/69a890af247de743333bd4d0.md @@ -0,0 +1,76 @@ +--- +id: 69a890af247de743333bd4d0 +title: "Challenge 227: Cooldown Time" +challengeType: 29 +dashedName: challenge-227 +--- + +# --description-- + +Given two timestamps, the first representing when a user finished an exam, and the second representing the current time, determine whether the user can take an exam again. + +- Both timestamps will be given the format: `"YYYY-MM-DDTHH:MM:SS"`, for example `"2026-03-25T14:00:00"`. Note that the time is 24-hour clock. +- A user must wait at least 48 hours before retaking an exam. + +# --hints-- + +`can_retake("2026-03-23T08:00:00", "2026-03-25T14:00:00")` should return `True`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertIs(can_retake("2026-03-23T08:00:00", "2026-03-25T14:00:00"), True)`) +}}) +``` + +`can_retake("2026-03-24T14:00:00", "2026-03-25T10:00:00")` should return `False`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertIs(can_retake("2026-03-24T14:00:00", "2026-03-25T10:00:00"), False)`) +}}) +``` + +`can_retake("2026-03-23T09:25:00", "2026-03-25T09:25:00")` should return `True`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertIs(can_retake("2026-03-23T09:25:00", "2026-03-25T09:25:00"), True)`) +}}) +``` + +`can_retake("2026-03-25T11:50:00", "2026-03-23T11:49:59")` should return `False`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertIs(can_retake("2026-03-25T11:50:00", "2026-03-23T11:49:59"), False)`) +}}) +``` + +# --seed-- + +## --seed-contents-- + +```py +def can_retake(finish_time, current_time): + + return finish_time +``` + +# --solutions-- + +```py +from datetime import datetime, timedelta + +def can_retake(finish_time, current_time): + fmt = "%Y-%m-%dT%H:%M:%S" + finished_dt = datetime.strptime(finish_time, fmt) + current_dt = datetime.strptime(current_time, fmt) + diff = current_dt - finished_dt + cooldown = timedelta(hours=48) + + return diff >= cooldown +``` diff --git a/curriculum/challenges/english/blocks/daily-coding-challenges-python/69a890af247de743333bd4d1.md b/curriculum/challenges/english/blocks/daily-coding-challenges-python/69a890af247de743333bd4d1.md new file mode 100644 index 00000000000..10415ba121d --- /dev/null +++ b/curriculum/challenges/english/blocks/daily-coding-challenges-python/69a890af247de743333bd4d1.md @@ -0,0 +1,134 @@ +--- +id: 69a890af247de743333bd4d1 +title: "Challenge 228: Movie Night" +challengeType: 29 +dashedName: challenge-228 +--- + +# --description-- + +Given a string for the day of the week, another string for a showtime, and an integer number of tickets, return the total cost of the movie tickets for that showing. + +The given day will be one of: + +- `"Monday"` +- `"Tuesday"` +- `"Wednesday"` +- `"Thursday"` +- `"Friday"` +- `"Saturday"` +- `"Sunday"` + +The showtime will be given in the format `"H:MMam"` or `"H:MMpm"`. For example `"10:00am"` or `"10:00pm"`. + +Return the total cost in the format `"$D.CC"` using these rules: + +- Weekend (Friday - Sunday): $12.00 per ticket. +- Weekday (Monday - Thursday): $10.00 per ticket. +- Matinee (before 5:00pm): subtract $2.00 per ticket (except on Tuesdays). +- Tuesdays: all tickets are $5.00 each. + +# --hints-- + +`get_movie_night_cost("Saturday", "10:00pm", 1)` should return `"$12.00"`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertEqual(get_movie_night_cost("Saturday", "10:00pm", 1), "$12.00")`) +}}) +``` + +`get_movie_night_cost("Sunday", "10:00am", 1)` should return `"$10.00"`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertEqual(get_movie_night_cost("Sunday", "10:00am", 1), "$10.00")`) +}}) +``` + +`get_movie_night_cost("Tuesday", "7:20pm", 2)` should return `"$10.00"`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertEqual(get_movie_night_cost("Tuesday", "7:20pm", 2), "$10.00")`) +}}) +``` + +`get_movie_night_cost("Wednesday", "5:40pm", 3)` should return `"$30.00"`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertEqual(get_movie_night_cost("Wednesday", "5:40pm", 3), "$30.00")`) +}}) +``` + +`get_movie_night_cost("Monday", "11:50am", 4)` should return `"$32.00"`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertEqual(get_movie_night_cost("Monday", "11:50am", 4), "$32.00")`) +}}) +``` + +`get_movie_night_cost("Friday", "4:30pm", 5)` should return `"$50.00"`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertEqual(get_movie_night_cost("Friday", "4:30pm", 5), "$50.00")`) +}}) +``` + +`get_movie_night_cost("Tuesday", "11:30am", 1)` should return `"$5.00"`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertEqual(get_movie_night_cost("Tuesday", "11:30am", 1), "$5.00")`) +}}) +``` + +# --seed-- + +## --seed-contents-- + +```py +def get_movie_night_cost(day, showtime, number_of_tickets): + + return day +``` + +# --solutions-- + +```py +def get_movie_night_cost(day, showtime, number_of_tickets): + if day == "Tuesday": + price = 5 + else: + if day in ["Friday", "Saturday", "Sunday"]: + price = 12 + else: + price = 10 + + hour = int(showtime.split(":")[0]) + period = showtime[-2:] + + hour24 = hour + + if period == "pm" and hour != 12: + hour24 += 12 + if period == "am" and hour == 12: + hour24 = 0 + + if hour24 < 17: + price -= 2 + + total = price * number_of_tickets + + return f"${total:.2f}" +``` diff --git a/curriculum/challenges/english/blocks/daily-coding-challenges-python/69a890af247de743333bd4d2.md b/curriculum/challenges/english/blocks/daily-coding-challenges-python/69a890af247de743333bd4d2.md new file mode 100644 index 00000000000..c3e71ec20d3 --- /dev/null +++ b/curriculum/challenges/english/blocks/daily-coding-challenges-python/69a890af247de743333bd4d2.md @@ -0,0 +1,130 @@ +--- +id: 69a890af247de743333bd4d2 +title: "Challenge 229: Truncate the Text 2" +challengeType: 29 +dashedName: challenge-229 +--- + +# --description-- + +Given a string, return a new string that is truncated so that the total width of the characters does not exceed 50 units. + +Each character has a specific width: + +| Letters | Width | +| - | - | +| `"ilI"` | 1 | +| `"fjrt"` | 2 | +| `"abcdeghkmnopqrstuvwxyzJL"` | 3 | +| `"ABCDEFGHKMNOPQRSTUVWXYZ"` | 4 | + +The table above includes all upper and lower case letters. Additionally: + +- Spaces (`" "`) have a width of 2 +- Periods (`"."`) have a width of 1 + +- If the given string is 50 units or less, return the string as-is, otherwise +- Truncate the string and add three periods at the end (`"..."`) so it's total width, including the three periods, is as close as possible to 60 units without going over. + +# --hints-- + +`truncate_text("The quick brown fox")` should return `"The quick brown f..."`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertEqual(truncate_text("The quick brown fox"), "The quick brown f...")`) +}}) +``` + +`truncate_text("The silky smooth sloth")` should return `truncate_text("The silky smooth sloth")`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertEqual(truncate_text("The silky smooth sloth"), truncate_text("The silky smooth sloth"))`) +}}) +``` + +`truncate_text("THE LOUD BRIGHT BIRD")` should return `"THE LOUD BRIG..."`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertEqual(truncate_text("THE LOUD BRIGHT BIRD"), "THE LOUD BRIG...")`) +}}) +``` + +`truncate_text("The fast striped zebra")` should return `"The fast striped z..."`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertEqual(truncate_text("The fast striped zebra"), "The fast striped z...")`) +}}) +``` + +`truncate_text("The big black bear")` should return `"The big black bear"`. + +```js +({test: () => { runPython(` +from unittest import TestCase +TestCase().assertEqual(truncate_text("The big black bear"), "The big black bear")`) +}}) +``` + +# --seed-- + +## --seed-contents-- + +```py +def truncate_text(s): + + return s +``` + +# --solutions-- + +```py +def truncate_text(s): + MAX_WIDTH = 50 + ELLIPSIS = "..." + ELLIPSIS_WIDTH = 3 + TRUNCATE_LIMIT = MAX_WIDTH - ELLIPSIS_WIDTH + + char_groups = { + "ilI.": 1, + "fjrt ": 2, + "abcdeghkmnopqrstuvwxyzJL": 3, + "ABCDEFGHKMNOPQRSTUVWXYZ": 4 + } + + def get_char_width(char): + for key, width in char_groups.items(): + if char in key: + return width + return 3 + + def string_width(string): + total = 0 + for char in string: + total += get_char_width(char) + return total + + if string_width(s) <= MAX_WIDTH: + return s + + result = "" + total_width = 0 + + for char in s: + char_width = get_char_width(char) + + if total_width + char_width > TRUNCATE_LIMIT: + break + + result += char + total_width += char_width + + return result + ELLIPSIS +``` diff --git a/curriculum/structure/blocks/daily-coding-challenges-javascript.json b/curriculum/structure/blocks/daily-coding-challenges-javascript.json index d0c5857ce60..579412034ca 100644 --- a/curriculum/structure/blocks/daily-coding-challenges-javascript.json +++ b/curriculum/structure/blocks/daily-coding-challenges-javascript.json @@ -894,6 +894,34 @@ { "id": "699c8e045ee7cb94ed2322dd", "title": "Challenge 222: Equinox Shadows" + }, + { + "id": "69a890af247de743333bd4cc", + "title": "Challenge 223: QR Decoder" + }, + { + "id": "69a890af247de743333bd4cd", + "title": "Challenge 224: Coffee Roast Detector" + }, + { + "id": "69a890af247de743333bd4ce", + "title": "Challenge 225: No Consecutive Repeats" + }, + { + "id": "69a890af247de743333bd4cf", + "title": "Challenge 226: Passing Exam Count" + }, + { + "id": "69a890af247de743333bd4d0", + "title": "Challenge 227: Cooldown Time" + }, + { + "id": "69a890af247de743333bd4d1", + "title": "Challenge 228: Movie Night" + }, + { + "id": "69a890af247de743333bd4d2", + "title": "Challenge 229: Truncate the Text 2" } ] } diff --git a/curriculum/structure/blocks/daily-coding-challenges-python.json b/curriculum/structure/blocks/daily-coding-challenges-python.json index f14c814f7d6..d6321795023 100644 --- a/curriculum/structure/blocks/daily-coding-challenges-python.json +++ b/curriculum/structure/blocks/daily-coding-challenges-python.json @@ -893,6 +893,34 @@ { "id": "699c8e045ee7cb94ed2322dd", "title": "Challenge 222: Equinox Shadows" + }, + { + "id": "69a890af247de743333bd4cc", + "title": "Challenge 223: QR Decoder" + }, + { + "id": "69a890af247de743333bd4cd", + "title": "Challenge 224: Coffee Roast Detector" + }, + { + "id": "69a890af247de743333bd4ce", + "title": "Challenge 225: No Consecutive Repeats" + }, + { + "id": "69a890af247de743333bd4cf", + "title": "Challenge 226: Passing Exam Count" + }, + { + "id": "69a890af247de743333bd4d0", + "title": "Challenge 227: Cooldown Time" + }, + { + "id": "69a890af247de743333bd4d1", + "title": "Challenge 228: Movie Night" + }, + { + "id": "69a890af247de743333bd4d2", + "title": "Challenge 229: Truncate the Text 2" } ] } diff --git a/tools/daily-challenges/seed-daily-challenges.ts b/tools/daily-challenges/seed-daily-challenges.ts index 0ba891fd36f..626c7ce77c3 100644 --- a/tools/daily-challenges/seed-daily-challenges.ts +++ b/tools/daily-challenges/seed-daily-challenges.ts @@ -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 = 222; +const EXPECTED_CHALLENGE_COUNT = 229; // 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)**