diff --git a/config.json b/config.json index 78e27ec..3e286bf 100644 --- a/config.json +++ b/config.json @@ -201,6 +201,14 @@ "practices": [], "prerequisites": [], "difficulty": 8 + }, + { + "slug": "pascals-triangle", + "name": "Pascal's Triangle", + "uuid": "fb614e0d-ad10-4710-8785-5ab07fd9eb5a", + "practices": [], + "prerequisites": [], + "difficulty": 8 } ] }, diff --git a/exercises/practice/pascals-triangle/.docs/instructions.md b/exercises/practice/pascals-triangle/.docs/instructions.md new file mode 100644 index 0000000..f556785 --- /dev/null +++ b/exercises/practice/pascals-triangle/.docs/instructions.md @@ -0,0 +1,14 @@ +# Instructions + +Compute Pascal's triangle up to a given number of rows. + +In Pascal's Triangle each number is computed by adding the numbers to the right and left of the current position in the previous row. + +```text + 1 + 1 1 + 1 2 1 + 1 3 3 1 +1 4 6 4 1 +# ... etc +``` diff --git a/exercises/practice/pascals-triangle/.meta/config.json b/exercises/practice/pascals-triangle/.meta/config.json new file mode 100644 index 0000000..19814dc --- /dev/null +++ b/exercises/practice/pascals-triangle/.meta/config.json @@ -0,0 +1,22 @@ +{ + "authors": [ + "Steffan153" + ], + "files": { + "solution": [ + "pascals-triangle.sql" + ], + "test": [ + "pascals-triangle_test.sql" + ], + "example": [ + ".meta/example.sql" + ], + "editor": [ + "data.csv" + ] + }, + "blurb": "Compute Pascal's triangle up to a given number of rows.", + "source": "Pascal's Triangle at Wolfram Math World", + "source_url": "https://www.wolframalpha.com/input/?i=Pascal%27s+triangle" +} diff --git a/exercises/practice/pascals-triangle/.meta/example.sql b/exercises/practice/pascals-triangle/.meta/example.sql new file mode 100644 index 0000000..3b91bdc --- /dev/null +++ b/exercises/practice/pascals-triangle/.meta/example.sql @@ -0,0 +1,23 @@ +UPDATE "pascals-triangle" +SET result = ( + WITH RECURSIVE counter(k) AS ( + SELECT 1 UNION ALL + SELECT k + 1 FROM counter WHERE k < input + ) + + SELECT group_concat( + ( + WITH RECURSIVE nums(idx, s) AS ( + SELECT 1, 1 UNION ALL + SELECT idx + 1, s * k / idx - s FROM nums WHERE idx < k + ) + + SELECT group_concat(s, ' ') FROM nums + ), + char(10) -- newline + ) FROM counter +); + +UPDATE "pascals-triangle" +SET result = '' +WHERE input = 0; diff --git a/exercises/practice/pascals-triangle/.meta/tests.toml b/exercises/practice/pascals-triangle/.meta/tests.toml new file mode 100644 index 0000000..2db0ee5 --- /dev/null +++ b/exercises/practice/pascals-triangle/.meta/tests.toml @@ -0,0 +1,34 @@ +# 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. + +[9920ce55-9629-46d5-85d6-4201f4a4234d] +description = "zero rows" + +[70d643ce-a46d-4e93-af58-12d88dd01f21] +description = "single row" + +[a6e5a2a2-fc9a-4b47-9f4f-ed9ad9fbe4bd] +description = "two rows" + +[97206a99-79ba-4b04-b1c5-3c0fa1e16925] +description = "three rows" + +[565a0431-c797-417c-a2c8-2935e01ce306] +description = "four rows" + +[06f9ea50-9f51-4eb2-b9a9-c00975686c27] +description = "five rows" + +[c3912965-ddb4-46a9-848e-3363e6b00b13] +description = "six rows" + +[6cb26c66-7b57-4161-962c-81ec8c99f16b] +description = "ten rows" diff --git a/exercises/practice/pascals-triangle/create_fixture.sql b/exercises/practice/pascals-triangle/create_fixture.sql new file mode 100644 index 0000000..2771304 --- /dev/null +++ b/exercises/practice/pascals-triangle/create_fixture.sql @@ -0,0 +1,8 @@ +DROP TABLE IF EXISTS "pascals-triangle"; +CREATE TABLE "pascals-triangle" ( + "input" INT, + "result" TEXT +); + +.mode csv +.import ./data.csv pascals-triangle diff --git a/exercises/practice/pascals-triangle/data.csv b/exercises/practice/pascals-triangle/data.csv new file mode 100644 index 0000000..be0ab69 --- /dev/null +++ b/exercises/practice/pascals-triangle/data.csv @@ -0,0 +1,8 @@ +0,"" +1,"" +2,"" +3,"" +4,"" +5,"" +6,"" +10,"" \ No newline at end of file diff --git a/exercises/practice/pascals-triangle/pascals-triangle.sql b/exercises/practice/pascals-triangle/pascals-triangle.sql new file mode 100644 index 0000000..ea04e78 --- /dev/null +++ b/exercises/practice/pascals-triangle/pascals-triangle.sql @@ -0,0 +1,2 @@ +-- Schema: CREATE TABLE "pascals-triangle" ("input" INT, "result" TEXT); +-- Task: update the pascals-triangle table and set the result based on the input field. diff --git a/exercises/practice/pascals-triangle/pascals-triangle_test.sql b/exercises/practice/pascals-triangle/pascals-triangle_test.sql new file mode 100644 index 0000000..90249f0 --- /dev/null +++ b/exercises/practice/pascals-triangle/pascals-triangle_test.sql @@ -0,0 +1,48 @@ +-- Setup test table and read in student solution: +.read ./test_setup.sql + +-- Test cases: +INSERT INTO tests (name, uuid, + input, expected) + VALUES + ('zero rows', '9920ce55-9629-46d5-85d6-4201f4a4234d', 0, ''), + ('single row', '70d643ce-a46d-4e93-af58-12d88dd01f21', 1, '1'), + ('two rows', 'a6e5a2a2-fc9a-4b47-9f4f-ed9ad9fbe4bd', 2, '1 +1 1'), + ('three rows', '97206a99-79ba-4b04-b1c5-3c0fa1e16925', 3, '1 +1 1 +1 2 1'), + ('four rows', '565a0431-c797-417c-a2c8-2935e01ce306', 4, '1 +1 1 +1 2 1 +1 3 3 1'), + ('five rows', '06f9ea50-9f51-4eb2-b9a9-c00975686c27', 5, '1 +1 1 +1 2 1 +1 3 3 1 +1 4 6 4 1'), + ('six rows', 'c3912965-ddb4-46a9-848e-3363e6b00b13', 6, '1 +1 1 +1 2 1 +1 3 3 1 +1 4 6 4 1 +1 5 10 10 5 1'), + ('ten rows', '6cb26c66-7b57-4161-962c-81ec8c99f16b', 10, '1 +1 1 +1 2 1 +1 3 3 1 +1 4 6 4 1 +1 5 10 10 5 1 +1 6 15 20 15 6 1 +1 7 21 35 35 21 7 1 +1 8 28 56 70 56 28 8 1 +1 9 36 84 126 126 84 36 9 1'); + +-- Comparison of user input and the tests updates the status for each test: +UPDATE tests +SET status = 'pass' +FROM (SELECT input, result FROM "pascals-triangle") AS actual +WHERE (actual.input, actual.result) = (tests.input, tests.expected); + +-- Write results and debug info: +.read ./test_reporter.sql diff --git a/exercises/practice/pascals-triangle/test_reporter.sql b/exercises/practice/pascals-triangle/test_reporter.sql new file mode 100644 index 0000000..8d6ce54 --- /dev/null +++ b/exercises/practice/pascals-triangle/test_reporter.sql @@ -0,0 +1,16 @@ +-- Update message for failed tests to give helpful information: +UPDATE tests +SET message = 'Result for ' || actual.input || ' is: "' || actual.result || '", but should be: "' || tests.expected || '"' +FROM (SELECT input, result FROM "pascals-triangle") AS actual +WHERE actual.input = tests.input AND tests.status = 'fail'; + +-- Save results to ./output.json (needed by the online test-runner) +.mode json +.once './output.json' +SELECT name, status, message, output, test_code, task_id +FROM tests; + +-- Display test results in readable form for the student: +.mode table +SELECT name, status, message +FROM tests; diff --git a/exercises/practice/pascals-triangle/test_setup.sql b/exercises/practice/pascals-triangle/test_setup.sql new file mode 100644 index 0000000..d3a800c --- /dev/null +++ b/exercises/practice/pascals-triangle/test_setup.sql @@ -0,0 +1,25 @@ +-- 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 ./pascals-triangle.sql +.output + +-- Create a clean testing environment: +DROP TABLE IF EXISTS tests; +CREATE TABLE IF NOT EXISTS tests ( + -- uuid and name (description) are taken from the test.toml file + uuid TEXT PRIMARY KEY, + name 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 + input INT NOT NULL, + expected TEXT NOT NULL +);