diff options
| author | drbaggy <js5@sanger.ac.uk> | 2022-05-30 10:35:19 +0100 |
|---|---|---|
| committer | drbaggy <js5@sanger.ac.uk> | 2022-05-30 10:35:19 +0100 |
| commit | ea71c8374b0ccd812cfe3412cf1e6415299764bf (patch) | |
| tree | 59b4bd4274d1db6ff27a8e45e2b281623ba928a7 | |
| parent | 09aa417f411a4bad93f0dbd10a3d8a2b1b3af261 (diff) | |
| download | perlweeklychallenge-club-ea71c8374b0ccd812cfe3412cf1e6415299764bf.tar.gz perlweeklychallenge-club-ea71c8374b0ccd812cfe3412cf1e6415299764bf.tar.bz2 perlweeklychallenge-club-ea71c8374b0ccd812cfe3412cf1e6415299764bf.zip | |
added link to blog - empty blog with code and fix to ch-2
| -rw-r--r-- | challenge-167/james-smith/README.md | 320 | ||||
| -rw-r--r-- | challenge-167/james-smith/blog.txt | 1 | ||||
| -rw-r--r-- | challenge-167/james-smith/perl/ch-2.pl | 2 |
3 files changed, 25 insertions, 298 deletions
diff --git a/challenge-167/james-smith/README.md b/challenge-167/james-smith/README.md index 4cc3055242..b66598bc2f 100644 --- a/challenge-167/james-smith/README.md +++ b/challenge-167/james-smith/README.md @@ -1,7 +1,7 @@ -[< Previous 165](https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-165/james-smith) | -[Next 167 >](https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-167/james-smith) +[< Previous 166](https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-166/james-smith) | +[Next 168 >](https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-168/james-smith) -# The Weekly Challenge 166 +# The Weekly Challenge 167 You can find more information about this weeks, and previous weeks challenges at: @@ -13,312 +13,38 @@ submit solutions in whichever language you feel comfortable with. You can find the solutions here on github at: -https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-166/james-smith +https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-167/james-smith -# Challenge 1 - Hex words.... +# Challenge 1 - Circular Prime -Now I've concentrated on challenge 2 this week but here is some of my code for Challenge 1 +***Write a script to find out first 10 circular primes having at least 3 digits (base 10). A circular prime is a prime number with the property that the number generated at each intermediate step when cyclically permuting its (base 10) digits will also be prime.*** ## Solution -Find all hex words, this generates all words, with options for adding filters - to -restrict the number of numbers - to only letters or all letters. By commenting/uncommenting -the filter lines.... I have added one more mapping that is in standard use which is -`g` -> `9` {others use `6` but it still works} ```perl -while(<>) { - chomp; - next unless m{^[abcdefoilstg]+$}; - my $t = $_; - my $N = tr/oilstg/011579/; - next if $N < length $_; - #next if $N > 0; - #next if $N > 15; - warn "$N\t$t\t$_\n" if $N == length $_; - $words->[length $_]{$N}{$t}="$_ (".hex($_).")"; +my($p,$N,@res) = (99,10); +O: while( @res < $N ) { + next O if ($p = next_prime $p)=~/[024568]/; + my @q = split//, $p; + push @res, $p unless + ( grep { $p>$_ } @q = map { push @q, shift @q; join '',@q } 2..@q ) + || grep { !is_prime( $_ ) } @q; } - -print Dumper( $words ); -``` - -## Some observations - -### Longest words -``` - falsifiabilities 0x fa15 1f1a b111 71e5 (18,020,343,683,493,229,029) - dissociabilities 0x d155 0c1a b111 71e5 (15,083,975,835,726,737,893) - lactobacillaceae 0x 1ac7 0bac 111a ceae ( 1,929,523,799,000,796,846) -``` -Can add (if we include the g->9 mapping): -``` - silicoflagellate 0x 5111 c0f1 a9e1 1a7e ( 5,841,662,335,845,997,182) -``` -### Longest word with at most `n` numbers: - -**0-numbers** - 8 letters -``` - fabaceae 0x 0000 0000 faba ceae ( 4,206,546,606) -``` -**1-number** - 10 lettters -``` - defaceable 0x 0000 00de face ab1e ( 957,690,587,934) - defaecated 0x 0000 00de faec a7ed ( 957,692,553,197) - effaceable 0x 0000 00ef face ab1e ( 1,030,705,031,966) -``` -**2-numbers/3-numbers** - 12 letters -``` - fiddledeedee 0x 0000 f1dd 1ede edee ( 265,932,007,992,814) -``` -**4-numbers** - 12 letters -``` - fiddledeedee 0x 0000 f1dd 1ede edee ( 265,932,007,992,814) - acetoacetate 0x 0000 ace7 0ace 7a7e ( 190,108,318,726,782) - cicadellidae 0x 0000 c1ca de11 1dae ( 213,077,053,218,222) -``` -**5-numbers** - 13 letters -``` - blastodiaceae 0x 000b 1a57 0d1a ceae ( 3,125,185,928,154,798) -``` -**6-numbers -- 9-numbers** - 16 letters -``` - lactobacillaceae 0x 1ac7 0bac 111a ceae ( 1,929,523,799,000,796,846) -``` -**10-numbers** - 16 letters -``` - lactobacillaceae 0x 1ac7 0bac 111a ceae ( 1,929,523,799,000,796,846) - falsifiabilities 0x fa15 1f1a b111 71e5 (18,020,343,683,493,229,029) -``` -Can add (if we include the g->9 mapping {could also do g->6}): +say for @res; ``` - silicoflagellate 0x 5111 c0f1 a9e1 1a7e ( 5,841,662,335,845,997,182) -``` -**11+-numbers** - 16 letters -``` - lactobacillaceae 0x 1ac7 0bac 111a ceae ( 1,929,523,799,000,796,846) - falsifiabilities 0x fa15 1f1a b111 71e5 (18,020,343,683,493,229,029) - dissociabilities 0x d155 0c1a b111 71e5 (15,083,975,835,726,737,893) -``` -Can add (if we include the g->9 mapping {could also do g->6}): -``` - silicoflagellate 0x 5111 c0f1 a9e1 1a7e ( 5,841,662,335,845,997,182) -``` - -### Longest word with all numbers: -``` - soloists 0x 0000 0000 5010 1575 ( 1,343,231,349) - titlists 0x 0000 0000 7171 1575 ( 1,903,236,469) -``` -If we include the g->9 mapping we can have: -``` - glossologists 0x 0000 91055 0109 1575 ( 2,551,232,066,033,013) -``` - -# Challenge 2 - k-diff - -## The solution -I approached this in a few different ways: +# Challenge 2 - Gamma function -### Getting the filenames... +***Implement subroutine gamma() using the Lanczos approximation method.*** -We can: - 1) Cheat - and create a hash of arrays; - 2) Use `opendir`/`readdir`/`closedir`; - 3) Use `blob '*/*'`; - 4) Use `<*/*>`. - -Each have advantages/disadvantages: - - * the first doesn't require us to create files on disk for testing; - * 2 allows you to find hidden file names but then you have to be careful with `.` & `..`. You have to join directory and filename to get the path - * 3 & 4 are essentially the same and get all "folders/entries". You have to split the path to get the directory and filename. - -The simplest approach is to use 3/4. - -### Finding a complete list of different filenames - -We collect a unique list of filenames, by putting them as the keys of a hash. We -could do this with a map - but it is useful to keep track of the number of times -we see each file. - -```perl - my( %directories, %filenames ); - for( sort <*/*> ) { - my( $dir, $file ) = split m{/}, $_; - $directories{$dir}=1; - $file.='/' if -d $_; - $filenames{ $file }{ $dir } = 1; - } - my @paths = sort keys %directories; -``` - -### Compute the length of the longest directory or filename - -For the output we will want to pretty print it - and so need to work out the width -of the columns - this is a simple loop over the directories and filenames. -```perl - my $length = 0; - for ( @paths, keys %filenames ) { - $length = length $_ if length $_ > $length; - } -``` -### Build templates for printing page horizontal line, sprintf table of heading/contents - -We draw the horizontal line three times, so it is useful to keep a copy of it, we -in the code also need a template to sprintf the header and the body of the table. -So we generate these now. We use the length we computed above to compute the runs of -characters needed. - -```perl - my $HORIZONTAL_LINE = join '-' x ( $length+2 ), ('+') x (1+@paths); - my $TEMPLATE = '|' . " %-${length}s |" x @paths; - - say $HORIZONTAL_LINE; - say sprintf $TEMPLATE, @paths; - say $HORIZONTAL_LINE; -``` - -### Workout what to print and printing - -This loops through the unique filenames we stored earlier. Then -for each filename we first check that it is present in all lists. -If it is we remove it and go onto the next filename. As we kept -counts of each filename this is as easy as checking that the -count is the same as the number of directories - this is the -first if in the loop. - -We then loop through each column - if the filename is present -we display it o/w we display a blank string. - -```perl - for my $filename ( sort keys %filenames ) { - next if @paths == keys %{$filenames{$filename}}; - my @columns; - for (@paths) { - if( exists $filenames{$filename}{$_} ) { - push @columns, $filename; - } else { - push @columns, ''; - } - } - say sprintf $TEMPLATE, @columns; - } -``` - -### Add the last line... - -We print the bottom of the table: - -```perl -say $1; -``` - -## The full code (with comments) +## Solution ```perl -sub k_diff { - ## my($l,%d,%u)=0; - my( $length, %directories, %filenames )=0; - - ## /\//,$u{$'.'/'x-d}{$d{$`}=$`}++for<*/*> - for( sort <*/*> ) { - my( $dir, $file ) = split m{/}, $_; - $directories{$dir}=1; - $file.='/' if -d $_; - $filenames{ $file }{ $dir } = 1; - } - - ## $l<length?$l=length:1for(my@p=sort keys%d),@_=keys%u - my @paths = sort keys %directories; - for ( @paths, keys %filenames ) { - $length = length $_ if length $_ > $length; - } - - ## say$a=join('-'x$l,('+--')x@p,"+\n"),sprintf($b="| %-${l}s "x@p."|\n",@p),$a, - my $HORIZONTAL_LINE = join '-' x ( $length+2 ), ('+') x (1+@paths); - my $TEMPLATE = '|' . " %-${length}s |" x @paths; - say $HORIZONTAL_LINE; - say sprintf $TEMPLATE, @paths; - say $HORIZONTAL_LINE; - - ## map({//;@p-%{$u{$'}}?sprintf$b,map{$u{$'}{$_}?$':''}@p:()}sort@_) - for my $filename ( sort keys %filenames ) { - next if @paths == keys %{$filenames{$filename}}; - my @columns; - for (@paths) { - if( exists $filenames{$filename}{$_} ) { - push @columns, $filename; - } else { - push @columns, ''; - } - } - say sprintf $TEMPLATE, @columns; - } - - ## $a - say $HORIZONTAL_LINE; +sub gamma { + my($i,$x,$z)=(0,$X,$_[0]); + return ($z<=0 && abs($z-int$z)<$EP) ? 'inf' + : $z < 0.5 ? $PI / sin($PI*$z) * gamma( 1-$z ) + : (map({$x+=$_/($z+$i++)}@PV),abs(($i=$RP*($i=$z+@PV-1.5)**($z-0.5)*exp(-$i)*$x)-int$i)<$EP?int$i:$i)[-1] + ; } ``` -## Obfurscated/Golf code... - -I started with a "simple" compact version of the code and then came -discussions with Eliza on the Perl Programmers Facebook group and things -slowly got smaller. A few bytes at a time to the 259 bytes: - -```perl -sub z{my($l,%d,%u)=0;/\//,$u{$'.'/'x-d}{$d{$`}=$`}++for<*/*>;$l<length?$l=length -:1for(my@p=sort keys%d),@_=keys%u;say$a=join('-'x$l,('+--')x@p,"+\n"),sprintf($b -="| %-${l}s "x@p."|\n",@p),$a,map({//;@p-%{$u{$'}}?sprintf$b,map{$u{$'}{$_}?$': -''}@p:()}sort@_),$a} -``` - -**or** if we "allow" return characters inside strings - this is 257 bytes of -perly goodness... - -```perl -sub z{my($l,%d,%u)=0;/\//,$u{$'.'/'x-d}{$d{$`}=$`}++for<*/*>;$l<length?$l=length -:1for(my@p=sort keys%d),@_=keys%u;say$a=join('-'x$l,('+--')x@p,'+ -'),sprintf($b="| %-${l}s "x@p.'| -',@p),$a,map({//;@p-%{$u{$'}}?sprintf$b,map{$u{$'}{$_}?$':''}@p:()}sort@_),$a} -``` - -**Notes** - - We replace many of the loops and conditionals with `map`s and `_?_:_` - - Where we use `$_` there are numerous function calls which use this when no - parameter is passed - in this case `length`, `split`, `-d`. - - When a "string" starts with a number than has a letter in it treats it as if - to add a space between the number and the rest of the string so we can rewrite - `1 for @array` as `1for@array`. - - we don't need to do `sort blob '*/*'` or `sort <*/*>` as for all "current" - versions of Perl we can assume that perl does this for us. - - Rather than using `split /\//`, we use the match operator `/\//` in one place - and `//` in another to split - the first half goes in `$`` and the second half - in `$'`. - - When using `//` this just copies `$_` into `$'`. - - if you subtract a hash in scalar context then it subtracts the numbers of keys. - Sp we can compute the number ot times a file is missing by doing `@p-%u`. -## Coda - taking the brakes off... - -For ultimate compactness we can remove the function overhead off, turn off both -`strict` and `warnings`. We can reduce this to either 233 bytes (or 231 bytes) - -```perl -/\//,$u{$'.'/'x-d}{$d{$`}=$`}++for<*/*>;$l<length?$l=length:1for(@p=sort keys%d),@_=keys%u;print$a=join('-'x$l,('+--')x@p,'+ -'),sprintf($b="| %-${l}s "x@p.'| -',@p),$a,map({//;@p-%{$u{$'}}?sprintf$b,map{$' x$u{$'}{$_}}@p:()}sort@_),$a -``` -This is the 233 byte version - we could reduce it to 231 bytes by replacing -`print` with `say` again... But ultimately that makes the execution more bytes. - -Command line with `print`: - -```perl -perl ch-2-ns.pl -``` - -Command line with `say` - -```perl -perl -M5.10.0 ch-2-ns.pl -``` -So to save 2 bytes we use 9 more to run the command... of course you could just run it as a 1-liner on the command line (with the -E) but that would just be silly! diff --git a/challenge-167/james-smith/blog.txt b/challenge-167/james-smith/blog.txt new file mode 100644 index 0000000000..68298febed --- /dev/null +++ b/challenge-167/james-smith/blog.txt @@ -0,0 +1 @@ +https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-167/james-smith diff --git a/challenge-167/james-smith/perl/ch-2.pl b/challenge-167/james-smith/perl/ch-2.pl index fd31b54b0d..db98fd1956 100644 --- a/challenge-167/james-smith/perl/ch-2.pl +++ b/challenge-167/james-smith/perl/ch-2.pl @@ -21,7 +21,7 @@ sub gamma { my($i,$x,$z)=(0,$X,$_[0]); return ($z<=0 && abs($z-int$z)<$EP) ? 'inf' : $z < 0.5 ? $PI / sin($PI*$z) * gamma( 1-$z ) - : [map({$x+=$_/($z+$i++)}@PV),abs(($i=$RP*($i=$z+@PV-1.5)**($z-0.5)*exp(-$i)*$x)-int$i)<$EP?int$i:$i]->[-1] + : (map({$x+=$_/($z+$i++)}@PV),abs(($i=$RP*($i=$z+@PV-1.5)**($z-0.5)*exp(-$i)*$x)-int$i)<$EP?int$i:$i)[-1] ; } |
