diff options
| author | Luis Mochan <mochan@fis.unam.mx> | 2021-12-23 09:31:38 -0600 |
|---|---|---|
| committer | Luis Mochan <mochan@fis.unam.mx> | 2021-12-23 09:31:38 -0600 |
| commit | c715c9c6a28663983f51848c96699ffb23e6189f (patch) | |
| tree | 6e8d0ac1bc1438f1e0cd4a7ac609dda25dd66bf0 | |
| parent | 0d456859d24f97ef36d88da5b067b49baa833aa0 (diff) | |
| parent | b369a8ed20a9d70d0d2500c5bd693b8be678f2c1 (diff) | |
| download | perlweeklychallenge-club-c715c9c6a28663983f51848c96699ffb23e6189f.tar.gz perlweeklychallenge-club-c715c9c6a28663983f51848c96699ffb23e6189f.tar.bz2 perlweeklychallenge-club-c715c9c6a28663983f51848c96699ffb23e6189f.zip | |
Merge branch 'master' of github.com:manwar/perlweeklychallenge-club into challenges
35 files changed, 3191 insertions, 2096 deletions
diff --git a/challenge-001/paulo-custodio/brainfuck.py b/challenge-001/paulo-custodio/brainfuck.py new file mode 100644 index 0000000000..7ef3443113 --- /dev/null +++ b/challenge-001/paulo-custodio/brainfuck.py @@ -0,0 +1,136 @@ +#!/usr/bin/python3 + +# Run brainfuck from input +# Option: -t - trace execution + +import sys +import getopt +import re + +TAPE_SIZE = 30000 +do_trace = False + +class TuringMachine: + def __init__(self, prog): + self.tape = [0 for x in range(TAPE_SIZE)] + self.ptr = 0 + self.prog = self.parse(prog) + self.ip = 0 + + def parse(self, prog): + prog = re.sub(r"[^-+<>,.\[\]]+", "", prog) # remove non-brainfuck operations + return prog + + def done(self): + return self.ip >= len(self.prog) + + def run(self): + while not self.done(): + self.step() + + def step(self): + global do_trace + + op, n = self.get_op() + if op=="+": + self.tape[self.ptr] = (self.tape[self.ptr] + n) & 0xff + elif op=="-": + self.tape[self.ptr] = (self.tape[self.ptr] - n) & 0xff + elif op=="<": + self.ptr -= n + if self.ptr < 0: + print("pointer beyond tape start") + sys.exit(1) + elif op==">": + self.ptr += n + if self.ptr < 0: + print("pointer beyond tape end") + sys.exit(1) + elif op==".": + print(chr(self.tape[self.ptr]), end="") + if do_trace: + print("") + elif op==",": + self.tape[self.ptr] = chr(sys.stdin.read(1)) + elif op=="[": + if self.tape[self.ptr]==0: + self.find_close() + elif op=="]": + if self.tape[self.ptr]!=0: + self.find_open() + else: + pass # ignore other characters + + if do_trace: + print(op, end=" ") + if n!=1: + print(n, end=" ") + print("", end="\t") + for i in range(self.ptr+10): + if i==self.ptr: + print(f"[{self.tape[i]:3d}]", end="") + else: + print(f" {self.tape[i]:3d} ", end="") + print("") + + def get_op(self): + if self.ip > len(self.prog): + print("execution beyond program end") + sys.exit(1) + + op = self.prog[self.ip] + self.ip += 1 + n = 1 + if op in ('+', '-', '<', '>'): + while self.ip < len(self.prog) and self.prog[self.ip]==op: + self.ip += 1 + n += 1 + return op, n + + def find_close(self): + num_open = 1 + while num_open > 0: + op, n = self.get_op() + if op=='[': + num_open += 1 + elif op==']': + num_open -= 1 + + def find_open(self): + num_open = 1 + self.ip -= 2 # point to op before ] + while num_open > 0: + if self.ip < 0: + print("execution beyond program start") + sys.exit(1) + op = self.prog[self.ip] + if op==']': + num_open += 1 + elif op=='[': + num_open -= 1 + if num_open==0: + self.ip += 1 + return + self.ip -= 1 + +# parse command line options +try: + opts, args = getopt.getopt(sys.argv[1:], 't') +except getopt.GetoptError as err: + print(err) + sys.exit(1) +for o, a in opts: + if o=="-t": + do_trace = True + else: + print("unhandled option") + sys.exit(1) +if len(args)!=1: + print("Usage: brainfuck.py [-t] file") + sys.exit(1) +with open(args[0]) as f: + prog = "".join(f.readlines()) + +# initialize and run Tuting Machine +tm = TuringMachine(prog) +tm.run() diff --git a/challenge-031/paulo-custodio/Makefile b/challenge-031/paulo-custodio/Makefile new file mode 100644 index 0000000000..c3c762d746 --- /dev/null +++ b/challenge-031/paulo-custodio/Makefile @@ -0,0 +1,2 @@ +all: + perl ../../challenge-001/paulo-custodio/test.pl diff --git a/challenge-031/paulo-custodio/README b/challenge-031/paulo-custodio/README new file mode 100644 index 0000000000..87dc0b2fbd --- /dev/null +++ b/challenge-031/paulo-custodio/README @@ -0,0 +1 @@ +Solution by Paulo Custodio diff --git a/challenge-031/paulo-custodio/perl/ch-1.pl b/challenge-031/paulo-custodio/perl/ch-1.pl new file mode 100644 index 0000000000..7e96de6302 --- /dev/null +++ b/challenge-031/paulo-custodio/perl/ch-1.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl + +# Challenge 031 +# +# Task #1 +# Create a function to check divide by zero error without checking if the +# denominator is zero. + +use Modern::Perl; + +sub divide { + my($num, $den) = @_; + my $res = eval { $num / $den }; + return "division by zero trapped" if $@; + return $res; +} + +say divide(5, 2); +say divide(5, 0); diff --git a/challenge-031/paulo-custodio/perl/ch-2.pl b/challenge-031/paulo-custodio/perl/ch-2.pl new file mode 100644 index 0000000000..0647281291 --- /dev/null +++ b/challenge-031/paulo-custodio/perl/ch-2.pl @@ -0,0 +1,16 @@ +#!/usr/bin/perl + +# Challenge 031 +# +# Task #2 +# Create a script to demonstrate creating dynamic variable name, assign a value +# to the variable and finally print the variable. The variable name would be +# passed as command line argument. + +use Modern::Perl; +no strict 'refs'; + +my $name = shift || die "Usage: ch-2.pl name\n"; + +${$name} = 10; +say ${$name}; diff --git a/challenge-031/paulo-custodio/python/ch-1.py b/challenge-031/paulo-custodio/python/ch-1.py new file mode 100644 index 0000000000..6d380fde03 --- /dev/null +++ b/challenge-031/paulo-custodio/python/ch-1.py @@ -0,0 +1,18 @@ +#!/usr/bin/python3 + +# Challenge 031 +# +# Task #1 +# Create a function to check divide by zero error without checking if the +# denominator is zero. + +def divide(num, den): + try: + res = num / den + except ZeroDivisionError: + return "division by zero trapped" + else: + return res + +print(divide(5, 2 )) +print(divide(5, 0)) diff --git a/challenge-031/paulo-custodio/python/ch-2.py b/challenge-031/paulo-custodio/python/ch-2.py new file mode 100644 index 0000000000..eb5675143d --- /dev/null +++ b/challenge-031/paulo-custodio/python/ch-2.py @@ -0,0 +1,13 @@ +#!/usr/bin/python3 + +# Challenge 031 +# +# Task #2 +# Create a script to demonstrate creating dynamic variable name, assign a value +# to the variable and finally print the variable. The variable name would be +# passed as command line argument. + +import sys + +globals()[sys.argv[1]] = 10 +print(globals()[sys.argv[1]]) diff --git a/challenge-031/paulo-custodio/t/test-1.yaml b/challenge-031/paulo-custodio/t/test-1.yaml new file mode 100644 index 0000000000..7451f174a9 --- /dev/null +++ b/challenge-031/paulo-custodio/t/test-1.yaml @@ -0,0 +1,7 @@ +- setup: + cleanup: + args: + input: + output: | + 2.5 + division by zero trapped diff --git a/challenge-031/paulo-custodio/t/test-2.yaml b/challenge-031/paulo-custodio/t/test-2.yaml new file mode 100644 index 0000000000..7a099edf5c --- /dev/null +++ b/challenge-031/paulo-custodio/t/test-2.yaml @@ -0,0 +1,5 @@ +- setup: + cleanup: + args: name + input: + output: 10 diff --git a/challenge-144/athanasius/perl/ch-1.pl b/challenge-144/athanasius/perl/ch-1.pl new file mode 100644 index 0000000000..de8f7b79a4 --- /dev/null +++ b/challenge-144/athanasius/perl/ch-1.pl @@ -0,0 +1,155 @@ +#!perl + +############################################################################### +=comment + +Perl Weekly Challenge 144 +========================= + +TASK #1 +------- +*Semiprime* + +Submitted by: Mohammad S Anwar + +Write a script to generate all Semiprime number <= 100. + +For more information about Semiprime, please checkout the +[ https://en.wikipedia.org/wiki/Semiprime |wikipedia page]. + + In mathematics, a semiprime is a natural number that is the product of + exactly two prime numbers. The two primes in the product may equal each + other, so the semiprimes include the squares of prime numbers. + +Example + + 10 is Semiprime as 10 = 2 x 5 + 15 is Semiprime as 15 = 3 x 5 + +=cut +############################################################################### + +#--------------------------------------# +# Copyright © 2021 PerlMonk Athanasius # +#--------------------------------------# + +#============================================================================== +=comment + +Algorithm +--------- +(1) Primes are generated via a Sieve of Eratosthenes. But how many primes are + needed? Consider: each semiprime is the product of 2 primes, and the small- + est prime is 2. If a given prime p is such that 2p is greater than 100, + then 3p will also be greater than 100, as will 5p, and so on, so p cannot + contribute to the semiprimes less than or equal to 100. And the same logic + holds for any prime number greater than p. So the primes needed are 2, 3, + 5, ..., q, where q is the largest prime for which 2q is less than or equal + to 100. + +(2) For each prime p, semiprimes are generated by multiplying p by each of the + primes q between 2 and p, inclusive. But as soon as the product is greater + than 100, the result is discarded and the remaining values of q can also be + skipped, since they will all generate semiprimes greater than 100. + +(3) The resulting list is guaranteed to include all semiprimes less than or + equal to 100, and only those. But in some cases semiprimes are generated + out of order. For example, 5 x 3 = 15 is generated before 7 x 2 = 14. It is + therefore necessary to sort the semiprimes (in ascending numerical order) + before they are displayed. + +(4) The resulting list of semiprimes contains 34 elements as follows: + + 4, 6, 9, 10, 14, 15, 21, 22, 25, 26, 33, 34, 35, 38, 39, 46, 49, + 51, 55, 57, 58, 62, 65, 69, 74, 77, 82, 85, 86, 87, 91, 93, 94, 95 + + -- which agrees with the entry for Semiprimes in the Online Encyclopedia of + Integer Sequences, https://oeis.org/A001358 + +=cut +#============================================================================== + +use strict; +use warnings; +use Const::Fast; + +const my $MAX => 100; +const my $USAGE => "Usage:\n perl $0\n"; + +#------------------------------------------------------------------------------ +BEGIN +#------------------------------------------------------------------------------ +{ + $| = 1; + print "\nChallenge 144, Task #1: Semiprime (Perl)\n\n"; +} + +#============================================================================== +MAIN: +#============================================================================== +{ + my $args = scalar @ARGV; + $args == 0 or error( "Expected 0 command line arguments, found $args" ); + + print "The semiprimes <= $MAX are:\n\n"; + + my $primes = find_primes(); + my @semiprimes; + + L_OUTER: + for my $i (0 .. $#$primes) + { + my $prime1 = $primes->[ $i ]; + + for my $j (0 .. $i) + { + my $prime2 = $primes->[ $j ]; + my $product = $prime1 * $prime2; + + next L_OUTER if $product > $MAX; + + push @semiprimes, $product; + } + } + + @semiprimes = sort { $a <=> $b } @semiprimes; + + printf "%s\n", join ', ', @semiprimes; +} + +#------------------------------------------------------------------------------ +sub find_primes +#------------------------------------------------------------------------------ +{ + use enum qw( NOT_PRIME PRIME ); + + my $max = int( $MAX / 2 ); + my @sieve = ((NOT_PRIME) x 2, (PRIME) x ($max - 1)); + my @primes; + + for my $i (2 .. $max) + { + if ($sieve[ $i ] == PRIME) + { + push @primes, $i; + + for (my $j = 2 * $i; $j <= $max; $j += $i) + { + $sieve[ $j ] = NOT_PRIME; + } + } + } + + return \@primes; +} + +#------------------------------------------------------------------------------ +sub error +#------------------------------------------------------------------------------ +{ + my ($message) = @_; + + die "ERROR: $message\n$USAGE"; +} + +############################################################################### diff --git a/challenge-144/athanasius/perl/ch-2.pl b/challenge-144/athanasius/perl/ch-2.pl new file mode 100644 index 0000000000..66380da332 --- /dev/null +++ b/challenge-144/athanasius/perl/ch-2.pl @@ -0,0 +1,169 @@ +#!perl + +############################################################################### +=comment + +Perl Weekly Challenge 144 +========================= + +TASK #2 +------- +*Ulam Sequence* + +Submitted by: Mohammad S Anwar + +You are given two positive numbers, $u and $v. + +Write a script to generate Ulam Sequence having at least 10 Ulam numbers where +$u and $v are the first 2 Ulam numbers. + +For more information about Ulam Sequence, please checkout the +[ https://en.wikipedia.org/wiki/Ulam_number |website]. + + The standard Ulam sequence (the (1, 2)-Ulam sequence) starts with U1 = 1 + and U2 = 2. Then for n > 2, Un is defined to be the smallest integer that + is the sum of two distinct earlier terms in exactly one way and larger than + all earlier terms. + +Example 1 + + Input: $u = 1, $v = 2 + Output: 1, 2, 3, 4, 6, 8, 11, 13, 16, 18 + +Example 2 + + Input: $u = 2, $v = 3 + Output: 2, 3, 5, 7, 8, 9, 13, 14, 18, 19 + +Example 3 + + Input: $u = 2, $v = 5 + Output: 2, 5, 7, 9, 11, 12, 13, 15, 19, 23 + +=cut +############################################################################### + +#--------------------------------------# +# Copyright © 2021 PerlMonk Athanasius # +#--------------------------------------# + +#============================================================================== +=comment + +Algorithm +--------- +@ulams is an array containing Ulam numbers in the order of their discovery. +%sums is a hash matching each sum of two distinct Ulam numbers to a count of + the number of different ways in which that sum can be produced. + +The main loop generates one new Ulam number per iteration, as follows: + - New sums are generated by adding the latest (i.e. last found) Ulam number + $last to each of the previously-known Ulam numbers. + - The next Ulam number is the smallest key in %sums which (1) is greater + than $last and (2) has a count of 1. + +Note that %sums is pruned on each iteration of the main loop by deleting all +the sums less than or equal to $last. This is not strictly necessary (a +different logic could be used), but has two advantages: + 1. It simplifies the logic, as the smallest candidate Ulam number is + guaranteed to be greater than $last. + 2. It prevents %sums from becoming unnecessarily large in memory. (This is + not a consideration when $TARGET = 10, but could become significant for + large values of $TARGET.) + +Performance +----------- +On my machine, the first 10,000 Ulam numbers for $u = 1, $v = 2 (see +https://oeis.org/A002858/b002858.txt) are generated in around 15 min 33 sec. + +Note that each Ulam number is displayed as it is found. This allows the user to +monitor progress when using large values of $TARGET. + +=cut +#============================================================================== + +use strict; +use warnings; +use Const::Fast; +use List::Util qw( min ); +use Regexp::Common qw( number ); +use constant TIMER => 0; # Compile-time constant + +const my $TARGET => 10; # Run-time constants +const my $USAGE => +"Usage: + perl $0 <u> <v> + + <u> A positive integer + <v> A positive integer > u\n"; + +#------------------------------------------------------------------------------ +BEGIN +#------------------------------------------------------------------------------ +{ + $| = 1; + print "\nChallenge 144, Task #2: Ulam Sequence (Perl)\n\n"; +} + +#============================================================================== +MAIN: +#============================================================================== +{ + use if TIMER, 'Time::HiRes' => qw( gettimeofday tv_interval ); + + my $t0 = [gettimeofday] if TIMER; + my @ulams = parse_command_line(); + my $last = $ulams[ 1 ]; + my %sums; + + printf "Input: \$u = %d, \$v = %d\nOutput: %d, %d", @ulams, @ulams; + + while (scalar @ulams < $TARGET) + { + ++$sums{ $_ + $last } for @ulams[ 0 .. $#ulams - 1 ]; + + $last = min grep { $sums{ $_ } == 1 } keys %sums; + + push @ulams, $last; + print ", $last"; + + $_ <= $last && delete $sums{ $_ } for keys %sums; + } + + print "\n"; + my $t = tv_interval( $t0 ) if TIMER; + print "\n$t seconds\n" if TIMER; +} + +#------------------------------------------------------------------------------ +sub parse_command_line +#------------------------------------------------------------------------------ +{ + my $args = scalar @ARGV; + $args == 2 or error( "Expected 2 command line arguments, found $args" ); + + for (@ARGV) + { + / ^ $RE{num}{int} $ /x + or error( qq["$_" is not a valid integer] ); + + $_ > 0 or error( "$_ is not positive" ); + } + + my ($u, $v) = @ARGV; + + $v > $u or error( "$v is not greater than $u" ); + + return ($u, $v); +} + +#------------------------------------------------------------------------------ +sub error +#------------------------------------------------------------------------------ +{ + my ($message) = @_; + + die "ERROR: $message\n$USAGE"; +} + +############################################################################### diff --git a/challenge-144/athanasius/raku/ch-1.raku b/challenge-144/athanasius/raku/ch-1.raku new file mode 100644 index 0000000000..6b5cc8b077 --- /dev/null +++ b/challenge-144/athanasius/raku/ch-1.raku @@ -0,0 +1,122 @@ +use v6d; + +############################################################################### +=begin comment + +Perl Weekly Challenge 144 +========================= + +TASK #1 +------- +*Semiprime* + +Submitted by: Mohammad S Anwar + +Write a script to generate all Semiprime number <= 100. + +For more information about Semiprime, please checkout the +[ https://en.wikipedia.org/wiki/Semiprime |wikipedia page]. + + In mathematics, a semiprime is a natural number that is the product of + exactly two prime numbers. The two primes in the product may equal each + other, so the semiprimes include the squares of prime numbers. + +Example + + 10 is Semiprime as 10 = 2 x 5 + 15 is Semiprime as 15 = 3 x 5 + +=end comment +############################################################################### + +#--------------------------------------# +# Copyright © 2021 PerlMonk Athanasius # +#--------------------------------------# + +#============================================================================== +=begin comment + +Algorithm +--------- +(1) Primes are generated using Raku's built-in is-prime() method. But how many + primes are needed? Consider: each semiprime is the product of 2 primes, and + the smallest prime is 2. If a given prime p is such that 2p is greater than + 100, then 3p will also be greater than 100, as will 5p, and so on, so p + cannot contribute to the semiprimes less than or equal to 100. And the same + logic holds for any prime number greater than p. So the primes needed are + 2, 3, 5, ..., q, where q is the largest prime for which 2q is less than or + equal to 100. + +(2) For each prime p, semiprimes are generated by multiplying p by each of the + primes q between 2 and p, inclusive. But as soon as the product is greater + than 100, the result is discarded and the remaining values of q can also be + skipped, since they will all generate semiprimes greater than 100. + +(3) The resulting list is guaranteed to include all semiprimes less than or + equal to 100, and only those. But in some cases semiprimes are generated + out of order. For example, 5 x 3 = 15 is generated before 7 x 2 = 14. It is + therefore necessary to sort the semiprimes (in ascending numerical order) + before they are displayed. + +(4) The resulting list of semiprimes contains 34 elements as follows: + + 4, 6, 9, 10, 14, 15, 21, 22, 25, 26, 33, 34, 35, 38, 39, 46, 49, + 51, 55, 57, 58, 62, 65, 69, 74, 77, 82, 85, 86, 87, 91, 93, 94, 95 + + -- which agrees with the entry for Semiprimes in the Online Encyclopedia of + Integer Sequences, https://oeis.org/A001358 + +=end comment +#============================================================================== + +my UInt constant $MAX = 100; + +#------------------------------------------------------------------------------ +BEGIN +#------------------------------------------------------------------------------ +{ + "\nChallenge 144, Task #1: Semiprime (Raku)\n".put; +} + +#============================================================================== +sub MAIN() +#============================================================================== +{ + "The semiprimes <= $MAX are:\n".put; + + my UInt @primes = (2 .. ($MAX / 2).floor).grep: { .is-prime }; + my UInt @semiprimes; + + L-OUTER: + for 0 .. @primes.end -> UInt $i + { + my UInt $prime1 = @primes[ $i ]; + + for 0 .. $i -> UInt $j + { + my UInt $prime2 = @primes[ $j ]; + my UInt $product = $prime1 * $prime2; + + next L-OUTER if $product > $MAX; + + @semiprimes.push: $product; + } + } + + @semiprimes.=sort; + + "%s\n".printf: @semiprimes.join: ', '; +} + +#------------------------------------------------------------------------------ +sub USAGE() +#------------------------------------------------------------------------------ +{ + my Str $usage = $*USAGE; + + $usage ~~ s/ ($*PROGRAM-NAME) /raku $0/; + + $usage.put; +} + +############################################################################## diff --git a/challenge-144/athanasius/raku/ch-2.raku b/challenge-144/athanasius/raku/ch-2.raku new file mode 100644 index 0000000000..2a9c6e1950 --- /dev/null +++ b/challenge-144/athanasius/raku/ch-2.raku @@ -0,0 +1,130 @@ +use v6d; + +############################################################################### +=begin comment + +Perl Weekly Challenge 144 +========================= + +TASK #2 +------- +*Ulam Sequence* + +Submitted by: Mohammad S Anwar + +You are given two positive numbers, $u and $v. + +Write a script to generate Ulam Sequence having at least 10 Ulam numbers where +$u and $v are the first 2 Ulam numbers. + +For more information about Ulam Sequence, please checkout the +[ https://en.wikipedia.org/wiki/Ulam_number |website]. + + The standard Ulam sequence (the (1, 2)-Ulam sequence) starts with U1 = 1 + and U2 = 2. Then for n > 2, Un is defined to be the smallest integer that + is the sum of two distinct earlier terms in exactly one way and larger than + all earlier terms. + +Example 1 + + Input: $u = 1, $v = 2 + Output: 1, 2, 3, 4, 6, 8, 11, 13, 16, 18 + +Example 2 + + Input: $u = 2, $v = 3 + Output: 2, 3, 5, 7, 8, 9, 13, 14, 18, 19 + +Example 3 + + Input: $u = 2, $v = 5 + Output: 2, 5, 7, 9, 11, 12, 13, 15, 19, 23 + +=end comment +############################################################################### + +#--------------------------------------# +# Copyright © 2021 PerlMonk Athanasius # +#--------------------------------------# + +#============================================================================== +=begin comment + +Algorithm +--------- +@ulams is an array containing Ulam numbers in the order of their discovery. +%sums is a hash matching each sum of two distinct Ulam numbers to a count of + the number of different ways in which that sum can be |
