diff --git a/config.json b/config.json index dc9cac0..a78823b 100644 --- a/config.json +++ b/config.json @@ -362,6 +362,14 @@ "prerequisites": [], "difficulty": 8 }, + { + "slug": "largest-series-product", + "name": "Largest Series Product", + "uuid": "66555259-8a28-428a-bca8-c0b06c889297", + "practices": [], + "prerequisites": [], + "difficulty": 8 + }, { "slug": "luhn", "name": "Luhn", @@ -441,19 +449,19 @@ "practices": [], "prerequisites": [], "difficulty": 8 - }, + }, { - "slug": "saddle-points", - "name": "Saddle Points", - "uuid": "d050e56b-9f86-416c-baa3-10a98f47b944", + "slug": "run-length-encoding", + "name": "Run-Length Encoding", + "uuid": "065feae7-f6fc-46b9-a226-d3d9df9d192b", "practices": [], "prerequisites": [], "difficulty": 8 }, { - "slug": "run-length-encoding", - "name": "Run-Length Encoding", - "uuid": "065feae7-f6fc-46b9-a226-d3d9df9d192b", + "slug": "saddle-points", + "name": "Saddle Points", + "uuid": "d050e56b-9f86-416c-baa3-10a98f47b944", "practices": [], "prerequisites": [], "difficulty": 8 diff --git a/exercises/practice/largest-series-product/.docs/instructions.md b/exercises/practice/largest-series-product/.docs/instructions.md new file mode 100644 index 0000000..f297b57 --- /dev/null +++ b/exercises/practice/largest-series-product/.docs/instructions.md @@ -0,0 +1,26 @@ +# Instructions + +Your task is to look for patterns in the long sequence of digits in the encrypted signal. + +The technique you're going to use here is called the largest series product. + +Let's define a few terms, first. + +- **input**: the sequence of digits that you need to analyze +- **series**: a sequence of adjacent digits (those that are next to each other) that is contained within the input +- **span**: how many digits long each series is +- **product**: what you get when you multiply numbers together + +Let's work through an example, with the input `"63915"`. + +- To form a series, take adjacent digits in the original input. +- If you are working with a span of `3`, there will be three possible series: + - `"639"` + - `"391"` + - `"915"` +- Then we need to calculate the product of each series: + - The product of the series `"639"` is 162 (`6 × 3 × 9 = 162`) + - The product of the series `"391"` is 27 (`3 × 9 × 1 = 27`) + - The product of the series `"915"` is 45 (`9 × 1 × 5 = 45`) +- 162 is bigger than both 27 and 45, so the largest series product of `"63915"` is from the series `"639"`. + So the answer is **162**. diff --git a/exercises/practice/largest-series-product/.docs/introduction.md b/exercises/practice/largest-series-product/.docs/introduction.md new file mode 100644 index 0000000..597bb5f --- /dev/null +++ b/exercises/practice/largest-series-product/.docs/introduction.md @@ -0,0 +1,5 @@ +# Introduction + +You work for a government agency that has intercepted a series of encrypted communication signals from a group of bank robbers. +The signals contain a long sequence of digits. +Your team needs to use various digital signal processing techniques to analyze the signals and identify any patterns that may indicate the planning of a heist. diff --git a/exercises/practice/largest-series-product/.meta/config.json b/exercises/practice/largest-series-product/.meta/config.json new file mode 100644 index 0000000..4b47bf4 --- /dev/null +++ b/exercises/practice/largest-series-product/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "jimmytty" + ], + "files": { + "solution": [ + "largest-series-product.sql" + ], + "test": [ + "largest-series-product_test.sql" + ], + "example": [ + ".meta/example.sql" + ] + }, + "blurb": "Given a string of digits, calculate the largest product for a contiguous substring of digits of length n.", + "source": "A variation on Problem 8 at Project Euler", + "source_url": "https://projecteuler.net/problem=8" +} diff --git a/exercises/practice/largest-series-product/.meta/example.sql b/exercises/practice/largest-series-product/.meta/example.sql new file mode 100644 index 0000000..95d5bb8 --- /dev/null +++ b/exercises/practice/largest-series-product/.meta/example.sql @@ -0,0 +1,46 @@ +UPDATE "largest-series-product" + SET error = 'span must not exceed string length' + WHERE LENGTH(digits) < span +; +UPDATE "largest-series-product" + SET error = 'digits input must only contain digits' + WHERE GLOB('*[^0-9]*', digits) +; +UPDATE "largest-series-product" + SET error = 'span must not be negative' + WHERE span < 0 +; + +UPDATE "largest-series-product" + SET result = 1 + WHERE span = 0 +; + +UPDATE "largest-series-product" + SET result = ( + WITH RECURSIVE split_series (string, serie, product) AS ( + VALUES (digits, NULL, NULL) + UNION ALL + SELECT SUBSTR(string, 2), + SUBSTR(string, 1, span), + (WITH RECURSIVE split_digits (serie, digit) AS ( + VALUES (SUBSTR(string, 1, span), NULL) + UNION ALL + SELECT SUBSTR(serie, 2), SUBSTR(serie, 1, 1) * 1 + FROM split_digits + WHERE serie <> '' + ) + SELECT IIF( + (SELECT 1 FROM split_digits WHERE digit = 0), + 0, EXP(SUM(LN(digit)))) AS product + FROM split_digits + WHERE digit NOTNULL + ) + FROM split_series + WHERE string <> '' + ) + SELECT ROUND(MAX(product)) FROM split_series WHERE LENGTH(serie) = span + ) + WHERE error ISNULL + AND result ISNULL +; diff --git a/exercises/practice/largest-series-product/.meta/tests.toml b/exercises/practice/largest-series-product/.meta/tests.toml new file mode 100644 index 0000000..5a62d61 --- /dev/null +++ b/exercises/practice/largest-series-product/.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. + +[7c82f8b7-e347-48ee-8a22-f672323324d4] +description = "finds the largest product if span equals length" + +[88523f65-21ba-4458-a76a-b4aaf6e4cb5e] +description = "can find the largest product of 2 with numbers in order" + +[f1376b48-1157-419d-92c2-1d7e36a70b8a] +description = "can find the largest product of 2" + +[46356a67-7e02-489e-8fea-321c2fa7b4a4] +description = "can find the largest product of 3 with numbers in order" + +[a2dcb54b-2b8f-4993-92dd-5ce56dece64a] +description = "can find the largest product of 3" + +[673210a3-33cd-4708-940b-c482d7a88f9d] +description = "can find the largest product of 5 with numbers in order" + +[02acd5a6-3bbf-46df-8282-8b313a80a7c9] +description = "can get the largest product of a big number" + +[76dcc407-21e9-424c-a98e-609f269622b5] +description = "reports zero if the only digits are zero" + +[6ef0df9f-52d4-4a5d-b210-f6fae5f20e19] +description = "reports zero if all spans include zero" + +[5d81aaf7-4f67-4125-bf33-11493cc7eab7] +description = "rejects span longer than string length" +include = false + +[0ae1ce53-d9ba-41bb-827f-2fceb64f058b] +description = "rejects span longer than string length" +reimplements = "5d81aaf7-4f67-4125-bf33-11493cc7eab7" + +[06bc8b90-0c51-4c54-ac22-3ec3893a079e] +description = "reports 1 for empty string and empty product (0 span)" + +[3ec0d92e-f2e2-4090-a380-70afee02f4c0] +description = "reports 1 for nonempty string and empty product (0 span)" + +[6d96c691-4374-4404-80ee-2ea8f3613dd4] +description = "rejects empty string and nonzero span" +include = false + +[6cf66098-a6af-4223-aab1-26aeeefc7402] +description = "rejects empty string and nonzero span" +reimplements = "6d96c691-4374-4404-80ee-2ea8f3613dd4" + +[7a38f2d6-3c35-45f6-8d6f-12e6e32d4d74] +description = "rejects invalid character in digits" + +[5fe3c0e5-a945-49f2-b584-f0814b4dd1ef] +description = "rejects negative span" +include = false + +[c859f34a-9bfe-4897-9c2f-6d7f8598e7f0] +description = "rejects negative span" +reimplements = "5fe3c0e5-a945-49f2-b584-f0814b4dd1ef" diff --git a/exercises/practice/largest-series-product/create_fixture.sql b/exercises/practice/largest-series-product/create_fixture.sql new file mode 100644 index 0000000..73e4965 --- /dev/null +++ b/exercises/practice/largest-series-product/create_fixture.sql @@ -0,0 +1,12 @@ +DROP TABLE IF EXISTS "largest-series-product"; +CREATE TABLE "largest-series-product" ( + digits TEXT NOT NULL, + span INTEGER NOT NULL, + result INTEGER , + error TEXT +); + +.mode csv +.import ./data.csv "largest-series-product" + +UPDATE "largest-series-product" SET result = NULL, error = NULL; diff --git a/exercises/practice/largest-series-product/create_test_table.sql b/exercises/practice/largest-series-product/create_test_table.sql new file mode 100644 index 0000000..7526863 --- /dev/null +++ b/exercises/practice/largest-series-product/create_test_table.sql @@ -0,0 +1,35 @@ +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 + digits TEXT NOT NULL, + span INTEGER NOT NULL, + expected_result INTEGER, + expected_error TEXT +); + +INSERT INTO tests (uuid, description, digits, span, expected_result, expected_error) +VALUES +('7c82f8b7-e347-48ee-8a22-f672323324d4', 'finds the largest product if span equals length', '29', 2, 18, NULL), +('88523f65-21ba-4458-a76a-b4aaf6e4cb5e', 'can find the largest product of 2 with numbers in order', '0123456789', 2, 72, NULL), +('f1376b48-1157-419d-92c2-1d7e36a70b8a', 'can find the largest product of 2', '576802143', 2, 48, NULL), +('46356a67-7e02-489e-8fea-321c2fa7b4a4', 'can find the largest product of 3 with numbers in order', '0123456789', 3, 504, NULL), +('a2dcb54b-2b8f-4993-92dd-5ce56dece64a', 'can find the largest product of 3', '1027839564', 3, 270, NULL), +('673210a3-33cd-4708-940b-c482d7a88f9d', 'can find the largest product of 5 with numbers in order', '0123456789', 5, 15120, NULL), +('02acd5a6-3bbf-46df-8282-8b313a80a7c9', 'can get the largest product of a big number', '73167176531330624919225119674426574742355349194934', 6, 23520, NULL), +('76dcc407-21e9-424c-a98e-609f269622b5', 'reports zero if the only digits are zero', '0000', 2, 0, NULL), +('6ef0df9f-52d4-4a5d-b210-f6fae5f20e19', 'reports zero if all spans include zero', '99099', 3, 0, NULL), +('0ae1ce53-d9ba-41bb-827f-2fceb64f058b', 'rejects span longer than string length', '123', 4, NULL, 'span must not exceed string length'), +('06bc8b90-0c51-4c54-ac22-3ec3893a079e', 'reports 1 for empty string and empty product (0 span)', '', 0, 1, NULL), +('3ec0d92e-f2e2-4090-a380-70afee02f4c0', 'reports 1 for nonempty string and empty product (0 span)', '123', 0, 1, NULL), +('6cf66098-a6af-4223-aab1-26aeeefc7402', 'rejects empty string and nonzero span', '', 1, NULL, 'span must not exceed string length'), +('7a38f2d6-3c35-45f6-8d6f-12e6e32d4d74', 'rejects invalid character in digits', '1234a5', 2, NULL, 'digits input must only contain digits'), +('c859f34a-9bfe-4897-9c2f-6d7f8598e7f0', 'rejects negative span', '12345', -1, NULL, 'span must not be negative'); diff --git a/exercises/practice/largest-series-product/data.csv b/exercises/practice/largest-series-product/data.csv new file mode 100644 index 0000000..1e903a3 --- /dev/null +++ b/exercises/practice/largest-series-product/data.csv @@ -0,0 +1,15 @@ +"29",2,, +"0123456789",2,, +"576802143",2,, +"0123456789",3,, +"1027839564",3,, +"0123456789",5,, +"73167176531330624919225119674426574742355349194934",6,, +"0000",2,, +"99099",3,, +"123",4,, +"",0,, +"123",0,, +"",1,, +"1234a5",2,, +"12345",-1,, diff --git a/exercises/practice/largest-series-product/largest-series-product.sql b/exercises/practice/largest-series-product/largest-series-product.sql new file mode 100644 index 0000000..a1e81ac --- /dev/null +++ b/exercises/practice/largest-series-product/largest-series-product.sql @@ -0,0 +1,9 @@ +-- Schema: +-- CREATE TABLE "largest-series-product" ( +-- digits TEXT NOT NULL, +-- span INTEGER NOT NULL, +-- result INTEGER , +-- error TEXT +-- ); +-- +-- Task: update the largest-series-product table and set the result or the error columns bases on the digits and the span. diff --git a/exercises/practice/largest-series-product/largest-series-product_test.sql b/exercises/practice/largest-series-product/largest-series-product_test.sql new file mode 100644 index 0000000..29fb334 --- /dev/null +++ b/exercises/practice/largest-series-product/largest-series-product_test.sql @@ -0,0 +1,53 @@ +-- 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 ./largest-series-product.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 digits, span, result, error + FROM "largest-series-product") AS actual + WHERE (actual.digits, actual.span) = (tests.digits, tests.span) + AND (actual.result = tests.expected_result + OR (actual.result ISNULL AND tests.expected_result ISNULL)) + AND (actual.error = tests.expected_error + OR (actual.error ISNULL AND tests.expected_error ISNULL)); + +-- Update message for failed tests to give helpful information: +UPDATE tests + SET message = ( + 'Result for "' + || PRINTF('digits=%s and span=%s', actual.digits, actual.span) + || '" 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 digits, span, result, error + FROM "largest-series-product") AS actual + WHERE (actual.digits, actual.span) = (tests.digits, tests.span) + 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;