Uniquely Constant
with Raku

by Arne Sommer

Uniquely Constant with Raku

[381] Published 25. January 2026.

This is my response to The Weekly Challenge #357.

#357.1 Kaprekar Constant

Write a function that takes a 4-digit integer and returns how many iterations are required to reach Kaprekar’s constant (6174). For more information about Kaprekar's Constant please follow the wikipedia page.

Example 1:
Input: $int = 3524
Output: 3

Iteration 1: 5432 - 2345 = 3087
Iteration 2: 8730 - 0378 = 8352
Iteration 3: 8532 - 2358 = 6174
Example 2:
Input: $int = 6174
Output: 0
Example 3:
Input: $int = 9998
Output: 5

Iteration 1: 9998 - 8999 = 0999
Iteration 2: 9990 - 0999 = 8991
Iteration 3: 9981 - 1899 = 8082
Iteration 4: 8820 - 0288 = 8532
Iteration 5: 8532 - 2358 = 6174
Example 4:
Input: $int = 1001
Output: 4

Iteration 1: 1100 - 0011 = 1089
Iteration 2: 9810 - 0189 = 9621
Iteration 3: 9621 - 1269 = 8352
Iteration 4: 8532 - 2358 = 6174
Example 5:
Input: $int = 1111
Output: -1

The sequence does not converge on 6174, so return -1.

File: kaprekar-constant
#! /usr/bin/env raku

unit sub MAIN (Int $int is copy where 1000 <= $int <= 9999,  # [1]
               :v(:$verbose));

my $iterations   = 0;                                        # [2]
constant $target = 6174;                                     # [3]

while $int != $target                                        # [4]
{
  $iterations++;                                             # [5]

  my $small = $int.comb.sort.join;                           # [6]
  my $large = $small.flip;                                   # [7]

  $large *= 10 while $large < 1000;                          # [8]

  $int      = $large - $small;                               # [9]

  say ": $iterations: $large - $small = $int" if $verbose;

  { say "-1"; exit; } unless $int;                           # [10]
}

say $iterations;                                             # [11]

[1] Ensure a four digit integer. The is copy adverb is there to make it possible to change the value later (see [7]).

See docs.raku.org/type/Parameter#method_copy for more information about is copy.

[2] The result; the number of iterations. None so far.

[3] The target. Declared as a constant, as it is constant.

See docs.raku.org/syntax/constant for more information about constant.

[4] As long as we have not reached the target.

[5] One more iteration to count.

[6] Split the integer into digits (with comb), sort them (smallest first) and glue them together again (with join).

[7] Reverse the string with flip.

See docs.raku.org/routine/flip for more information about flip.

[8] Any leading zeroes of $int are missing. See the verbose output from the third example for why this may occur. We fix this by adding them as trailing zeroes on the large number.

[9] Get the new integer.

[10] Prevent an eternal loop, which we would get if we reached zero, as described in the wikipedia article.

[11] Print the number of iterations.

Running it:

$ ./kaprekar-constant 3524
3

$ ./kaprekar-constant 6174
0

$ ./kaprekar-constant 9998
5

$ ./kaprekar-constant 1001
4

$ ./kaprekar-constant 1111
-1

Looking good.

With verbose mode:

$ ./kaprekar-constant -v 3524
: 1: 5432 - 2345 = 3087
: 2: 8730 - 0378 = 8352
: 3: 8532 - 2358 = 6174
3

$ ./kaprekar-constant -v 6174
0

$ ./kaprekar-constant -v 9998
: 1: 9998 - 8999 = 999
: 2: 9990 - 999 = 8991
: 3: 9981 - 1899 = 8082
: 4: 8820 - 0288 = 8532
: 5: 8532 - 2358 = 6174
5

$ ./kaprekar-constant -v 1001
: 1: 1100 - 0011 = 1089
: 2: 9810 - 0189 = 9621
: 3: 9621 - 1269 = 8352
: 4: 8532 - 2358 = 6174
4

$ ./kaprekar-constant -v 1111
: 1: 1111 - 1111 = 0
-1

#357.2 Unique Fraction Generator Given a positive integer N, generate all unique fractions you can create using integers from 1 to N and follow the rules below:
  • Use numbers 1 through N only (no zero)
  • Create fractions like numerator/denominator
  • List them in ascending order (from smallest to largest)
  • If two fractions have the same value (like 1/2 and 2/4), only show the one with the smallest numerator
Example 1:
Input: $int = 3
Output: 1/3, 1/2, 2/3, 1/1, 3/2, 2/1, 3/1
Example 2:
Input: $int = 4
Output: 1/4, 1/3, 1/2, 2/3, 3/4, 1/1, 4/3, 3/2, 2/1, 3/1, 4/1
Example 3:
Input: $int = 1
Output: 1/1
Example 4:
Input: $int = 6
Output: 1/6, 1/5, 1/4, 1/3, 2/5, 1/2, 3/5, 2/3, 3/4,
        4/5, 5/6, 1/1, 6/5, 5/4, 4/3, 3/2, 5/3, 2/1,
        5/2, 3/1, 4/1, 5/1, 6/1
Example 5:
Input: $int = 5
Output: 1/5, 1/4, 1/3, 2/5, 1/2, 3/5, 2/3, 3/4, 4/5, 1/1,
        5/4, 4/3, 3/2, 5/3, 2/1, 5/2, 3/1, 4/1, 5/1

Raku's built in support for rational numbers makes this easy:

> 1/3 + 1/3 + 1/3;  # -> 1
> (1/2).WHAT;       # -> (Rat)

See docs.raku.org/type/Rat for more information about the Rat type.

File: ufg
#! /usr/bin/env raku

unit sub MAIN (Int $int where $int > 0, :v(:$verbose));  # [1]

my @fractions;                                           # [2]
my @verbose;

for 1 .. $int -> $numerator                              # [3]
{
  for 1 .. $int -> $denominator                          # [4]
  {
    @fractions.push: $numerator / $denominator;          # [5]
    @verbose.push: "$numerator/$denominator" if $verbose;
  }
}

say ": Added: { @verbose.join(", ") }" if $verbose;

say @fractions.sort.squish.map({ .numerator ~ "/"
  ~ .denominator }).join(", ");                          # [6]

[1] Ensure a positive integer.

[2] The fractions will be collected here, with duplicates.

[3] Iterate over the numerators,

[4] and the denominators.

[5] Calculate the fraction and add it to the list.

[6] We are requested to print the values in ascending order, so we sort them. (The values are numeric, so they are sorted numerically.) Then we apply squish to get rid of duplicates (*). (squish only works on sorted data, which we have here. Use unique if the data is unsorted.) Then we use map to explicitly print the numerator, / and the denominator version of the values, as a comma separated string. (Just printing the values would have given e.g. 4 instead of 4/1.)

* = 2/4 and 1/2 have the same numeric value, and the first one is actually reduced to the same numerator and denominator as the second one internally.

See docs.raku.org/routine/squish for more information about squish.

See docs.raku.org/routine/numerator for more information about numerator.

See docs.raku.org/routine/denominator for more information about denominator.

Running it:

$ ./ufg 3
1/3, 1/2, 2/3, 1/1, 3/2, 2/1, 3/1

$ ./ufg 4
1/4, 1/3, 1/2, 2/3, 3/4, 1/1, 4/3, 3/2, 2/1, 3/1, 4/1

$ ./ufg 1
1/1

$ ./ufg 6
1/6, 1/5, 1/4, 1/3, 2/5, 1/2, 3/5, 2/3, 3/4, 4/5, 5/6, 1/1, 6/5, 5/4, \
  4/3, 3/2, 5/3, 2/1, 5/2, 3/1, 4/1, 5/1, 6/1

$ ./ufg 5
1/5, 1/4, 1/3, 2/5, 1/2, 3/5, 2/3, 3/4, 4/5, 1/1, 5/4, 4/3, 3/2, 5/3, \
  2/1, 5/2, 3/1, 4/1, 5/1

Looking good.

With verbose mode, showing the duplicates:

$ ./ufg -v 3
: Added: 1/1, 1/2, 1/3, 2/1, 2/2, 2/3, 3/1, 3/2, 3/3
1/3, 1/2, 2/3, 1/1, 3/2, 2/1, 3/1

$ ./ufg -v 4
: Added: 1/1, 1/2, 1/3, 1/4, 2/1, 2/2, 2/3, 2/4, 3/1, 3/2, 3/3, 3/4, \
  4/1, 4/2, 4/3, 4/4
1/4, 1/3, 1/2, 2/3, 3/4, 1/1, 4/3, 3/2, 2/1, 3/1, 4/1

$ ./ufg -v 1
: Added: 1/1
1/1

$ ./ufg -v 6
: Added: 1/1, 1/2, 1/3, 1/4, 1/5, 1/6, 2/1, 2/2, 2/3, 2/4, 2/5, 2/6, \
  3/1, 3/2, 3/3, 3/4, 3/5, 3/6, 4/1, 4/2, 4/3, 4/4, 4/5, 4/6, 5/1, 5/2, \
  5/3, 5/4, 5/5, 5/6, 6/1, 6/2, 6/3, 6/4, 6/5, 6/6
1/6, 1/5, 1/4, 1/3, 2/5, 1/2, 3/5, 2/3, 3/4, 4/5, 5/6, 1/1, 6/5, 5/4, \
  4/3, 3/2, 5/3, 2/1, 5/2, 3/1, 4/1, 5/1, 6/1

$ ./ufg -v 5
: Added: 1/1, 1/2, 1/3, 1/4, 1/5, 2/1, 2/2, 2/3, 2/4, 2/5, 3/1, 3/2, \
  3/3, 3/4, 3/5, 4/1, 4/2, 4/3, 4/4, 4/5, 5/1, 5/2, 5/3, 5/4, 5/5
1/5, 1/4, 1/3, 2/5, 1/2, 3/5, 2/3, 3/4, 4/5, 1/1, 5/4, 4/3, 3/2, 5/3, \
  2/1, 5/2, 3/1, 4/1, 5/1

And that's it.