diff --git a/config.json b/config.json index 3e286bf..bfe4b2f 100644 --- a/config.json +++ b/config.json @@ -202,6 +202,14 @@ "prerequisites": [], "difficulty": 8 }, + { + "slug": "matching-brackets", + "name": "Matching Brackets", + "uuid": "cc2a9d38-4d01-479a-a7d1-f1a5662cbc3e", + "practices": [], + "prerequisites": [], + "difficulty": 8 + }, { "slug": "pascals-triangle", "name": "Pascal's Triangle", diff --git a/exercises/practice/matching-brackets/.docs/instructions.md b/exercises/practice/matching-brackets/.docs/instructions.md new file mode 100644 index 0000000..ea17084 --- /dev/null +++ b/exercises/practice/matching-brackets/.docs/instructions.md @@ -0,0 +1,5 @@ +# Instructions + +Given a string containing brackets `[]`, braces `{}`, parentheses `()`, or any combination thereof, verify that any and all pairs are matched and nested correctly. +Any other characters should be ignored. +For example, `"{what is (42)}?"` is balanced and `"[text}"` is not. diff --git a/exercises/practice/matching-brackets/.docs/introduction.md b/exercises/practice/matching-brackets/.docs/introduction.md new file mode 100644 index 0000000..0618221 --- /dev/null +++ b/exercises/practice/matching-brackets/.docs/introduction.md @@ -0,0 +1,8 @@ +# Introduction + +You're given the opportunity to write software for the Bracketeer™, an ancient but powerful mainframe. +The software that runs on it is written in a proprietary language. +Much of its syntax is familiar, but you notice _lots_ of brackets, braces and parentheses. +Despite the Bracketeer™ being powerful, it lacks flexibility. +If the source code has any unbalanced brackets, braces or parentheses, the Bracketeer™ crashes and must be rebooted. +To avoid such a scenario, you start writing code that can verify that brackets, braces, and parentheses are balanced before attempting to run it on the Bracketeer™. diff --git a/exercises/practice/matching-brackets/.meta/config.json b/exercises/practice/matching-brackets/.meta/config.json new file mode 100644 index 0000000..6fb22b0 --- /dev/null +++ b/exercises/practice/matching-brackets/.meta/config.json @@ -0,0 +1,21 @@ +{ + "authors": [ + "Steffan153" + ], + "files": { + "solution": [ + "matching-brackets.sql" + ], + "test": [ + "matching-brackets_test.sql" + ], + "example": [ + ".meta/example.sql" + ], + "editor": [ + "data.csv" + ] + }, + "blurb": "Make sure the brackets and braces all match.", + "source": "Ginna Baker" +} diff --git a/exercises/practice/matching-brackets/.meta/example.sql b/exercises/practice/matching-brackets/.meta/example.sql new file mode 100644 index 0000000..dfcc3f1 --- /dev/null +++ b/exercises/practice/matching-brackets/.meta/example.sql @@ -0,0 +1,31 @@ +ALTER TABLE "matching-brackets" +ADD brackets TEXT DEFAULT ''; + +PRAGMA recursive_triggers = ON; + +CREATE TRIGGER IF NOT EXISTS update_backets + AFTER UPDATE + ON "matching-brackets" + WHEN NEW.brackets != OLD.brackets +BEGIN + UPDATE "matching-brackets" + SET brackets = REPLACE(REPLACE(REPLACE(brackets, '()', ''), '[]', ''), '{}', '') + WHERE brackets = NEW.brackets; +END; + +UPDATE "matching-brackets" +SET brackets = ( + WITH cnt(n) AS ( + SELECT 1 + UNION ALL + SELECT n + 1 FROM cnt WHERE n <= LENGTH(input) + ) + + -- clean the input to only have ()[]{} characters + SELECT group_concat(SUBSTR(input, n, 1), '') + FROM cnt + WHERE '()[]{}' LIKE ('%' || SUBSTR(input, n, 1) || '%') +); + +UPDATE "matching-brackets" +SET result = (brackets = ''); diff --git a/exercises/practice/matching-brackets/.meta/tests.toml b/exercises/practice/matching-brackets/.meta/tests.toml new file mode 100644 index 0000000..35a98a0 --- /dev/null +++ b/exercises/practice/matching-brackets/.meta/tests.toml @@ -0,0 +1,70 @@ +# 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. + +[81ec11da-38dd-442a-bcf9-3de7754609a5] +description = "paired square brackets" + +[287f0167-ac60-4b64-8452-a0aa8f4e5238] +description = "empty string" + +[6c3615a3-df01-4130-a731-8ef5f5d78dac] +description = "unpaired brackets" + +[9d414171-9b98-4cac-a4e5-941039a97a77] +description = "wrong ordered brackets" + +[f0f97c94-a149-4736-bc61-f2c5148ffb85] +description = "wrong closing bracket" + +[754468e0-4696-4582-a30e-534d47d69756] +description = "paired with whitespace" + +[ba84f6ee-8164-434a-9c3e-b02c7f8e8545] +description = "partially paired brackets" + +[3c86c897-5ff3-4a2b-ad9b-47ac3a30651d] +description = "simple nested brackets" + +[2d137f2c-a19e-4993-9830-83967a2d4726] +description = "several paired brackets" + +[2e1f7b56-c137-4c92-9781-958638885a44] +description = "paired and nested brackets" + +[84f6233b-e0f7-4077-8966-8085d295c19b] +description = "unopened closing brackets" + +[9b18c67d-7595-4982-b2c5-4cb949745d49] +description = "unpaired and nested brackets" + +[a0205e34-c2ac-49e6-a88a-899508d7d68e] +description = "paired and wrong nested brackets" + +[1d5c093f-fc84-41fb-8c2a-e052f9581602] +description = "paired and wrong nested brackets but innermost are correct" + +[ef47c21b-bcfd-4998-844c-7ad5daad90a8] +description = "paired and incomplete brackets" + +[a4675a40-a8be-4fc2-bc47-2a282ce6edbe] +description = "too many closing brackets" + +[a345a753-d889-4b7e-99ae-34ac85910d1a] +description = "early unexpected brackets" + +[21f81d61-1608-465a-b850-baa44c5def83] +description = "early mismatched brackets" + +[99255f93-261b-4435-a352-02bdecc9bdf2] +description = "math expression" + +[8e357d79-f302-469a-8515-2561877256a1] +description = "complex latex expression" diff --git a/exercises/practice/matching-brackets/create_fixture.sql b/exercises/practice/matching-brackets/create_fixture.sql new file mode 100644 index 0000000..a63fa2e --- /dev/null +++ b/exercises/practice/matching-brackets/create_fixture.sql @@ -0,0 +1,8 @@ +DROP TABLE IF EXISTS "matching-brackets"; +CREATE TABLE "matching-brackets" ( + "input" TEXT, + "result" BOOLEAN +); + +.mode csv +.import ./data.csv matching-brackets diff --git a/exercises/practice/matching-brackets/data.csv b/exercises/practice/matching-brackets/data.csv new file mode 100644 index 0000000..dcd5124 --- /dev/null +++ b/exercises/practice/matching-brackets/data.csv @@ -0,0 +1,20 @@ +"[]", +"", +"[[", +"}{", +"{]", +"{ }", +"{[])", +"{[]}", +"{}[]", +"([{}({}[])])", +"{[)][]}", +"([{])", +"[({]})", +"[({}])", +"{}[", +"[]]", +")()", +"{)()", +"(((185 + 223.85) * 15) - 543)/2", +"\left(\begin{array}{cc} \frac{1}{3} & x\\ \mathrm{e}^{x} &... x^2 \end{array}\right)", diff --git a/exercises/practice/matching-brackets/matching-brackets.sql b/exercises/practice/matching-brackets/matching-brackets.sql new file mode 100644 index 0000000..a50e092 --- /dev/null +++ b/exercises/practice/matching-brackets/matching-brackets.sql @@ -0,0 +1,2 @@ +-- Schema: CREATE TABLE "matching-brackets" ("input" TEXT "result" BOOLEAN); +-- Task: update the matching-brackets table and set the result based on the input field. diff --git a/exercises/practice/matching-brackets/matching-brackets_test.sql b/exercises/practice/matching-brackets/matching-brackets_test.sql new file mode 100644 index 0000000..d0cb714 --- /dev/null +++ b/exercises/practice/matching-brackets/matching-brackets_test.sql @@ -0,0 +1,35 @@ +-- Setup test table and read in student solution: +.read ./test_setup.sql + +-- Test cases: +INSERT INTO tests (name, uuid, input, expected) + VALUES + ('paired square brackets', '81ec11da-38dd-442a-bcf9-3de7754609a5', '[]', 1), + ('empty string', '287f0167-ac60-4b64-8452-a0aa8f4e5238', '', 1), + ('unpaired brackets', '6c3615a3-df01-4130-a731-8ef5f5d78dac', '[[', 0), + ('wrong ordered brackets', '9d414171-9b98-4cac-a4e5-941039a97a77', '}{', 0), + ('wrong closing bracket', 'f0f97c94-a149-4736-bc61-f2c5148ffb85', '{]', 0), + ('paired with whitespace', '754468e0-4696-4582-a30e-534d47d69756', '{ }', 1), + ('partially paired brackets', 'ba84f6ee-8164-434a-9c3e-b02c7f8e8545', '{[])', 0), + ('simple nested brackets', '3c86c897-5ff3-4a2b-ad9b-47ac3a30651d', '{[]}', 1), + ('several paired brackets', '2d137f2c-a19e-4993-9830-83967a2d4726', '{}[]', 1), + ('paired and nested brackets', '2e1f7b56-c137-4c92-9781-958638885a44', '([{}({}[])])', 1), + ('unopened closing brackets', '84f6233b-e0f7-4077-8966-8085d295c19b', '{[)][]}', 0), + ('unpaired and nested brackets', '9b18c67d-7595-4982-b2c5-4cb949745d49', '([{])', 0), + ('paired and wrong nested brackets', 'a0205e34-c2ac-49e6-a88a-899508d7d68e', '[({]})', 0), + ('paired and wrong nested brackets but innermost are correct', '1d5c093f-fc84-41fb-8c2a-e052f9581602', '[({}])', 0), + ('paired and incomplete brackets', 'ef47c21b-bcfd-4998-844c-7ad5daad90a8', '{}[', 0), + ('too many closing brackets', 'a4675a40-a8be-4fc2-bc47-2a282ce6edbe', '[]]', 0), + ('early unexpected brackets', 'a345a753-d889-4b7e-99ae-34ac85910d1a', ')()', 0), + ('early mismatched brackets', '21f81d61-1608-465a-b850-baa44c5def83', '{)()', 0), + ('math expression', '99255f93-261b-4435-a352-02bdecc9bdf2', '(((185 + 223.85) * 15) - 543)/2', 1), + ('complex latex expression', '8e357d79-f302-469a-8515-2561877256a1', '\left(\begin{array}{cc} \frac{1}{3} & x\\ \mathrm{e}^{x} &... x^2 \end{array}\right)', 1); + +-- Comparison of user input and the tests updates the status for each test: +UPDATE tests +SET status = 'pass' +FROM (SELECT input, result FROM "matching-brackets") 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/matching-brackets/test_reporter.sql b/exercises/practice/matching-brackets/test_reporter.sql new file mode 100644 index 0000000..51eb81c --- /dev/null +++ b/exercises/practice/matching-brackets/test_reporter.sql @@ -0,0 +1,16 @@ +-- Update message for failed tests to give helpful information: +UPDATE tests +SET message = 'Result for "' || tests.input || '" is ' || actual.result || ', but should be ' || tests.expected +FROM (SELECT input, result FROM 'matching-brackets') 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/matching-brackets/test_setup.sql b/exercises/practice/matching-brackets/test_setup.sql new file mode 100644 index 0000000..bd1a1f3 --- /dev/null +++ b/exercises/practice/matching-brackets/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 ./matching-brackets.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 TEXT NOT NULL, + expected BOOLEAN NOT NULL +);