Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,14 @@
"prerequisites": [],
"difficulty": 8
},
{
"slug": "say",
"name": "Say",
"uuid": "5b643efe-e63b-4598-95f8-a4cb319107de",
"practices": [],
"prerequisites": [],
"difficulty": 8
},
{
"slug": "scrabble-score",
"name": "Scrabble Score",
Expand Down
12 changes: 12 additions & 0 deletions exercises/practice/say/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Instructions

Given a number, your task is to express it in English words exactly as your friend should say it out loud.
Yaʻqūb expects to use numbers from 0 up to 999,999,999,999.

Examples:

- 0 → zero
- 1 → one
- 12 → twelve
- 123 → one hundred twenty-three
- 1,234 → one thousand two hundred thirty-four
6 changes: 6 additions & 0 deletions exercises/practice/say/.docs/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Introduction

Your friend Yaʻqūb works the counter at the busiest deli in town, slicing, weighing, and wrapping orders for a never-ending line of hungry customers.
To keep things moving, each customer takes a numbered ticket when they arrive.

When it’s time to call the next person, Yaʻqūb reads their number out loud, always in full English words to make sure everyone hears it clearly.
19 changes: 19 additions & 0 deletions exercises/practice/say/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"authors": [
"jimmytty"
],
"files": {
"solution": [
"say.sql"
],
"test": [
"say_test.sql"
],
"example": [
".meta/example.sql"
]
},
"blurb": "Given a number from 0 to 999,999,999,999, spell out that number in English.",
"source": "A variation on the JavaRanch CattleDrive, Assignment 4",
"source_url": "https://web.archive.org/web/20240907035912/https://coderanch.com/wiki/718804"
}
147 changes: 147 additions & 0 deletions exercises/practice/say/.meta/example.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
UPDATE say SET result = 'zero' WHERE number = 0;

UPDATE say
SET error = 'input out of range'
WHERE number < 0
OR number >= 1e12
;

DROP TABLE IF EXISTS dict;
CREATE TEMPORARY TABLE dict (
digits INTEGER PRIMARY KEY,
words TEXT NOT NULL
);
INSERT INTO dict (digits, words)
VALUES ( 0, 'zero' ),
( 1, 'one' ),
( 2, 'two' ),
( 3, 'three' ),
( 4, 'four' ),
( 5, 'five' ),
( 6, 'six' ),
( 7, 'seven' ),
( 8, 'eight' ),
( 9, 'nine' ),
(10, 'ten' ),
(11, 'eleven' ),
(12, 'twelve' ),
(13, 'thirteen' ),
(14, 'fourteen' ),
(15, 'fifteen' ),
(16, 'sixteen' ),
(17, 'seventeen'),
(18, 'eighteen' ),
(19, 'nineteen' ),
(20, 'twenty' ),
(30, 'thirty' ),
(40, 'forty' ),
(50, 'fifty' ),
(60, 'sixty' ),
(70, 'seventy' ),
(80, 'eighty' ),
(90, 'ninety' );
WITH dozens (jarray) AS (
SELECT (
WITH RECURSIVE rcte (base, unit, dozen, string) AS (
VALUES (digits, 1, NULL, NULL)
UNION ALL
SELECT digits,
unit + 1,
base + unit,
PRINTF(
'%s-%s',
(SELECT words FROM dict WHERE digits = base),
(SELECT words FROM dict WHERE digits = unit))
FROM rcte
WHERE unit < 10
)
SELECT JSON_GROUP_ARRAY(JSON_ARRAY(dozen, string))
FROM rcte
WHERE dozen NOT NULL
)
FROM dict
WHERE digits BETWEEN 20 AND 90
)
INSERT INTO dict (digits, words)
SELECT JSON_EXTRACT(j.VALUE, '$[0]'), JSON_EXTRACT(j.VALUE, '$[1]')
FROM dozens, JSON_EACH(jarray) j;
INSERT INTO dict
SELECT value * 100,
(SELECT words FROM dict WHERE digits = VALUE) || ' hundred'
FROM GENERATE_SERIES(1, 9);

DROP TABLE IF EXISTS positions;
CREATE TEMPORARY TABLE positions (
pos INTEGER PRIMARY KEY,
words TEXT NOT NULL
);
INSERT INTO positions (pos, words)
VALUES ( 2, 'thousand' ),
( 3, 'million' ),
( 4, 'billion' ),
( 5, 'trillion' ),
( 6, 'quadrillion' ),
( 7, 'quintillion' ),
( 8, 'sextillion' ),
( 9, 'septillion' ),
(10, 'octillion' ),
(11, 'nonillion' ),
(12, 'decillion' ),
(13, 'undecillion' ),
(14, 'duodecillion' ),
(15, 'tredecillion' ),
(16, 'quattuordecillion'),
(17, 'quindecillion' ),
(18, 'sexdecillion' ),
(19, 'septendecillion' ),
(20, 'octodecillion' ),
(21, 'novemdecillion' ),
(22, 'vigintillion' );

UPDATE say
SET result = (
WITH
decompositor (num, thousands, thpos) AS (
WITH RECURSIVE decompositor (num, thousands, thpos) AS (
VALUES (number, NULL, 0)
UNION ALL
SELECT num / 1000,
JSON_ARRAY( num % 1000 - num % 100, (num % 1000) % 100 ),
thpos + 1
FROM decompositor
WHERE num > 0
)
SELECT * FROM decompositor
),
to_strings (thpos, hundred, dozen, pos_str) AS (
SELECT
thpos,
(
SELECT words
FROM dict
WHERE digits = NULLIF(JSON_EXTRACT(thousands, '$[0]'), 0)
),
(
SELECT words
FROM dict
WHERE digits = NULLIF(JSON_EXTRACT(thousands, '$[1]'), 0 )
),
IIF(
JSON_EXTRACT(thousands, '$[0]') +
JSON_EXTRACT(thousands, '$[1]') > 0,
(SELECT words FROM positions WHERE pos = thpos),
NULL
)
FROM decompositor
WHERE thpos > 0
),
to_format (thpos, string) AS (
SELECT thpos, TRIM(PRINTF('%s %s %s', hundred, dozen, pos_str))
FROM to_strings
ORDER BY thpos DESC
)
SELECT TRIM(GROUP_CONCAT(string, ' ')) FROM to_format
)
WHERE error IS NULL
AND number > 0
;
67 changes: 67 additions & 0 deletions exercises/practice/say/.meta/tests.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# This is an auto-generated file.
#
# Regenerating this file via `configlet sync` will:
# - Recreate every `description` key/value pair
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
# - Preserve any other key/value pair
#
# As user-added comments (using the # character) will be removed when this file
# is regenerated, comments can be added via a `comment` key.

[5d22a120-ba0c-428c-bd25-8682235d83e8]
description = "zero"

[9b5eed77-dbf6-439d-b920-3f7eb58928f6]
description = "one"

[7c499be1-612e-4096-a5e1-43b2f719406d]
description = "fourteen"

[f541dd8e-f070-4329-92b4-b7ce2fcf06b4]
description = "twenty"

[d78601eb-4a84-4bfa-bf0e-665aeb8abe94]
description = "twenty-two"

[f010d4ca-12c9-44e9-803a-27789841adb1]
description = "thirty"

[738ce12d-ee5c-4dfb-ad26-534753a98327]
description = "ninety-nine"

[e417d452-129e-4056-bd5b-6eb1df334dce]
description = "one hundred"

[d6924f30-80ba-4597-acf6-ea3f16269da8]
description = "one hundred twenty-three"

[2f061132-54bc-4fd4-b5df-0a3b778959b9]
description = "two hundred"

[feed6627-5387-4d38-9692-87c0dbc55c33]
description = "nine hundred ninety-nine"

[3d83da89-a372-46d3-b10d-de0c792432b3]
description = "one thousand"

[865af898-1d5b-495f-8ff0-2f06d3c73709]
description = "one thousand two hundred thirty-four"

[b6a3f442-266e-47a3-835d-7f8a35f6cf7f]
description = "one million"

[2cea9303-e77e-4212-b8ff-c39f1978fc70]
description = "one million two thousand three hundred forty-five"

[3e240eeb-f564-4b80-9421-db123f66a38f]
description = "one billion"

[9a43fed1-c875-4710-8286-5065d73b8a9e]
description = "a big number"

[49a6a17b-084e-423e-994d-a87c0ecc05ef]
description = "numbers below zero are out of range"

[4d6492eb-5853-4d16-9d34-b0f61b261fd9]
description = "numbers above 999,999,999,999 are out of range"
11 changes: 11 additions & 0 deletions exercises/practice/say/create_fixture.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
DROP TABLE IF EXISTS say;
CREATE TABLE say (
number INTEGER NOT NULL,
result TEXT,
error TEXT
);

.mode csv
.import ./data.csv say

UPDATE say SET result = NULL, error = NULL;
38 changes: 38 additions & 0 deletions exercises/practice/say/create_test_table.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
DROP TABLE IF EXISTS tests;
CREATE TABLE IF NOT EXISTS tests (
-- uuid and description are taken from the test.toml file
uuid TEXT PRIMARY KEY,
description TEXT NOT NULL,
-- The following section is needed by the online test-runner
status TEXT DEFAULT 'fail',
message TEXT,
output TEXT,
test_code TEXT,
task_id INTEGER DEFAULT NULL,
-- Here are columns for the actual tests
number INTEGER NOT NULL,
expected_result TEXT,
expected_error TEXT
);

INSERT INTO tests (uuid, description, number, expected_result, expected_error)
VALUES
('5d22a120-ba0c-428c-bd25-8682235d83e8', 'zero', 0, 'zero', NULL),
('9b5eed77-dbf6-439d-b920-3f7eb58928f6', 'one', 1, 'one', NULL),
('7c499be1-612e-4096-a5e1-43b2f719406d', 'fourteen', 14, 'fourteen', NULL),
('f541dd8e-f070-4329-92b4-b7ce2fcf06b4', 'twenty', 20, 'twenty', NULL),
('d78601eb-4a84-4bfa-bf0e-665aeb8abe94', 'twenty-two', 22, 'twenty-two', NULL),
('f010d4ca-12c9-44e9-803a-27789841adb1', 'thirty', 30, 'thirty', NULL),
('738ce12d-ee5c-4dfb-ad26-534753a98327', 'ninety-nine', 99, 'ninety-nine', NULL),
('e417d452-129e-4056-bd5b-6eb1df334dce', 'one hundred', 100, 'one hundred', NULL),
('d6924f30-80ba-4597-acf6-ea3f16269da8', 'one hundred twenty-three', 123, 'one hundred twenty-three', NULL),
('2f061132-54bc-4fd4-b5df-0a3b778959b9', 'two hundred', 200, 'two hundred', NULL),
('feed6627-5387-4d38-9692-87c0dbc55c33', 'nine hundred ninety-nine', 999, 'nine hundred ninety-nine', NULL),
('3d83da89-a372-46d3-b10d-de0c792432b3', 'one thousand', 1000, 'one thousand', NULL),
('865af898-1d5b-495f-8ff0-2f06d3c73709', 'one thousand two hundred thirty-four', 1234, 'one thousand two hundred thirty-four', NULL),
('b6a3f442-266e-47a3-835d-7f8a35f6cf7f', 'one million', 1000000, 'one million', NULL),
('2cea9303-e77e-4212-b8ff-c39f1978fc70', 'one million two thousand three hundred forty-five', 1002345, 'one million two thousand three hundred forty-five', NULL),
('3e240eeb-f564-4b80-9421-db123f66a38f', 'one billion', 1000000000, 'one billion', NULL),
('9a43fed1-c875-4710-8286-5065d73b8a9e', 'a big number', 987654321123, 'nine hundred eighty-seven billion six hundred fifty-four million three hundred twenty-one thousand one hundred twenty-three', NULL),
('49a6a17b-084e-423e-994d-a87c0ecc05ef', 'numbers below zero are out of range', -1, NULL, 'input out of range'),
('4d6492eb-5853-4d16-9d34-b0f61b261fd9', 'numbers above 999,999,999,999 are out of range', 1000000000000, NULL, 'input out of range');
19 changes: 19 additions & 0 deletions exercises/practice/say/data.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
0,,
1,,
14,,
20,,
22,,
30,,
99,,
100,,
123,,
200,,
999,,
1000,,
1234,,
1000000,,
1002345,,
1000000000,,
987654321123,,
-1,,
1000000000000,,
8 changes: 8 additions & 0 deletions exercises/practice/say/say.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
-- Schema:
-- CREATE TABLE say (
-- number INTEGER NOT NULL,
-- result TEXT,
-- error TEXT
-- );
--
-- Task: update the say table and set the result or the error columns based on the number.
48 changes: 48 additions & 0 deletions exercises/practice/say/say_test.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
-- Create database:
.read ./create_fixture.sql

-- Read user student solution and save any output as markdown in user_output.md:
.mode markdown
.output user_output.md
.read ./say.sql
.output

-- Create a clean testing environment:
.read ./create_test_table.sql

-- Comparison of user input and the tests updates the status for each test:
UPDATE tests
SET status = 'pass'
FROM (SELECT number, result, error FROM say) AS actual
WHERE actual.number = tests.NUMBER
AND (actual.result = tests.expected_result
OR COALESCE(actual.result, tests.expected_result) ISNULL)
AND (actual.error = tests.expected_error
OR COALESCE(actual.error, tests.expected_error) ISNULL);

-- Update message for failed tests to give helpful information:
UPDATE tests
SET message = (
'Result for "' || actual.NUMBER || '"' || ' is <'
|| PRINTF('result=%s and error="%s"',
COALESCE(actual.result, 'NULL'),
COALESCE(actual.error, 'NULL'))
|| '> but should be <'
|| PRINTF('result=%s and error="%s"',
COALESCE(tests.expected_result, '"NULL"'),
COALESCE(tests.expected_error, 'NULL'))
|| '>'
)
FROM (SELECT number, result, error FROM say) AS actual
WHERE (actual.number) = tests.number AND tests.status = 'fail';

-- Save results to ./output.json (needed by the online test-runner)
.mode json
.once './output.json'
SELECT description, status, message, output, test_code, task_id
FROM tests;

-- Display test results in readable form for the student:
.mode table
SELECT description, status, message
FROM tests;