This is my response to the Perl Weekly Challenge #104.
Write a script to generate first 50 members of FUSC Sequence
. Please refer to
OEIS for more information.
The sequence defined as below:
fusc(0) = 0
fusc(1) = 1
for n > 1:
when n is even: fusc(n) = fusc(n / 2),
when n is odd: fusc(n) = fusc((n-1)/2) + fusc((n+1)/2)
This is yet another sequence that would have fitted right in in my Centenary Sequences with Raku article series.
We can set up this as a sequence with
gather
/take
:
#! /usr/bin/env raku
unit sub MAIN ($limit = 50); # [1]
my $fusc := gather # [2]
{
take 0; # [3]
take 1; # [4]
my $index = 1; # [5]
loop # [6]
{
$index++; # [7]
take $fusc[$index / 2]; # [8]
$index++; # [7]
take $fusc[($index - 1)/2] + $fusc[($index +1)/2]; # [9]
}
}
say $fusc[^$limit].join(", "); # [10]
[1] Default to the first 50 values.
[2] A gather
block to gather the following values.
[3] The first value, with take
.
[4] The second value.
[5] The sequence relies on previous values, hence the need for the index.
[6] En eternal loop. Note that we used binding (:=
in [2]), so
the values are not computed until we need them.
[7] Update the index.
[8] This is the value, when the index is even.
[9] And this is the value, when the index is odd.
[10] Print the requested number of values.
See my Raku Gather,
I Take article or
docs.raku.org/syntax/gather take for more information about
gather
/take
.
Running it:
$ ./fusc-seq 10
0, 1, 1, 2, 1, 3, 2, 3, 1, 4
$ ./fusc-seq
0, 1, 1, 2, 1, 3, 2, 3, 1, 4, 3, 5, 2, 5, 3, 4, 1, 5, 4, 7, 3, 8, 5, 7, 2, \
7, 5, 8, 3, 7, 4, 5, 1, 6, 5, 9, 4, 11, 7, 10, 3, 11, 8, 13, 5, 12, 7, 9, 2, 9
Note that this program (as opposed to a recursive
approach) only calculates each value once. The next time we need a prior value (in [8]
or [9]), it looks it up in the the $fusc
variable. We got built in caching,
for free.
NIM Game
.
a) You have 12 tokens
b) Each player can pick 1, 2 or 3 tokens at a time
c) The player who picks the last token wins the game
The program is not very smart. It picks the number of tokens (1, 2 or 3) by random. Except when there is 3 or less tokens left, when it takes them all.
File: nim-game
#! /usr/bin/env raku
unit sub MAIN;
my $tokens = 12; # [1]
loop # [2]
{
say "Remaining tokens: $tokens";
my $count = prompt "How many tokens do you want (1,2,3): "; # [3]
die unless $count == any(1,2,3); # [4]
$tokens -= $count; # [5]
if $tokens <= 0 # [6]
{
say "You won!";
last; # [6a]
}
say "Remaining tokens: $tokens";
$count = $tokens <= 3 ?? $tokens !! (1,2,3).pick; # [7]
say "Machine picked $count tokens";
$tokens -= $count; # [5]
if $tokens <= 0 # [8]
{
say "The Machine won!";
last; # [8a]
}
}
[1] The game starts with 12 tokens.
[2] An eternal loop. Note the two (explicit) exits with last
, in
[6a] and [8a].
[3] Use prompt
to get user input, after printing
the text (if any).
[4] Using an any
junction to check that the input values is one of
1, 2 or 3. Terminate the program if not. (This is not very user friendly, but
it can be considered a suitable punishment for typing in something illegal.)
[5] Update the number of tokens left.
[6] It is ok to specify more tokens than we have left. You win if you take the last one(s).
[7] The machine player takes all the remaining tokens, if there afre 3 or less
of them. if not, it picks a random number between 1 and 3 (with pick
).
[8] Has the machine player won?
See
docs.raku.org/routine/prompt for
more information about prompt
.
Running it:
$ ./nim-game
Remaining tokens: 12
How many tokens do you want (1,2,3): 3
Remaining tokens: 9
Machine picked 3 tokens
Remaining tokens: 6
How many tokens do you want (1,2,3): 2
Remaining tokens: 4
Machine picked 3 tokens
Remaining tokens: 1
How many tokens do you want (1,2,3): 1
You won!
$ ./nim-game
Remaining tokens: 12
How many tokens do you want (1,2,3): 3
Remaining tokens: 9
Machine picked 1 tokens
Remaining tokens: 8
How many tokens do you want (1,2,3): 3
Remaining tokens: 5
Machine picked 2 tokens
Remaining tokens: 3
How many tokens do you want (1,2,3): 2
Remaining tokens: 1
Machine picked 1 tokens
The Machine won!
You win if you can arrange a situation where there are 4 tokens left when it is the other user's turn.
And that's it.