From dee531793c067b74447e0241d8327919ad7a9a2a Mon Sep 17 00:00:00 2001 From: keiravillekode Date: Mon, 25 Nov 2024 01:40:53 +1100 Subject: [PATCH] Add palindrome-products exercise (#224) --- config.json | 8 ++ .../palindrome-products/.docs/instructions.md | 36 +++++++++ .../palindrome-products/.meta/config.json | 19 +++++ .../palindrome-products/.meta/proof.ci.wren | 74 ++++++++++++++++++ .../palindrome-products/.meta/tests.toml | 49 ++++++++++++ .../practice/palindrome-products/LICENSE | 21 +++++ .../practice/palindrome-products/package.wren | 14 ++++ .../palindrome-products.spec.wren | 78 +++++++++++++++++++ .../palindrome-products.wren | 8 ++ 9 files changed, 307 insertions(+) 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/proof.ci.wren create mode 100644 exercises/practice/palindrome-products/.meta/tests.toml create mode 100644 exercises/practice/palindrome-products/LICENSE create mode 100644 exercises/practice/palindrome-products/package.wren create mode 100644 exercises/practice/palindrome-products/palindrome-products.spec.wren create mode 100644 exercises/practice/palindrome-products/palindrome-products.wren diff --git a/config.json b/config.json index 1a053e3..a1256af 100644 --- a/config.json +++ b/config.json @@ -788,6 +788,14 @@ "prerequisites": [], "difficulty": 6 }, + { + "slug": "palindrome-products", + "name": "Palindrome Products", + "uuid": "b73c893c-7ecb-4195-af8a-d8fd91b35bd2", + "practices": [], + "prerequisites": [], + "difficulty": 6 + }, { "slug": "rail-fence-cipher", "name": "Rail Fence Cipher", 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..463d036 --- /dev/null +++ b/exercises/practice/palindrome-products/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "keiravillekode" + ], + "files": { + "solution": [ + "palindrome-products.wren" + ], + "test": [ + "palindrome-products.spec.wren" + ], + "example": [ + ".meta/proof.ci.wren" + ] + }, + "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/proof.ci.wren b/exercises/practice/palindrome-products/.meta/proof.ci.wren new file mode 100644 index 0000000..35acb12 --- /dev/null +++ b/exercises/practice/palindrome-products/.meta/proof.ci.wren @@ -0,0 +1,74 @@ +class PalindromeProducts { + construct smallest(min, max) { + if (min > max) { + Fiber.abort("min must be <= max") + } + + _value = max * max + 1 + _factors = [] + for (first in min..max) { + for (second in first..max) { + var product = first * second + if (product > _value) { + break + } + + if (!PalindromeProducts.isPalindrome(product)) { + continue + } + + if (product < _value) { + _value = product + _factors = [] + } + + _factors.add([first, second]) + } + } + + if (_factors.count == 0) { + _value = null + } + } + + construct largest(min, max) { + if (min > max) { + Fiber.abort("min must be <= max") + } + + _value = -1 + _factors = [] + for (second in max..min) { + for (first in second..min) { + var product = first * second + if (product < _value) { + break + } + + if (!PalindromeProducts.isPalindrome(product)) { + continue + } + + if (product > _value) { + _value = product + _factors = [] + } + + _factors.add([first, second]) + } + } + + if (_factors.count == 0) { + _value = null + } + } + + value {_value} + + factors {_factors} + + static isPalindrome(num) { + var str = num.toString + return str == str[-1..0] + } +} 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/LICENSE b/exercises/practice/palindrome-products/LICENSE new file mode 100644 index 0000000..c362f61 --- /dev/null +++ b/exercises/practice/palindrome-products/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Exercism + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/exercises/practice/palindrome-products/package.wren b/exercises/practice/palindrome-products/package.wren new file mode 100644 index 0000000..aaee3c8 --- /dev/null +++ b/exercises/practice/palindrome-products/package.wren @@ -0,0 +1,14 @@ +import "wren-package" for WrenPackage, Dependency +import "os" for Process + +class Package is WrenPackage { + construct new() {} + name { "exercism/palindrome-products" } + dependencies { + return [ + Dependency.new("wren-testie", "0.3.0", "https://github.com/joshgoebel/wren-testie.git") + ] + } +} + +Package.new().default() diff --git a/exercises/practice/palindrome-products/palindrome-products.spec.wren b/exercises/practice/palindrome-products/palindrome-products.spec.wren new file mode 100644 index 0000000..a6d5bb9 --- /dev/null +++ b/exercises/practice/palindrome-products/palindrome-products.spec.wren @@ -0,0 +1,78 @@ +import "./palindrome-products" for PalindromeProducts +import "wren-testie/testie" for Testie, Expect + +Testie.test("PalindromeProducts") { |do, skip| + do.test("find the smallest palindrome from single digit factors") { + var result = PalindromeProducts.smallest(1, 9) + Expect.value(result.value).toEqual(1) + Expect.value(result.factors).toEqual([[1, 1]]) + } + + skip.test("find the largest palindrome from single digit factors") { + var result = PalindromeProducts.largest(1, 9) + Expect.value(result.value).toEqual(9) + Expect.value(result.factors).toEqual([[1, 9], [3, 3]]) + } + + skip.test("find the smallest palindrome from double digit factors") { + var result = PalindromeProducts.smallest(10, 99) + Expect.value(result.value).toEqual(121) + Expect.value(result.factors).toEqual([[11, 11]]) + } + + skip.test("find the largest palindrome from double digit factors") { + var result = PalindromeProducts.largest(10, 99) + Expect.value(result.value).toEqual(9009) + Expect.value(result.factors).toEqual([[91, 99]]) + } + + skip.test("find the smallest palindrome from triple digit factors") { + var result = PalindromeProducts.smallest(100, 999) + Expect.value(result.value).toEqual(10201) + Expect.value(result.factors).toEqual([[101, 101]]) + } + + skip.test("find the largest palindrome from triple digit factors") { + var result = PalindromeProducts.largest(100, 999) + Expect.value(result.value).toEqual(906609) + Expect.value(result.factors).toEqual([[913, 993]]) + } + + skip.test("find the smallest palindrome from four digit factors") { + var result = PalindromeProducts.smallest(1000, 9999) + Expect.value(result.value).toEqual(1002001) + Expect.value(result.factors).toEqual([[1001, 1001]]) + } + + skip.test("find the largest palindrome from four digit factors") { + var result = PalindromeProducts.largest(1000, 9999) + Expect.value(result.value).toEqual(99000099) + Expect.value(result.factors).toEqual([[9901, 9999]]) + } + + skip.test("empty result for smallest if no palindrome in the range") { + var result = PalindromeProducts.smallest(1002, 1003) + Expect.value(result.value).toEqual(null) + Expect.value(result.factors).toEqual([]) + } + + skip.test("empty result for largest if no palindrome in the range") { + var result = PalindromeProducts.largest(15, 15) + Expect.value(result.value).toEqual(null) + Expect.value(result.factors).toEqual([]) + } + + Expect.that { + PalindromeProducts.smallest(10000, 1) + }.abortsWith("min must be <= max") + + Expect.that { + PalindromeProducts.largest(2, 1) + }.abortsWith("min must be <= max") + + skip.test("smallest product does not use the smallest factor") { + var result = PalindromeProducts.smallest(3215, 4000) + Expect.value(result.value).toEqual(10988901) + Expect.value(result.factors).toEqual([[3297, 3333]]) + } +} diff --git a/exercises/practice/palindrome-products/palindrome-products.wren b/exercises/practice/palindrome-products/palindrome-products.wren new file mode 100644 index 0000000..4ae1690 --- /dev/null +++ b/exercises/practice/palindrome-products/palindrome-products.wren @@ -0,0 +1,8 @@ +class PalindromeProducts { + construct smallest(min, max) { + Fiber.abort("Remove this statement and implement this class") + } + construct largest(min, max) { + Fiber.abort("Remove this statement and implement this class") + } +}