Skip to content

Commit

Permalink
Add palindrome-products exercise
Browse files Browse the repository at this point in the history
  • Loading branch information
ageron committed Oct 15, 2024
1 parent d53f7d1 commit ffe8174
Show file tree
Hide file tree
Showing 8 changed files with 365 additions and 0 deletions.
8 changes: 8 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,14 @@
"prerequisites": [],
"difficulty": 6
},
{
"slug": "palindrome-products",
"name": "Palindrome Products",
"uuid": "a0f2579e-f990-4773-a05d-e7a508fcd53e",
"practices": [],
"prerequisites": [],
"difficulty": 6
},
{
"slug": "rational-numbers",
"name": "Rational Numbers",
Expand Down
36 changes: 36 additions & 0 deletions exercises/practice/palindrome-products/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -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)`.
64 changes: 64 additions & 0 deletions exercises/practice/palindrome-products/.meta/Example.roc
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
module [smallest, largest]

smallest : { min : U64, max : U64 } -> Result { value : U64, factors : Set (U64, U64) } [MinWasLargerThanMax]
smallest = \{ min, max } ->
if min > max then
Err MinWasLargerThanMax
else

help = \factor1, factor2, bestValue, factors ->
if factor1 > max then
finalValue = if factors == [] then 0 else bestValue
Ok { value: finalValue, factors: Set.fromList factors }
else if factor2 == max + 1 then
help (factor1 + 1) (factor1 + 1) bestValue factors
else

value = factor1 * factor2
if value > bestValue then
help (factor1 + 1) (factor1 + 1) bestValue factors
else
nextFactor2 = factor2 + 1
if value == bestValue then
newFactors = factors |> List.append (factor1, factor2)
help factor1 nextFactor2 bestValue newFactors
else if value |> isPalindrome then
help factor1 nextFactor2 value [(factor1, factor2)]
else
help factor1 nextFactor2 bestValue factors

help min min Num.maxU64 []

largest : { min : U64, max : U64 } -> Result { value : U64, factors : Set (U64, U64) } [MinWasLargerThanMax]
largest = \{ min, max } ->
if min > max then
Err MinWasLargerThanMax
else

help = \factor1, factor2, bestValue, factors ->
if factor1 < min then
finalValue = if factors == [] then 0 else bestValue
Ok { value: finalValue, factors: Set.fromList factors }
else if factor2 < factor1 then
help (factor1 - 1) max bestValue factors
else

value = factor1 * factor2
if value < bestValue then
help (factor1 - 1) max bestValue factors
else
nextFactor2 = factor2 - 1
if value == bestValue then
newFactors = factors |> List.append (factor1, factor2)
help factor1 nextFactor2 bestValue newFactors
else if value |> isPalindrome then
help factor1 nextFactor2 value [(factor1, factor2)]
else
help factor1 nextFactor2 bestValue factors

help max max 0 []

isPalindrome : U64 -> Bool
isPalindrome = \number ->
digits = number |> Num.toStr |> Str.toUtf8
digits == digits |> List.reverse
19 changes: 19 additions & 0 deletions exercises/practice/palindrome-products/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"authors": [
"ageron"
],
"files": {
"solution": [
"PalindromeProducts.roc"
],
"test": [
"palindrome-products-test.roc"
],
"example": [
".meta/Example.roc"
]
},
"blurb": "Detect palindrome products in a given range.",
"source": "Problem 4 at Project Euler",
"source_url": "https://projecteuler.net/problem=4"
}
31 changes: 31 additions & 0 deletions exercises/practice/palindrome-products/.meta/template.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{%- import "generator_macros.j2" as macros with context -%}
{{ macros.canonical_ref() }}
{{ macros.header() }}

import {{ exercise | to_pascal }} exposing [smallest, largest]

isEq = \result, expected ->
when (result, expected) is
(Ok {value, factors}, Ok {value: expectedValue, factors: expectedFactors}) ->
value == expectedValue && factors == expectedFactors
_ -> Bool.false

{% for case in cases -%}
# {{ case["description"] }}
expect
result = {{ case["property"] | to_camel }} {{ case["input"] | to_roc }}
{%- if case["expected"]["error"] %}
result |> Result.isErr
{%- else %}
expected = Ok {
value: {% if case["expected"]["value"] is none %}0{% else %}{{ case["expected"]["value"] }}{% endif %},
factors: Set.fromList [
{%- for pair in case["expected"]["factors"] %}
({{ pair[0] }}, {{ pair[1] }}),{% endfor %}
]
}
result |> isEq expected
{%- endif %}

{% endfor %}

49 changes: 49 additions & 0 deletions exercises/practice/palindrome-products/.meta/tests.toml
Original file line number Diff line number Diff line change
@@ -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"
9 changes: 9 additions & 0 deletions exercises/practice/palindrome-products/PalindromeProducts.roc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module [smallest, largest]

smallest : { min : U64, max : U64 } -> Result { value : U64, factors : Set (U64, U64) } _
smallest = \{ min, max } ->
crash "Please implement the 'smallest' function"

largest : { min : U64, max : U64 } -> Result { value : U64, factors : Set (U64, U64) } _
largest = \{ min, max } ->
crash "Please implement the 'largest' function"
149 changes: 149 additions & 0 deletions exercises/practice/palindrome-products/palindrome-products-test.roc
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# These tests are auto-generated with test data from:
# https://github.com/exercism/problem-specifications/tree/main/exercises/palindrome-products/canonical-data.json
# File last updated on 2024-10-15
app [main] {
pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.15.0/SlwdbJ-3GR7uBWQo6zlmYWNYOxnvo8r6YABXD-45UOw.tar.br",
}

main =
Task.ok {}

import PalindromeProducts exposing [smallest, largest]

isEq = \result, expected ->
when (result, expected) is
(Ok { value, factors }, Ok { value: expectedValue, factors: expectedFactors }) ->
value == expectedValue && factors == expectedFactors

_ -> Bool.false

# find the smallest palindrome from single digit factors
expect
result = smallest { min: 1, max: 9 }
expected = Ok {
value: 1,
factors: Set.fromList [
(1, 1),
],
}
result |> isEq expected

# find the largest palindrome from single digit factors
expect
result = largest { min: 1, max: 9 }
expected = Ok {
value: 9,
factors: Set.fromList [
(1, 9),
(3, 3),
],
}
result |> isEq expected

# find the smallest palindrome from double digit factors
expect
result = smallest { min: 10, max: 99 }
expected = Ok {
value: 121,
factors: Set.fromList [
(11, 11),
],
}
result |> isEq expected

# find the largest palindrome from double digit factors
expect
result = largest { min: 10, max: 99 }
expected = Ok {
value: 9009,
factors: Set.fromList [
(91, 99),
],
}
result |> isEq expected

# find the smallest palindrome from triple digit factors
expect
result = smallest { min: 100, max: 999 }
expected = Ok {
value: 10201,
factors: Set.fromList [
(101, 101),
],
}
result |> isEq expected

# find the largest palindrome from triple digit factors
expect
result = largest { min: 100, max: 999 }
expected = Ok {
value: 906609,
factors: Set.fromList [
(913, 993),
],
}
result |> isEq expected

# find the smallest palindrome from four digit factors
expect
result = smallest { min: 1000, max: 9999 }
expected = Ok {
value: 1002001,
factors: Set.fromList [
(1001, 1001),
],
}
result |> isEq expected

# find the largest palindrome from four digit factors
expect
result = largest { min: 1000, max: 9999 }
expected = Ok {
value: 99000099,
factors: Set.fromList [
(9901, 9999),
],
}
result |> isEq expected

# empty result for smallest if no palindrome in the range
expect
result = smallest { min: 1002, max: 1003 }
expected = Ok {
value: 0,
factors: Set.fromList [
],
}
result |> isEq expected

# empty result for largest if no palindrome in the range
expect
result = largest { min: 15, max: 15 }
expected = Ok {
value: 0,
factors: Set.fromList [
],
}
result |> isEq expected

# error result for smallest if min is more than max
expect
result = smallest { min: 10000, max: 1 }
result |> Result.isErr

# error result for largest if min is more than max
expect
result = largest { min: 2, max: 1 }
result |> Result.isErr

# smallest product does not use the smallest factor
expect
result = smallest { min: 3215, max: 4000 }
expected = Ok {
value: 10988901,
factors: Set.fromList [
(3297, 3333),
],
}
result |> isEq expected

0 comments on commit ffe8174

Please sign in to comment.