From 024fcaee8704a2c9a0329ff51cd77c7e4d29c85d Mon Sep 17 00:00:00 2001 From: Glenn Jackman Date: Wed, 24 Dec 2025 18:53:36 -0500 Subject: [PATCH] largest-series-product --- config.json | 8 ++ .../practice/largest-series-product/.busted | 5 ++ .../.docs/instructions.md | 26 +++++++ .../.docs/introduction.md | 5 ++ .../largest-series-product/.meta/config.json | 19 +++++ .../largest-series-product/.meta/example.moon | 18 +++++ .../.meta/spec_generator.moon | 20 +++++ .../largest-series-product/.meta/tests.toml | 70 +++++++++++++++++ .../largest_series_product.moon | 4 + .../largest_series_product_spec.moon | 76 +++++++++++++++++++ 10 files changed, 251 insertions(+) create mode 100644 exercises/practice/largest-series-product/.busted create mode 100644 exercises/practice/largest-series-product/.docs/instructions.md create mode 100644 exercises/practice/largest-series-product/.docs/introduction.md create mode 100644 exercises/practice/largest-series-product/.meta/config.json create mode 100644 exercises/practice/largest-series-product/.meta/example.moon create mode 100644 exercises/practice/largest-series-product/.meta/spec_generator.moon create mode 100644 exercises/practice/largest-series-product/.meta/tests.toml create mode 100644 exercises/practice/largest-series-product/largest_series_product.moon create mode 100644 exercises/practice/largest-series-product/largest_series_product_spec.moon diff --git a/config.json b/config.json index 85077cc..2f3e073 100644 --- a/config.json +++ b/config.json @@ -342,6 +342,14 @@ "practices": [], "prerequisites": [], "difficulty": 4 + }, + { + "slug": "largest-series-product", + "name": "Largest Series Product", + "uuid": "d56c9861-434c-4299-b2ce-aa067a6d965f", + "practices": [], + "prerequisites": [], + "difficulty": 4 } ] }, diff --git a/exercises/practice/largest-series-product/.busted b/exercises/practice/largest-series-product/.busted new file mode 100644 index 0000000..86b84e7 --- /dev/null +++ b/exercises/practice/largest-series-product/.busted @@ -0,0 +1,5 @@ +return { + default = { + ROOT = { '.' } + } +} 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..26c6bca --- /dev/null +++ b/exercises/practice/largest-series-product/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "glennj" + ], + "files": { + "solution": [ + "largest_series_product.moon" + ], + "test": [ + "largest_series_product_spec.moon" + ], + "example": [ + ".meta/example.moon" + ] + }, + "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.moon b/exercises/practice/largest-series-product/.meta/example.moon new file mode 100644 index 0000000..cd7c900 --- /dev/null +++ b/exercises/practice/largest-series-product/.meta/example.moon @@ -0,0 +1,18 @@ +import fold from require 'moon' + +product = (...) -> fold {1, ...}, (p, d) -> p * d + +refute = (cond, msg) -> assert not cond, msg + +{ + largest_product: (digits, span) -> + return 1 if span == 0 + + assert span >= 0, 'span must not be negative' + assert span <= #digits, 'span must not exceed string length' + refute digits\find('[^%d]'), 'digits input must only contain digits' + + ds = [tonumber c for c in digits\gmatch('.')] + prods = [product table.unpack(ds, i, i + span - 1) for i = 1, #ds - (span - 1)] + math.max table.unpack prods +} diff --git a/exercises/practice/largest-series-product/.meta/spec_generator.moon b/exercises/practice/largest-series-product/.meta/spec_generator.moon new file mode 100644 index 0000000..f07afb0 --- /dev/null +++ b/exercises/practice/largest-series-product/.meta/spec_generator.moon @@ -0,0 +1,20 @@ +{ + module_imports: {'largest_product'}, + + generate_test: (case, level) -> + lines = {} + switch type(case.expected) + when 'number' + table.insert lines, "-- #{line}" for line in *(case.comments or {}) + table.insert lines, line for line in *{ + "result = largest_product #{quote case.input.digits}, #{case.input.span}", + "assert.are.equal #{case.expected}, result" + } + when 'table' + lines = { + "f = -> largest_product #{quote case.input.digits}, #{case.input.span}", + "assert.has.errors f, #{quote case.expected.error}" + } + + table.concat [indent line, level for line in *lines], '\n' +} 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/largest_series_product.moon b/exercises/practice/largest-series-product/largest_series_product.moon new file mode 100644 index 0000000..8c5093e --- /dev/null +++ b/exercises/practice/largest-series-product/largest_series_product.moon @@ -0,0 +1,4 @@ +{ + largest_product: (digits, span) -> + error 'Implement me' +} diff --git a/exercises/practice/largest-series-product/largest_series_product_spec.moon b/exercises/practice/largest-series-product/largest_series_product_spec.moon new file mode 100644 index 0000000..237e6ed --- /dev/null +++ b/exercises/practice/largest-series-product/largest_series_product_spec.moon @@ -0,0 +1,76 @@ +import largest_product from require 'largest_series_product' + +describe 'largest-series-product', -> + it 'finds the largest product if span equals length', -> + result = largest_product '29', 2 + assert.are.equal 18, result + + pending 'can find the largest product of 2 with numbers in order', -> + result = largest_product '0123456789', 2 + assert.are.equal 72, result + + pending 'can find the largest product of 2', -> + result = largest_product '576802143', 2 + assert.are.equal 48, result + + pending 'can find the largest product of 3 with numbers in order', -> + result = largest_product '0123456789', 3 + assert.are.equal 504, result + + pending 'can find the largest product of 3', -> + result = largest_product '1027839564', 3 + assert.are.equal 270, result + + pending 'can find the largest product of 5 with numbers in order', -> + result = largest_product '0123456789', 5 + assert.are.equal 15120, result + + pending 'can get the largest product of a big number', -> + result = largest_product '73167176531330624919225119674426574742355349194934', 6 + assert.are.equal 23520, result + + pending 'reports zero if the only digits are zero', -> + result = largest_product '0000', 2 + assert.are.equal 0, result + + pending 'reports zero if all spans include zero', -> + result = largest_product '99099', 3 + assert.are.equal 0, result + + pending 'rejects span longer than string length', -> + f = -> largest_product '123', 4 + assert.has.errors f, 'span must not exceed string length' + + pending 'reports 1 for empty string and empty product (0 span)', -> + -- There may be some confusion about whether this should be 1 or error. + -- The reasoning for it being 1 is this: + -- There is one 0-character string contained in the empty string. + -- That's the empty string itself. + -- The empty product is 1 (the identity for multiplication). + -- Therefore LSP('', 0) is 1. + -- It's NOT the case that LSP('', 0) takes max of an empty list. + -- So there is no error. + -- Compare against LSP('123', 4): + -- There are zero 4-character strings in '123'. + -- So LSP('123', 4) really DOES take the max of an empty list. + -- So LSP('123', 4) errors and LSP('', 0) does NOT. + result = largest_product '', 0 + assert.are.equal 1, result + + pending 'reports 1 for nonempty string and empty product (0 span)', -> + -- As above, there is one 0-character string in '123'. + -- So again no error. It's the empty product, 1. + result = largest_product '123', 0 + assert.are.equal 1, result + + pending 'rejects empty string and nonzero span', -> + f = -> largest_product '', 1 + assert.has.errors f, 'span must not exceed string length' + + pending 'rejects invalid character in digits', -> + f = -> largest_product '1234a5', 2 + assert.has.errors f, 'digits input must only contain digits' + + pending 'rejects negative span', -> + f = -> largest_product '12345', -1 + assert.has.errors f, 'span must not be negative'