From 33fdce52719b74618c1549324f4e5248391fe942 Mon Sep 17 00:00:00 2001 From: Glenn Jackman Date: Wed, 24 Dec 2025 19:18:21 -0500 Subject: [PATCH] palindrome-products --- config.json | 8 ++ .../practice/palindrome-products/.busted | 5 ++ .../palindrome-products/.docs/instructions.md | 36 ++++++++ .../palindrome-products/.meta/config.json | 19 ++++ .../palindrome-products/.meta/example.moon | 43 +++++++++ .../.meta/spec_generator.moon | 26 ++++++ .../palindrome-products/.meta/tests.toml | 49 +++++++++++ .../palindrome_products.moon | 7 ++ .../palindrome_products_spec.moon | 87 +++++++++++++++++++ 9 files changed, 280 insertions(+) create mode 100644 exercises/practice/palindrome-products/.busted create mode 100644 exercises/practice/palindrome-products/.docs/instructions.md create mode 100644 exercises/practice/palindrome-products/.meta/config.json create mode 100644 exercises/practice/palindrome-products/.meta/example.moon create mode 100644 exercises/practice/palindrome-products/.meta/spec_generator.moon create mode 100644 exercises/practice/palindrome-products/.meta/tests.toml create mode 100644 exercises/practice/palindrome-products/palindrome_products.moon create mode 100644 exercises/practice/palindrome-products/palindrome_products_spec.moon diff --git a/config.json b/config.json index 4ba69bd..156c454 100644 --- a/config.json +++ b/config.json @@ -478,6 +478,14 @@ "practices": [], "prerequisites": [], "difficulty": 6 + }, + { + "slug": "palindrome-products", + "name": "Palindrome Products", + "uuid": "ee7bdced-c0f3-4435-a9c4-1dec3b14540f", + "practices": [], + "prerequisites": [], + "difficulty": 6 } ] }, diff --git a/exercises/practice/palindrome-products/.busted b/exercises/practice/palindrome-products/.busted new file mode 100644 index 0000000..86b84e7 --- /dev/null +++ b/exercises/practice/palindrome-products/.busted @@ -0,0 +1,5 @@ +return { + default = { + ROOT = { '.' } + } +} diff --git a/exercises/practice/palindrome-products/.docs/instructions.md b/exercises/practice/palindrome-products/.docs/instructions.md new file mode 100644 index 0000000..aac6652 --- /dev/null +++ b/exercises/practice/palindrome-products/.docs/instructions.md @@ -0,0 +1,36 @@ +# Instructions + +Detect palindrome products in a given range. + +A palindromic number is a number that remains the same when its digits are reversed. +For example, `121` is a palindromic number but `112` is not. + +Given a range of numbers, find the largest and smallest palindromes which +are products of two numbers within that range. + +Your solution should return the largest and smallest palindromes, along with the factors of each within the range. +If the largest or smallest palindrome has more than one pair of factors within the range, then return all the pairs. + +## Example 1 + +Given the range `[1, 9]` (both inclusive)... + +And given the list of all possible products within this range: +`[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, 18, 15, 21, 24, 27, 20, 28, 32, 36, 25, 30, 35, 40, 45, 42, 48, 54, 49, 56, 63, 64, 72, 81]` + +The palindrome products are all single digit numbers (in this case): +`[1, 2, 3, 4, 5, 6, 7, 8, 9]` + +The smallest palindrome product is `1`. +Its factors are `(1, 1)`. +The largest palindrome product is `9`. +Its factors are `(1, 9)` and `(3, 3)`. + +## Example 2 + +Given the range `[10, 99]` (both inclusive)... + +The smallest palindrome product is `121`. +Its factors are `(11, 11)`. +The largest palindrome product is `9009`. +Its factors are `(91, 99)`. diff --git a/exercises/practice/palindrome-products/.meta/config.json b/exercises/practice/palindrome-products/.meta/config.json new file mode 100644 index 0000000..4466f21 --- /dev/null +++ b/exercises/practice/palindrome-products/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "glennj" + ], + "files": { + "solution": [ + "palindrome_products.moon" + ], + "test": [ + "palindrome_products_spec.moon" + ], + "example": [ + ".meta/example.moon" + ] + }, + "blurb": "Detect palindrome products in a given range.", + "source": "Problem 4 at Project Euler", + "source_url": "https://projecteuler.net/problem=4" +} diff --git a/exercises/practice/palindrome-products/.meta/example.moon b/exercises/practice/palindrome-products/.meta/example.moon new file mode 100644 index 0000000..194e005 --- /dev/null +++ b/exercises/practice/palindrome-products/.meta/example.moon @@ -0,0 +1,43 @@ +reverse_number = (num) -> + rev = 0 + while num > 0 + rev = rev * 10 + num % 10 + num = num // 10 + rev + + +is_palindrome = (number) -> + number == reverse_number number + + +bounded_factors = (number, min, max) -> + factors = {} + limit = math.min(max, math.floor math.sqrt number) + for f = min, limit + g = number // f + if f * g == number and g <= max + table.insert factors, {f, g} + factors + + +solve = (start, stop, step, min, max) -> + assert min <= max, "min must be <= max" + + for product = start, stop, step + if is_palindrome product + fs = bounded_factors product, min, max + if #fs > 0 + return {value: product, factors: fs} + + {value: nil, factors: {}} + + +{ + smallest: (min, max) -> + result = solve min * min, max * max, 1, min, max + result.value, result.factors + + largest: (min, max) -> + result = solve max * max, min * min, -1, min, max + result.value, result.factors +} diff --git a/exercises/practice/palindrome-products/.meta/spec_generator.moon b/exercises/practice/palindrome-products/.meta/spec_generator.moon new file mode 100644 index 0000000..e8d7da3 --- /dev/null +++ b/exercises/practice/palindrome-products/.meta/spec_generator.moon @@ -0,0 +1,26 @@ +int_list = (list) -> "{#{table.concat list, ', '}}" + +int_lists = (lists) -> + "{#{table.concat [int_list list for list in *lists], ', '}}" + + +{ + module_name: 'PalindromeProducts', + + generate_test: (case, level) -> + local lines + if case.expected.error + lines = { + "f = -> PalindromeProducts.#{case.property} #{case.input.min}, #{case.input.max}", + "assert.has.errors f, #{quote case.expected.error}", + } + else + lines = { + "palindrome, factors = PalindromeProducts.#{case.property} #{case.input.min}, #{case.input.max}", + "expected_palindrome = #{case.expected.value}", + "expected_factors = #{int_lists case.expected.factors}", + "assert.are.equal expected_palindrome, palindrome", + "assert.are.same expected_factors, factors", + } + table.concat [indent line, level for line in *lines], '\n' +} diff --git a/exercises/practice/palindrome-products/.meta/tests.toml b/exercises/practice/palindrome-products/.meta/tests.toml new file mode 100644 index 0000000..a3bc417 --- /dev/null +++ b/exercises/practice/palindrome-products/.meta/tests.toml @@ -0,0 +1,49 @@ +# 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. + +[5cff78fe-cf02-459d-85c2-ce584679f887] +description = "find the smallest palindrome from single digit factors" + +[0853f82c-5fc4-44ae-be38-fadb2cced92d] +description = "find the largest palindrome from single digit factors" + +[66c3b496-bdec-4103-9129-3fcb5a9063e1] +description = "find the smallest palindrome from double digit factors" + +[a10682ae-530a-4e56-b89d-69664feafe53] +description = "find the largest palindrome from double digit factors" + +[cecb5a35-46d1-4666-9719-fa2c3af7499d] +description = "find the smallest palindrome from triple digit factors" + +[edab43e1-c35f-4ea3-8c55-2f31dddd92e5] +description = "find the largest palindrome from triple digit factors" + +[4f802b5a-9d74-4026-a70f-b53ff9234e4e] +description = "find the smallest palindrome from four digit factors" + +[787525e0-a5f9-40f3-8cb2-23b52cf5d0be] +description = "find the largest palindrome from four digit factors" + +[58fb1d63-fddb-4409-ab84-a7a8e58d9ea0] +description = "empty result for smallest if no palindrome in the range" + +[9de9e9da-f1d9-49a5-8bfc-3d322efbdd02] +description = "empty result for largest if no palindrome in the range" + +[12e73aac-d7ee-4877-b8aa-2aa3dcdb9f8a] +description = "error result for smallest if min is more than max" + +[eeeb5bff-3f47-4b1e-892f-05829277bd74] +description = "error result for largest if min is more than max" + +[16481711-26c4-42e0-9180-e2e4e8b29c23] +description = "smallest product does not use the smallest factor" diff --git a/exercises/practice/palindrome-products/palindrome_products.moon b/exercises/practice/palindrome-products/palindrome_products.moon new file mode 100644 index 0000000..7837366 --- /dev/null +++ b/exercises/practice/palindrome-products/palindrome_products.moon @@ -0,0 +1,7 @@ +{ + smallest: (min, max) -> + error 'Implement me' + + largest: (min, max) -> + error 'Implement me' +} diff --git a/exercises/practice/palindrome-products/palindrome_products_spec.moon b/exercises/practice/palindrome-products/palindrome_products_spec.moon new file mode 100644 index 0000000..e58bef9 --- /dev/null +++ b/exercises/practice/palindrome-products/palindrome_products_spec.moon @@ -0,0 +1,87 @@ +PalindromeProducts = require 'palindrome_products' + +describe 'palindrome-products', -> + it 'find the smallest palindrome from single digit factors', -> + palindrome, factors = PalindromeProducts.smallest 1, 9 + expected_palindrome = 1 + expected_factors = {{1, 1}} + assert.are.equal expected_palindrome, palindrome + assert.are.same expected_factors, factors + + pending 'find the largest palindrome from single digit factors', -> + palindrome, factors = PalindromeProducts.largest 1, 9 + expected_palindrome = 9 + expected_factors = {{1, 9}, {3, 3}} + assert.are.equal expected_palindrome, palindrome + assert.are.same expected_factors, factors + + pending 'find the smallest palindrome from double digit factors', -> + palindrome, factors = PalindromeProducts.smallest 10, 99 + expected_palindrome = 121 + expected_factors = {{11, 11}} + assert.are.equal expected_palindrome, palindrome + assert.are.same expected_factors, factors + + pending 'find the largest palindrome from double digit factors', -> + palindrome, factors = PalindromeProducts.largest 10, 99 + expected_palindrome = 9009 + expected_factors = {{91, 99}} + assert.are.equal expected_palindrome, palindrome + assert.are.same expected_factors, factors + + pending 'find the smallest palindrome from triple digit factors', -> + palindrome, factors = PalindromeProducts.smallest 100, 999 + expected_palindrome = 10201 + expected_factors = {{101, 101}} + assert.are.equal expected_palindrome, palindrome + assert.are.same expected_factors, factors + + pending 'find the largest palindrome from triple digit factors', -> + palindrome, factors = PalindromeProducts.largest 100, 999 + expected_palindrome = 906609 + expected_factors = {{913, 993}} + assert.are.equal expected_palindrome, palindrome + assert.are.same expected_factors, factors + + pending 'find the smallest palindrome from four digit factors', -> + palindrome, factors = PalindromeProducts.smallest 1000, 9999 + expected_palindrome = 1002001 + expected_factors = {{1001, 1001}} + assert.are.equal expected_palindrome, palindrome + assert.are.same expected_factors, factors + + pending 'find the largest palindrome from four digit factors', -> + palindrome, factors = PalindromeProducts.largest 1000, 9999 + expected_palindrome = 99000099 + expected_factors = {{9901, 9999}} + assert.are.equal expected_palindrome, palindrome + assert.are.same expected_factors, factors + + pending 'empty result for smallest if no palindrome in the range', -> + palindrome, factors = PalindromeProducts.smallest 1002, 1003 + expected_palindrome = nil + expected_factors = {} + assert.are.equal expected_palindrome, palindrome + assert.are.same expected_factors, factors + + pending 'empty result for largest if no palindrome in the range', -> + palindrome, factors = PalindromeProducts.largest 15, 15 + expected_palindrome = nil + expected_factors = {} + assert.are.equal expected_palindrome, palindrome + assert.are.same expected_factors, factors + + pending 'error result for smallest if min is more than max', -> + f = -> PalindromeProducts.smallest 10000, 1 + assert.has.errors f, 'min must be <= max' + + pending 'error result for largest if min is more than max', -> + f = -> PalindromeProducts.largest 2, 1 + assert.has.errors f, 'min must be <= max' + + pending 'smallest product does not use the smallest factor', -> + palindrome, factors = PalindromeProducts.smallest 3215, 4000 + expected_palindrome = 10988901 + expected_factors = {{3297, 3333}} + assert.are.equal expected_palindrome, palindrome + assert.are.same expected_factors, factors