diff --git a/config.json b/config.json index a798115..495db0e 100644 --- a/config.json +++ b/config.json @@ -258,6 +258,14 @@ "prerequisites": [], "difficulty": 5 }, + { + "slug": "sum-of-multiples", + "name": "Sum of Multiples", + "uuid": "18ea92e5-6855-4dd6-b6d0-e2473d036fd4", + "practices": [], + "prerequisites": [], + "difficulty": 5 + }, { "slug": "swift-scheduling", "name": "Swift Scheduling", diff --git a/exercises/practice/sum-of-multiples/.docs/instructions.append.md b/exercises/practice/sum-of-multiples/.docs/instructions.append.md new file mode 100644 index 0000000..27d1e44 --- /dev/null +++ b/exercises/practice/sum-of-multiples/.docs/instructions.append.md @@ -0,0 +1,7 @@ +# SQLite-specific instructions + +## JSON documentation + +[JSON Functions And Operators][json-docs] + +[json-docs]: https://www.sqlite.org/json1.html diff --git a/exercises/practice/sum-of-multiples/.docs/instructions.md b/exercises/practice/sum-of-multiples/.docs/instructions.md new file mode 100644 index 0000000..d69f890 --- /dev/null +++ b/exercises/practice/sum-of-multiples/.docs/instructions.md @@ -0,0 +1,27 @@ +# Instructions + +Your task is to write the code that calculates the energy points that get awarded to players when they complete a level. + +The points awarded depend on two things: + +- The level (a number) that the player completed. +- The base value of each magical item collected by the player during that level. + +The energy points are awarded according to the following rules: + +1. For each magical item, take the base value and find all the multiples of that value that are less than the level number. +2. Combine the sets of numbers. +3. Remove any duplicates. +4. Calculate the sum of all the numbers that are left. + +Let's look at an example: + +**The player completed level 20 and found two magical items with base values of 3 and 5.** + +To calculate the energy points earned by the player, we need to find all the unique multiples of these base values that are less than level 20. + +- Multiples of 3 less than 20: `{3, 6, 9, 12, 15, 18}` +- Multiples of 5 less than 20: `{5, 10, 15}` +- Combine the sets and remove duplicates: `{3, 5, 6, 9, 10, 12, 15, 18}` +- Sum the unique multiples: `3 + 5 + 6 + 9 + 10 + 12 + 15 + 18 = 78` +- Therefore, the player earns **78** energy points for completing level 20 and finding the two magical items with base values of 3 and 5. diff --git a/exercises/practice/sum-of-multiples/.docs/introduction.md b/exercises/practice/sum-of-multiples/.docs/introduction.md new file mode 100644 index 0000000..69cabee --- /dev/null +++ b/exercises/practice/sum-of-multiples/.docs/introduction.md @@ -0,0 +1,6 @@ +# Introduction + +You work for a company that makes an online, fantasy-survival game. + +When a player finishes a level, they are awarded energy points. +The amount of energy awarded depends on which magical items the player found while exploring that level. diff --git a/exercises/practice/sum-of-multiples/.meta/config.json b/exercises/practice/sum-of-multiples/.meta/config.json new file mode 100644 index 0000000..5d5f258 --- /dev/null +++ b/exercises/practice/sum-of-multiples/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "jimmytty" + ], + "files": { + "solution": [ + "sum-of-multiples.sql" + ], + "test": [ + "sum-of-multiples_test.sql" + ], + "example": [ + ".meta/example.sql" + ] + }, + "blurb": "Given a number, find the sum of all the multiples of particular numbers up to but not including that number.", + "source": "A variation on Problem 1 at Project Euler", + "source_url": "https://projecteuler.net/problem=1" +} diff --git a/exercises/practice/sum-of-multiples/.meta/example.sql b/exercises/practice/sum-of-multiples/.meta/example.sql new file mode 100644 index 0000000..0f4ec1f --- /dev/null +++ b/exercises/practice/sum-of-multiples/.meta/example.sql @@ -0,0 +1,14 @@ +UPDATE "sum-of-multiples" + SET result = ( + WITH sets (multiples) AS ( + SELECT ( + SELECT JSON_GROUP_ARRAY(s.value) + FROM GENERATE_SERIES(1, "limit" - 1) s + WHERE s.value % j.value = 0 + ) + FROM JSON_EACH(factors) j + ) + SELECT COALESCE(SUM(DISTINCT(j.value)), 0) + FROM sets, JSON_EACH(multiples) j + ) +; diff --git a/exercises/practice/sum-of-multiples/.meta/tests.toml b/exercises/practice/sum-of-multiples/.meta/tests.toml new file mode 100644 index 0000000..1e9b124 --- /dev/null +++ b/exercises/practice/sum-of-multiples/.meta/tests.toml @@ -0,0 +1,58 @@ +# 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. + +[54aaab5a-ce86-4edc-8b40-d3ab2400a279] +description = "no multiples within limit" + +[361e4e50-c89b-4f60-95ef-5bc5c595490a] +description = "one factor has multiples within limit" + +[e644e070-040e-4ae0-9910-93c69fc3f7ce] +description = "more than one multiple within limit" + +[607d6eb9-535c-41ce-91b5-3a61da3fa57f] +description = "more than one factor with multiples within limit" + +[f47e8209-c0c5-4786-b07b-dc273bf86b9b] +description = "each multiple is only counted once" + +[28c4b267-c980-4054-93e9-07723db615ac] +description = "a much larger limit" + +[09c4494d-ff2d-4e0f-8421-f5532821ee12] +description = "three factors" + +[2d0d5faa-f177-4ad6-bde9-ebb865083751] +description = "factors not relatively prime" + +[ece8f2e8-96aa-4166-bbb7-6ce71261e354] +description = "some pairs of factors relatively prime and some not" + +[624fdade-6ffb-400e-8472-456a38c171c0] +description = "one factor is a multiple of another" + +[949ee7eb-db51-479c-b5cb-4a22b40ac057] +description = "much larger factors" + +[41093673-acbd-482c-ab80-d00a0cbedecd] +description = "all numbers are multiples of 1" + +[1730453b-baaa-438e-a9c2-d754497b2a76] +description = "no factors means an empty sum" + +[214a01e9-f4bf-45bb-80f1-1dce9fbb0310] +description = "the only multiple of 0 is 0" + +[c423ae21-a0cb-4ec7-aeb1-32971af5b510] +description = "the factor 0 does not affect the sum of multiples of other factors" + +[17053ba9-112f-4ac0-aadb-0519dd836342] +description = "solutions using include-exclude must extend to cardinality greater than 3" diff --git a/exercises/practice/sum-of-multiples/create_fixture.sql b/exercises/practice/sum-of-multiples/create_fixture.sql new file mode 100644 index 0000000..01f12a1 --- /dev/null +++ b/exercises/practice/sum-of-multiples/create_fixture.sql @@ -0,0 +1,11 @@ +DROP TABLE IF EXISTS "sum-of-multiples"; +CREATE TABLE "sum-of-multiples" ( + factors TEXT NOT NULL, -- json array of integers + "limit" INTEGER NOT NULL, + result INTEGER +); + +.mode csv +.import ./data.csv "sum-of-multiples" + +UPDATE "sum-of-multiples" SET result = NULL; diff --git a/exercises/practice/sum-of-multiples/create_test_table.sql b/exercises/practice/sum-of-multiples/create_test_table.sql new file mode 100644 index 0000000..0b0c2cf --- /dev/null +++ b/exercises/practice/sum-of-multiples/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 + factors TEXT NOT NULL, -- json array of integers + "limit" INTEGER NOT NULL, + expected INTEGER NOT NULL +); + +INSERT INTO tests (uuid, description, factors, "limit", expected) + VALUES + ('54aaab5a-ce86-4edc-8b40-d3ab2400a279', 'no multiples within limit', '[3,5]', 1, 0), + ('361e4e50-c89b-4f60-95ef-5bc5c595490a', 'one factor has multiples within limit', '[3,5]', 4, 3), + ('e644e070-040e-4ae0-9910-93c69fc3f7ce', 'more than one multiple within limit', '[3]', 7, 9), + ('607d6eb9-535c-41ce-91b5-3a61da3fa57f', 'more than one factor with multiples within limit', '[3,5]', 10, 23), + ('f47e8209-c0c5-4786-b07b-dc273bf86b9b', 'each multiple is only counted once', '[3,5]', 100, 2318), + ('28c4b267-c980-4054-93e9-07723db615ac', 'a much larger limit', '[3,5]', 1000, 233168), + ('09c4494d-ff2d-4e0f-8421-f5532821ee12', 'three factors', '[7,13,17]', 20, 51), + ('2d0d5faa-f177-4ad6-bde9-ebb865083751', 'factors not relatively prime', '[4,6]', 15, 30), + ('ece8f2e8-96aa-4166-bbb7-6ce71261e354', 'some pairs of factors relatively prime and some not', '[5,6,8]', 150, 4419), + ('624fdade-6ffb-400e-8472-456a38c171c0', 'one factor is a multiple of another', '[5,25]', 51, 275), + ('949ee7eb-db51-479c-b5cb-4a22b40ac057', 'much larger factors', '[43,47]', 10000, 2203160), + ('41093673-acbd-482c-ab80-d00a0cbedecd', 'all numbers are multiples of 1', '[1]', 100, 4950), + ('1730453b-baaa-438e-a9c2-d754497b2a76', 'no factors means an empty sum', '[]', 10000, 0), + ('214a01e9-f4bf-45bb-80f1-1dce9fbb0310', 'the only multiple of 0 is 0', '[0]', 1, 0), + ('c423ae21-a0cb-4ec7-aeb1-32971af5b510', 'the factor 0 does not affect the sum of multiples of other factors', '[3,0]', 4, 3), + ('17053ba9-112f-4ac0-aadb-0519dd836342', 'solutions using include-exclude must extend to cardinality greater than 3', '[2,3,5,7,11]', 10000, 39614537); diff --git a/exercises/practice/sum-of-multiples/data.csv b/exercises/practice/sum-of-multiples/data.csv new file mode 100644 index 0000000..8376e9a --- /dev/null +++ b/exercises/practice/sum-of-multiples/data.csv @@ -0,0 +1,16 @@ +"[3,5]",1, +"[3,5]",4, +"[3]",7, +"[3,5]",10, +"[3,5]",100, +"[3,5]",1000, +"[7,13,17]",20, +"[4,6]",15, +"[5,6,8]",150, +"[5,25]",51, +"[43,47]",10000, +"[1]",100, +"[]",10000, +"[0]",1, +"[3,0]",4, +"[2,3,5,7,11]",10000, diff --git a/exercises/practice/sum-of-multiples/sum-of-multiples.sql b/exercises/practice/sum-of-multiples/sum-of-multiples.sql new file mode 100644 index 0000000..159eccc --- /dev/null +++ b/exercises/practice/sum-of-multiples/sum-of-multiples.sql @@ -0,0 +1,8 @@ +-- Schema: +-- CREATE TABLE "sum-of-multiples" ( +-- factors TEXT NOT NULL, -- json array of integers +-- "limit" INTEGER NOT NULL, +-- result INTEGER +-- ); +-- +-- Task: update the "sum-of-multiples" table and set the result based on the phrase. diff --git a/exercises/practice/sum-of-multiples/sum-of-multiples_test.sql b/exercises/practice/sum-of-multiples/sum-of-multiples_test.sql new file mode 100644 index 0000000..dec615f --- /dev/null +++ b/exercises/practice/sum-of-multiples/sum-of-multiples_test.sql @@ -0,0 +1,40 @@ +-- 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 ./sum-of-multiples.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 factors, "limit", result FROM "sum-of-multiples") AS actual +WHERE (actual.factors, actual."limit", actual.result) = (tests.factors, tests."limit", tests.expected); + +-- Update message for failed tests to give helpful information: +UPDATE tests +SET message = ( + 'Result for "' + || PRINTF('factors=%s, limit=%d', tests.factors, tests."limit") + || '"' + || ' is <' || COALESCE(actual.result, 'NULL') + || '> but should be <' || tests.expected || '>' +) +FROM (SELECT factors, "limit", result FROM "sum-of-multiples") AS actual +WHERE (actual.factors, actual."limit") = (tests.factors, tests."limit") 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;