diff options
Diffstat (limited to 'challenge-246')
| -rw-r--r-- | challenge-246/athanasius/perl/ch-1.pl | 86 | ||||
| -rw-r--r-- | challenge-246/athanasius/perl/ch-2.pl | 267 | ||||
| -rw-r--r-- | challenge-246/athanasius/raku/ch-1.raku | 79 | ||||
| -rw-r--r-- | challenge-246/athanasius/raku/ch-2.raku | 261 |
4 files changed, 693 insertions, 0 deletions
diff --git a/challenge-246/athanasius/perl/ch-1.pl b/challenge-246/athanasius/perl/ch-1.pl new file mode 100644 index 0000000000..505e8d8be5 --- /dev/null +++ b/challenge-246/athanasius/perl/ch-1.pl @@ -0,0 +1,86 @@ +#!perl + +################################################################################ +=comment + +Perl Weekly Challenge 246 +========================= + +TASK #1 +------- +*6 out of 49* + +Submitted by: Andreas Voegele + +6 out of 49 is a German lottery. + +Write a script that outputs six unique random integers from the range 1 to 49. + +Output + + 3 + 10 + 11 + 22 + 38 + 49 + +=cut +################################################################################ + +#--------------------------------------# +# Copyright © 2023 PerlMonk Athanasius # +#--------------------------------------# + +#=============================================================================== +=comment + +Assumption +---------- +From the sample output, it appears that the selected integers should be display- +ed in ascending numerical order. + +=cut +#=============================================================================== + +use v5.32.1; # Enables strictures +use warnings; +use Const::Fast; +use List::Util qw( shuffle ); +use Test::More; + +const my $START => 1; +const my $END => 49; +const my $SELECT => 6; +const my $USAGE => +"Usage: + perl $0\n"; + +#------------------------------------------------------------------------------- +BEGIN +#------------------------------------------------------------------------------- +{ + $| = 1; + print "\nChallenge 246, Task #1: 6 out of 49 (Perl)\n\n"; +} + +#=============================================================================== +MAIN: +#=============================================================================== +{ + if (scalar @ARGV == 0) + { + print "Output\n\n"; + + my @selection = (shuffle( $START .. $END ))[ 0 .. $SELECT - 1 ]; + @selection = sort { $a <=> $b } @selection; + + printf " %2d\n", $_ for @selection; + } + else + { + die "ERROR: Command-line argument(s) found\n$USAGE"; + } +} + +################################################################################ diff --git a/challenge-246/athanasius/perl/ch-2.pl b/challenge-246/athanasius/perl/ch-2.pl new file mode 100644 index 0000000000..45a75928fd --- /dev/null +++ b/challenge-246/athanasius/perl/ch-2.pl @@ -0,0 +1,267 @@ +#!perl + +################################################################################ +=comment + +Perl Weekly Challenge 246 +========================= + +TASK #2 +------- +*Linear Recurrence of Second Order* + +Submitted by: Jorg Sommrey + +You are given an array @a of five integers. + +Write a script to decide whether the given integers form a linear recurrence of +second order with integer factors. + +A linear recurrence of second order has the form + + a[n] = p * a[n-2] + q * a[n-1] with n > 1 + + where p and q must be integers. + +Example 1 + + Input: @a = (1, 1, 2, 3, 5) + Output: true + + @a is the initial part of the Fibonacci sequence a[n] = a[n-2] + a[n-1] + with a[0] = 1 and a[1] = 1. + +Example 2 + + Input: @a = (4, 2, 4, 5, 7) + Output: false + + a[1] and a[2] are even. Any linear combination of two even numbers with + integer factors is even, too. + Because a[3] is odd, the given numbers cannot form a linear recurrence of + second order with integer factors. + +Example 3 + + Input: @a = (4, 1, 2, -3, 8) + Output: true + + a[n] = a[n-2] - 2 * a[n-1] + +=cut +################################################################################ + +#--------------------------------------# +# Copyright © 2023 PerlMonk Athanasius # +#--------------------------------------# + +#=============================================================================== +=comment + +Interface +--------- +1. If no command-line arguments are given, the test suite is run. Otherwise: +2. If $VERBOSE is set to a true value, and the given sequence does form a linear + recurrence of the second order, the values of p and q are shown in the + recurrence relation. + +Analysis +-------- +Let Z be the set of integers, and let the input list be (a, b, c, d, e) where +each of a ... e is an element of Z. Then, from the recurrence relation: + + a[n] = p * a[n-2] + q * a[n-1] with n > 1 + +if follows that: + + c = pa + qb (1) + d = pb + qc (2) +and e = pc + qd (3) + +Solving (1) ∧ (2) as 2 simultaneous equations with 2 variables (see below), we +determine the values of p and q in terms of the given constants a, b, c, and d. +If either p or q is not an integer, the input integers do not form a linear +recurrence of the second order with integer factors. + +If both p and q are integers, it remains to determine from (3) whether the +derived values of p and q correctly generate e, the fifth term in the series. +If they do, the input integers DO form a linear recurrence relation of the +second order with integer factors. + +* * * + +Solving (1) and (2) as simultaneous equations: + +From (1): pa + qb = c ⊃ + qb = c - pa ⊃ + q = (c - pa)/b (4) + +From (2): pb + qc = d ⊃ + pb + c[(c - pa)/b] = d ⊃ from (4) + pb + (c² - pac)/b = d ⊃ + pb² + c² - pac = bd ⊃ + pb² - pac = bd - c² ⊃ + p(b² - ac) = bd - c² ⊃ + p = (bd - c²)/(b² - ac) (5) + +From (4): q = (c - pa)/b ⊃ + q = (c - a[(bd - c²)/(b² - ac)])/b from (5) + +=cut +#=============================================================================== + +use v5.32.1; # Enables strictures +use warnings; +use Const::Fast; +use Regexp::Common qw( number ); +use Test::More; + +const my $VERBOSE => 1; +const my $EPSILON => 1e-9; +const my $USAGE => +"Usage: + perl $0 [<a> ...] + perl $0 + + [<a> ...] A list of 5 integers\n"; + +#------------------------------------------------------------------------------- +BEGIN +#------------------------------------------------------------------------------- +{ + $| = 1; + print "\nChallenge 246, Task #2: Linear Recurrence of Second Order (Perl)" . + "\n\n"; +} + +#=============================================================================== +MAIN: +#=============================================================================== +{ + if (scalar @ARGV == 0) + { + run_tests(); + } + else + { + my @a = @ARGV; + + / ^ $RE{num}{int} $ /x or error( qq["$_" is not a valid integer] ) + for @a; + + my $argc = scalar @a; + $argc == 5 or error( "Expected 5 integers, found $argc" ); + + printf "Input: \@a = (%s)\n", join ', ', @a; + + my ($p, $q) = solve( \@a ); + my $success = defined $p && defined $q; + + printf "Output: %s\n", $success ? 'true' : 'false'; + + if ($VERBOSE && $success) + { + print "\nRecurrence relation:\n"; + printf " a[n] = %d * a[n-2] %s %d * a[n-1]\n", + $p, ($q < 0 ? '-' : '+'), abs $q; + } + } +} + +#------------------------------------------------------------------------------- +sub solve +#------------------------------------------------------------------------------- +{ + my ($ints) = @_; + my ($p, $q); + my ($a, $b, $c, $d, $e) = @$ints; + + # p = (bd - c²) / (b² - ac) + + my $divisor = $b * $b - $a * $c; + + if ($divisor && $b) + { + my $p_ = ($b * $d - $c * $c) / $divisor; + + if (is_int( $p_ )) + { + # q = (c - a[ (bd - c²) / (b² - ac) ]) / b + + my $q_ = ($c - $a * ( ($b * $d - $c * $c) / $divisor )) / $b; + + if (is_int( $q_ )) + { + my $exp_e = $p_ * $c + $q_ * $d; + + ($p, $q) = ($p_, $q_) if is_int( $exp_e ) && $e == $exp_e; + } + } + } + + return ($p, $q); +} + +#------------------------------------------------------------------------------- +sub is_int +#------------------------------------------------------------------------------- +{ + abs( $_[ 0 ] - int( $_[ 0 ] ) ) < $EPSILON; +} + +#------------------------------------------------------------------------------- +sub run_tests +#------------------------------------------------------------------------------- +{ + print "Running the test suite\n"; + + while (my $line = <DATA>) + { + chomp $line; + + my ($test_name, $ints_str, $exp_p, $exp_q) = split / \| /x, $line; + + for ($test_name, $ints_str, $exp_p, $exp_q) + { + s/ ^ \s+ //x; + s/ \s+ $ //x; + } + + my @ints = split / \s+ /x, $ints_str; + my ($p, $q) = solve( \@ints ); + + if (defined $p) + { + is $p, $exp_p, "$test_name: p"; + is $q, $exp_q, "$test_name: q"; + } + else + { + is $exp_p, '', "$test_name: p"; + is $exp_q, '', "$test_name: q"; + } + } + + done_testing; +} + +#------------------------------------------------------------------------------- +sub error +#------------------------------------------------------------------------------- +{ + my ($message) = @_; + + die "ERROR: $message\n$USAGE"; +} + +################################################################################ + +__DATA__ +Example 1 | 1 1 2 3 5| 1| 1 +Example 2 | 4 2 4 5 7| | +Example 3 | 4 1 2 -3 8| 1| -2 +Example 3a | 4 1 2 -3 9| | +Run of same| 1 1 1 1 1| | +Zero b |-1 0 -1 0 -1| | +Large 1 | 1 1 25 -383 7561|42|-17 +Large 1a | 1 1 25 -383 7560| | diff --git a/challenge-246/athanasius/raku/ch-1.raku b/challenge-246/athanasius/raku/ch-1.raku new file mode 100644 index 0000000000..527d7bdd25 --- /dev/null +++ b/challenge-246/athanasius/raku/ch-1.raku @@ -0,0 +1,79 @@ +use v6d; + +################################################################################ +=begin comment + +Perl Weekly Challenge 246 +========================= + +TASK #1 +------- +*6 out of 49* + +Submitted by: Andreas Voegele + +6 out of 49 is a German lottery. + +Write a script that outputs six unique random integers from the range 1 to 49. + +Output + + 3 + 10 + 11 + 22 + 38 + 49 + +=end comment +################################################################################ + +#--------------------------------------# +# Copyright © 2023 PerlMonk Athanasius # +#--------------------------------------# + +#=============================================================================== +=begin comment + +Assumption +---------- +From the sample output, it appears that the selected integers should be display- +ed in ascending numerical order. + +=end comment +#=============================================================================== + +my Int constant START = 1; +my Int constant END = 49; +my UInt constant SELECT = 6; + +#------------------------------------------------------------------------------- +BEGIN +#------------------------------------------------------------------------------- +{ + "\nChallenge 246, Task #1: 6 out of 49 (Raku)\n".put; +} + +#=============================================================================== +sub MAIN() +#=============================================================================== +{ + "Output\n".put; + + my Int @selection = (START .. END).pick( SELECT ).sort: { $^a <=> $^b }; + + " %2d\n".printf: $_ for @selection; +} + +#------------------------------------------------------------------------------- +sub USAGE() +#------------------------------------------------------------------------------- +{ + my Str $usage = $*USAGE; + + $usage ~~ s:g/ ($*PROGRAM-NAME) /raku $0/; + + $usage.put; +} + +################################################################################ diff --git a/challenge-246/athanasius/raku/ch-2.raku b/challenge-246/athanasius/raku/ch-2.raku new file mode 100644 index 0000000000..a52f4510d0 --- /dev/null +++ b/challenge-246/athanasius/raku/ch-2.raku @@ -0,0 +1,261 @@ +use v6d; + +################################################################################ +=begin comment + +Perl Weekly Challenge 246 +========================= + +TASK #2 +------- +*Linear Recurrence of Second Order* + +Submitted by: Jorg Sommrey + +You are given an array @a of five integers. + +Write a script to decide whether the given integers form a linear recurrence of +second order with integer factors. + +A linear recurrence of second order has the form + + a[n] = p * a[n-2] + q * a[n-1] with n > 1 + + where p and q must be integers. + +Example 1 + + Input: @a = (1, 1, 2, 3, 5) + Output: true + + @a is the initial part of the Fibonacci sequence a[n] = a[n-2] + a[n-1] + with a[0] = 1 and a[1] = 1. + +Example 2 + + Input: @a = (4, 2, 4, 5, 7) + Output: false + + a[1] and a[2] are even. Any linear combination of two even numbers with + integer factors is even, too. + Because a[3] is odd, the given numbers cannot form a linear recurrence of + second order with integer factors. + +Example 3 + + Input: @a = (4, 1, 2, -3, 8) + Output: true + + a[n] = a[n-2] - 2 * a[n-1] + +=end comment +################################################################################ + +#--------------------------------------# +# Copyright © 2023 PerlMonk Athanasius # +#--------------------------------------# + +#=============================================================================== +=begin comment + +Interface +--------- +1. If no command-line arguments are given, the test suite is run. Otherwise: +2. If the first integer is negative, it must be preceded by "--" to indicate + that it is not a command-line flag. +3. If VERBOSE is set to True, and the given sequence does form a linear recur- + rence of the second order, the values of p and q are shown in the recurrence + relation. + +Analysis +-------- +Let Z be the set of integers, and let the input list be (a, b, c, d, e) where +each of a ... e is an element of Z. Then, from the recurrence relation: + + a[n] = p * a[n-2] + q * a[n-1] with n > 1 + +if follows that: + + c = pa + qb (1) + d = pb + qc (2) +and e = pc + qd (3) + +Solving (1) ∧ (2) as 2 simultaneous equations with 2 variables (see below), we +determine the values of p and q in terms of the given constants a, b, c, and d. +If either p or q is not an integer, the input integers do not form a linear +recurrence of the second order with integer factors. + +If both p and q are integers, it remains to determine from (3) whether the +derived values of p and q correctly generate e, the fifth term in the series. +If they do, the input integers DO form a linear recurrence relation of the +second order with integer factors. + +* * * + +Solving (1) and (2) as simultaneous equations: + +From (1): pa + qb = c ⊃ + qb = c - pa ⊃ + q = (c - pa)/b (4) + +From (2): pb + qc = d ⊃ + pb + c[(c - pa)/b] = d ⊃ from (4) + pb + (c² - pac)/b = d ⊃ + pb² + c² - pac = bd ⊃ + pb² - pac = bd - c² ⊃ + p(b² - ac) = bd - c² ⊃ + p = (bd - c²)/(b² - ac) (5) + +From (4): q = (c - pa)/b ⊃ + q = (c - a[(bd - c²)/(b² - ac)])/b from (5) + +=end comment +#=============================================================================== + +use Test; + +my UInt constant NUM-INTS = 5; +my Bool constant VERBOSE = True; + +#------------------------------------------------------------------------------- +BEGIN +#------------------------------------------------------------------------------- +{ + "\nChallenge 246, Task #2: Linear Recurrence of Second Order (Raku)\n".put; +} + +#=============================================================================== +multi sub MAIN +( + *@a where { .elems == NUM-INTS && .all ~~ Int:D } #= A list of 5 integers +) +#=============================================================================== +{ + "Input: \@a = (%s)\n".printf: @a.join: ', '; + + my Int ($p, $q) = solve( @a ); + my Bool $success = $p.defined && $q.defined; + + "Output: %s\n".printf: $success ?? 'true' !! 'false'; + + if VERBOSE && $success + { + "\nRecurrence relation:".put; + " a[n] = %d * a[n-2] %s %d * a[n-1]\n".printf: + $p, ($q < 0 ?? '-' !! '+'), $q.abs; + } +} + +#=============================================================================== +multi sub MAIN() # No input: run the test suite +#=============================================================================== +{ + run-tests(); +} + +#------------------------------------------------------------------------------- +sub solve( List:D[Int:D] $ints where { .elems == NUM-INTS } --> List:D[Int:_] ) +#------------------------------------------------------------------------------- +{ + my Int ($p, $q); + my Int ($a, $b, $c, $d, $e) = @$ints; + + # p = (bd - c²) / (b² - ac) + + my Int $divisor = $b * $b - $a * $c; + + if $divisor && $b + { + my Rat $p_ = ($b * $d - $c * $c) / $divisor; + + if $p_.denominator == 1 + { + # q = (c - a[ (bd - c²) / (b² - ac) ]) / b + + my Rat $q_ = ($c - $a * ( ($b * $d - $c * $c) / $divisor )) / $b; + + if $q_.denominator == 1 + { + my Rat $exp-e = $p_ * $c + $q_ * $d; + + ($p, $q) = $p_.Int, $q_.Int if $e == $exp-e; + } + } + } + + return $p, $q; +} + +#------------------------------------------------------------------------------- +sub run-tests() +#------------------------------------------------------------------------------- +{ + 'Running the test suite'.put; + + for test-data.lines -> Str $line + { + my Str ($test-name, $ints-str, $exp-p, $exp-q) = $line.split: / \| /; + + for $test-name, $ints-str, $exp-p, $exp-q + { + s/ ^ \s+ //; + s/ \s+ $ //; + } + + my Int @ints = $ints-str.split( / \s+ / ).map: { .Int }; + my Int ($p, $q) = solve( @ints ); + + if $p.defined + { + is $p, $exp-p.Int, "$test-name: p"; + is $q, $exp-q.Int, "$test-name: q"; + } + else + { + is $exp-p, '', "$test-name: p"; + is $exp-q, '', "$test-name: q"; + } + } + + done-testing; +} + +#------------------------------------------------------------------------------- +sub error( Str:D $message ) +#------------------------------------------------------------------------------- +{ + "ERROR: $message".put; + + USAGE(); + + exit 0; +} + +#------------------------------------------------------------------------------- +sub USAGE() +#------------------------------------------------------------------------------- +{ + my Str $usage = $*USAGE; + + $usage ~~ s:g/ ($*PROGRAM-NAME) /raku $0/; + + $usage.put; +} + +#------------------------------------------------------------------------------- +sub test-data( --> Str:D ) +#------------------------------------------------------------------------------- +{ + return q:to/END/; + Example 1 | 1 1 2 3 5| 1| 1 + Example 2 | 4 2 4 5 7| | + Example 3 | 4 1 2 -3 8| 1| -2 + Example 3a | 4 1 2 -3 9| | + Run of same| 1 1 1 1 1| | + Zero b |-1 0 -1 0 -1| | + Large 1 | 1 1 25 -383 7561|42|-17 + Large 1a | 1 1 25 -383 7560| | + END +} + +################################################################################ |
