[ Index | Introduction | Base | Recursion | Loops | Summary | RakuConf ]
Note that we cannot change the maximum word length in this program. We have 9 hard coded loops, one for each letter.
File: generate-words-loops
#! /usr/bin/env raku
unit sub MAIN (UInt :a(:$alphabet) where 1 <= $alphabet <= 35 = 0,
UInt :l(:$limit) where $limit > 0 = 9_000_000_000,
:v(:$verbose));
my $count = 0;
my $last-word = "";
my @alphabet = (1..9, 'A'..'Z').flat.[^$alphabet];
say ": Alphabet: { @alphabet.join(", ") }" if $verbose;
ALPHABET: # [1]
for @alphabet -> $first # [2]
{
register($first); # [3]
for @alphabet -> $second
{
my $two = $first ~ $second; # [4]
register($two);
for @alphabet -> $third
{
my $three = $two ~ $third;
register($three);
for @alphabet -> $fourth
{
my $four = $three ~ $fourth;
next if $four ~~ /(.) {} :my $c=$0; <?after $c ** 4> /; # [5]
register($four);
for @alphabet -> $fifth
{
my $five = $four ~ $fifth;
next if $five ~~ /(.) {} :my $c=$0; <?after $c ** 4> /;
register($five);
for @alphabet -> $sixth
{
my $six = $five ~ $sixth;
next if $six ~~ /(.) {} :my $c=$0; <?after $c ** 4> /;
register($six);
for @alphabet -> $seventh
{
my $seven = $six ~ $seventh;
next if $seven ~~ /(.) {} :my $c=$0; <?after $c ** 4> /;
register($seven);
for @alphabet -> $eighth
{
my $eight = $seven ~ $eighth;
next if $eight ~~ /(.) {} :my $c=$0; <?after $c ** 4> /;
register($eight);
for @alphabet -> $ninth
{
my $nine = $eight ~ $ninth;
next if $nine ~~ /(.) {} :my $c=$0; <?after $c ** 4> /;
register($nine);
}
}
}
}
}
}
}
}
}
sub register ($word) # [6]
{
$count++; # [7]
$last-word = $word; # [8]
say ": Word: $word (#$count)" if $verbose;
last ALPHABET if $count >= $limit; # [9]
}
say "$count words (last '$last-word' with length { $last-word.chars } \
stopped at target: { (1000000 * $count/$limit).Int / 10000 }%)";
[1] Use this label to exit the whole loop in one go (when we have reached the target number of words; see [9]).
[2] Iterate over the first character in the new word,
[3] and register it (see [6]).
[4] We build up the word by appending the current letter to the word from the prior loop.
[5] Now we have four characters in the word, the shortest word length where and the succession rule can apply.
[6] Register the word;
[7] • increase the counter.
[8] • save the word (for the final summary line).
[9] • we can exit a loop, from within a procedure called from the loop. This is really nice, and/or magical...
We get the exact same order as in the recursive version:
$ ./generate-words-loops -a=10 -l=15 -v
: Alphabet: 1, 2, 3, 4, 5, 6, 7, 8, 9, A
: Word: 1 (#1)
: Word: 11 (#2)
: Word: 111 (#3)
: Word: 1112 (#4)
: Word: 11121 (#5)
: Word: 111211 (#6)
: Word: 1112111 (#7)
: Word: 11121112.. (#8)
: Word: 111211121 (#9)
: Word: 111211122 (#10)
: Word: 111211123 (#11)
: Word: 111211124 (#12)
: Word: 111211125 (#13)
: Word: 111211126 (#14)
: Word: 111211127 (#15)
15 words (last '111211127' with length 9 stopped at target: 100%)
We will discuss the efficiency (time usage) of the different programs in the next part.
[ Index | Introduction | Base | Recursion | Loops | Summary | RakuConf ]