From 4058ea6a34fc0aaf88753ee94b2fc5ab0370b4a8 Mon Sep 17 00:00:00 2001 From: depial <91621102+depial@users.noreply.github.com> Date: Fri, 19 Jul 2024 06:57:25 -0400 Subject: [PATCH] add practice exercise palindrome-products --- config.json | 8 ++ .../palindrome-products/.docs/instructions.md | 36 +++++++++ .../palindrome-products/.meta/config.json | 17 ++++ .../palindrome-products/.meta/example.jl | 27 +++++++ .../palindrome-products/.meta/tests.toml | 49 ++++++++++++ .../palindrome-products.jl | 4 + .../practice/palindrome-products/runtests.jl | 79 +++++++++++++++++++ 7 files changed, 220 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/example.jl create mode 100644 exercises/practice/palindrome-products/.meta/tests.toml create mode 100644 exercises/practice/palindrome-products/palindrome-products.jl create mode 100644 exercises/practice/palindrome-products/runtests.jl diff --git a/config.json b/config.json index 93662c99..3245146e 100644 --- a/config.json +++ b/config.json @@ -993,6 +993,14 @@ "practices": [], "prerequisites": [], "difficulty": 2 + }, + { + "slug": "palindrome-products", + "name": "Palindrome Products", + "uuid": "7ab2d0e6-6a39-4edf-86e9-1e49dfb8908e", + "practices": [], + "prerequisites": [], + "difficulty": 4 } ] }, diff --git a/exercises/practice/palindrome-products/.docs/instructions.md b/exercises/practice/palindrome-products/.docs/instructions.md new file mode 100644 index 00000000..aac66521 --- /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 00000000..b67f97b6 --- /dev/null +++ b/exercises/practice/palindrome-products/.meta/config.json @@ -0,0 +1,17 @@ +{ + "authors": [], + "files": { + "solution": [ + "palindrome-products.jl" + ], + "test": [ + "runtests.jl" + ], + "example": [ + ".meta/example.jl" + ] + }, + "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.jl b/exercises/practice/palindrome-products/.meta/example.jl new file mode 100644 index 00000000..4406bcfa --- /dev/null +++ b/exercises/practice/palindrome-products/.meta/example.jl @@ -0,0 +1,27 @@ +getfactors(n, low, high) = [[i, n÷i] for i in low:isqrt(n) if iszero(n%i) && low ≤ n÷i ≤ high] + +function nextpal(n, smallest) + smallest && occursin(r"^9+$", "$n") && return n + 2 + !smallest && occursin(r"^10*1$", "$n") && return n - 2 + half = "$(parse(Int, "$n"[1:(ndigits(n)+1)÷2]) + (-1)^!smallest)" + parse(Int, half * reverse(half)[1+isodd(ndigits(n)):end]) +end + +function nearestvalidpal(bound, smallest) + half = "$bound"[1:(ndigits(bound)+1)÷2] + pal = parse(Int, half * reverse(half)[1+isodd(ndigits(bound)):end]) + inrange = smallest ? bound ≤ pal : pal ≤ bound + inrange ? pal : nextpal(pal, smallest) +end + +function pal_n_facts(pal, low, high, smallest) + ((smallest && pal > high^2) || (!smallest && pal < low^2)) && return nothing, [] + facts = getfactors(pal, low, high) + isempty(facts) ? pal_n_facts(nextpal(pal, smallest), low, high, smallest) : (pal, facts) +end + +function palindromeproducts(low, high, smallest) + high < low && throw(ArgumentError("low is greater than high: $low > $high")) + bound = smallest ? low^2 : high^2 + pal_n_facts(nearestvalidpal(bound, smallest), low, high, smallest) +end diff --git a/exercises/practice/palindrome-products/.meta/tests.toml b/exercises/practice/palindrome-products/.meta/tests.toml new file mode 100644 index 00000000..a3bc4175 --- /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.jl b/exercises/practice/palindrome-products/palindrome-products.jl new file mode 100644 index 00000000..690196c9 --- /dev/null +++ b/exercises/practice/palindrome-products/palindrome-products.jl @@ -0,0 +1,4 @@ +function palindromeproducts(low::Int, high::Int, smallest::Bool) + # Your code here + palindrome, factors +end diff --git a/exercises/practice/palindrome-products/runtests.jl b/exercises/practice/palindrome-products/runtests.jl new file mode 100644 index 00000000..a1c8cf2e --- /dev/null +++ b/exercises/practice/palindrome-products/runtests.jl @@ -0,0 +1,79 @@ +using Test + +include("palindrome-products.jl") + +@testset verbose = true "tests" begin + @testset "find the smallest palindrome from single digit factors" begin + palindrome, factors = palindromeproducts(1, 9, true) + @test palindrome == 1 + @test factors == [[1, 1]] + end + + @testset "find the largest palindrome from single digit factors" begin + palindrome, factors = palindromeproducts(1, 9, false) + @test palindrome == 9 + @test sort(factors) == [[1, 9], [3, 3]] + end + + @testset "find the smallest palindrome from double digit factors" begin + palindrome, factors = palindromeproducts(10, 99, true) + @test palindrome == 121 + @test factors == [[11, 11]] + end + + @testset "find the largest palindrome from double digit factors" begin + palindrome, factors = palindromeproducts(10, 99, false) + @test palindrome == 9009 + @test factors == [[91, 99]] + end + + @testset "find the smallest palindrome from triple digit factors" begin + palindrome, factors = palindromeproducts(100, 999, true) + @test palindrome == 10201 + @test factors == [[101, 101]] + end + + @testset "find the largest palindrome from triple digit factors" begin + palindrome, factors = palindromeproducts(100, 999, false) + @test palindrome == 906609 + @test factors == [[913, 993]] + end + + @testset "find the smallest palindrome from four digit factors" begin + palindrome, factors = palindromeproducts(1000, 9999, true) + @test palindrome == 1002001 + @test factors == [[1001, 1001]] + end + + @testset "find the largest palindrome from four digit factors" begin + palindrome, factors = palindromeproducts(1000, 9999, false) + @test palindrome == 99000099 + @test factors == [[9901, 9999]] + end + + @testset "empty result for smallest if no palindrome in the range" begin + palindrome, factors = palindromeproducts(1002, 1003, true) + @test isnothing(palindrome) + @test isempty(factors) + end + + @testset "empty result for largest if no palindrome in the range" begin + palindrome, factors = palindromeproducts(15, 15, false) + @test isnothing(palindrome) + @test isempty(factors) + end + + @testset "error result for smallest if min is more than max" begin + @test_throws ArgumentError palindromeproducts(10000, 1, true) + end + + @testset "error result for largest if min is more than max" begin + @test_throws ArgumentError palindromeproducts(10000, 1, false) + end + + @testset "smallest product does not use the smallest factor" begin + palindrome, factors = palindromeproducts(3215, 4000, true) + @test palindrome == 10988901 + @test factors == [[3297, 3333]] + end +end