diff options
| author | dcw <d.white@imperial.ac.uk> | 2022-07-19 21:36:06 +0100 |
|---|---|---|
| committer | dcw <d.white@imperial.ac.uk> | 2022-07-19 21:36:06 +0100 |
| commit | ebff3d92804951f510087c8e24d5447d611c6a59 (patch) | |
| tree | 249431366865da2c59560eb165ab72006d4f1d2d | |
| parent | cbcd936c890a9608f5c7a89322aefae1c0b2bb97 (diff) | |
| download | perlweeklychallenge-club-ebff3d92804951f510087c8e24d5447d611c6a59.tar.gz perlweeklychallenge-club-ebff3d92804951f510087c8e24d5447d611c6a59.tar.bz2 perlweeklychallenge-club-ebff3d92804951f510087c8e24d5447d611c6a59.zip | |
belatedly had a crack at challenge 173.. both probs done in Perl and C
| -rw-r--r-- | challenge-173/duncan-c-white/C/.cbuild | 3 | ||||
| -rw-r--r-- | challenge-173/duncan-c-white/C/Makefile | 14 | ||||
| -rw-r--r-- | challenge-173/duncan-c-white/C/README | 9 | ||||
| -rw-r--r-- | challenge-173/duncan-c-white/C/args.c | 174 | ||||
| -rw-r--r-- | challenge-173/duncan-c-white/C/args.h | 7 | ||||
| -rw-r--r-- | challenge-173/duncan-c-white/C/ch-1.c | 91 | ||||
| -rw-r--r-- | challenge-173/duncan-c-white/C/ch-2.c | 58 | ||||
| -rw-r--r-- | challenge-173/duncan-c-white/README | 51 | ||||
| -rwxr-xr-x | challenge-173/duncan-c-white/perl/ch-1.pl | 90 | ||||
| -rwxr-xr-x | challenge-173/duncan-c-white/perl/ch-2.pl | 59 |
10 files changed, 537 insertions, 19 deletions
diff --git a/challenge-173/duncan-c-white/C/.cbuild b/challenge-173/duncan-c-white/C/.cbuild index 7171ba4c65..fce622d376 100644 --- a/challenge-173/duncan-c-white/C/.cbuild +++ b/challenge-173/duncan-c-white/C/.cbuild @@ -1,3 +1,4 @@ -BUILD = ch-1 +BUILD = ch-1 ch-2 CFLAGS = -Wall +LDFLAGS = -lgmp #CFLAGS = -g diff --git a/challenge-173/duncan-c-white/C/Makefile b/challenge-173/duncan-c-white/C/Makefile new file mode 100644 index 0000000000..9d1b99a602 --- /dev/null +++ b/challenge-173/duncan-c-white/C/Makefile @@ -0,0 +1,14 @@ +BUILD = ch-1 ch-2 +CC = gcc +CFLAGS = -Wall -g +LDLIBS = -lm -lgmp + +all: $(BUILD) + +clean: + /bin/rm -f $(BUILD) *.o core a.out + +ch-1: ch-1.o args.o +ch-1.o: ch-1.c args.h +ch-2: ch-2.o args.o +ch-2.o: ch-2.c args.h diff --git a/challenge-173/duncan-c-white/C/README b/challenge-173/duncan-c-white/C/README new file mode 100644 index 0000000000..d860e74093 --- /dev/null +++ b/challenge-173/duncan-c-white/C/README @@ -0,0 +1,9 @@ +Thought I'd also have a go at translating ch-1.pl and ch-2.pl into C.. + +Both C versions produce identical (non-debugging) output to my Perl originals + +Both ch-1.c and ch-2.c use the command-line argument processing module +args.[ch], which I've tweaked slightly (adding a default value to +process_onenumarg()). + +ch-2.c uses libgmp, the Gnu multi-precision library, to provide bigint support. diff --git a/challenge-173/duncan-c-white/C/args.c b/challenge-173/duncan-c-white/C/args.c new file mode 100644 index 0000000000..77834b0d5b --- /dev/null +++ b/challenge-173/duncan-c-white/C/args.c @@ -0,0 +1,174 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> + + +bool debug = false; + + +// process_flag_noarg( name, argc, argv ); +// Process the -d flag, and check that there are no +// remaining arguments. +void process_flag_noarg( char *name, int argc, char **argv ) +{ + int arg=1; + if( argc>1 && strcmp( argv[arg], "-d" ) == 0 ) + { + debug = true; + arg++; + } + + int left = argc-arg; + if( left != 0 ) + { + fprintf( stderr, "Usage: %s [-d]\n", name ); + exit(1); + } +} + + +// process_onenumarg_default( name, argc, argv, defvalue, &n ); +// Process the -d flag, and check that there is a single +// remaining numeric argument (or no arguments, in which case +// we use the defvalue), putting it into n +void process_onenumarg_default( char *name, int argc, char **argv, int defvalue, int *n ) +{ + int arg=1; + if( argc>1 && strcmp( argv[arg], "-d" ) == 0 ) + { + debug = true; + arg++; + } + + int left = argc-arg; + if( left > 1 ) + { + fprintf( stderr, "Usage: %s [-d] n\n", name ); + exit(1); + } + + if( left == 0 ) + { + *n = defvalue; + return; + } + + // element is in argv[arg] + + if( debug ) + { + printf( "debug: remaining arguments are in arg=%d, " + "firstn=%s\n", arg, argv[arg] ); + } + + *n = atoi( argv[arg] ); +} + + +// process_onenumarg( name, argc, argv, &n ); +// Process the -d flag, and check that there is a single +// remaining numeric argument, putting it into n +void process_onenumarg( char *name, int argc, char **argv, int *n ) +{ + int arg=1; + if( argc>1 && strcmp( argv[arg], "-d" ) == 0 ) + { + debug = true; + arg++; + } + + int left = argc-arg; + if( left != 1 ) + { + fprintf( stderr, "Usage: %s [-d] n\n", name ); + exit(1); + } + + // element is in argv[arg] + + if( debug ) + { + printf( "debug: remaining arguments are in arg=%d, " + "firstn=%s\n", arg, argv[arg] ); + } + + *n = atoi( argv[arg] ); +} + + +// process_twonumargs( name, argc, argv, &m, &n ); +// Process the -d flag, and check that there are 2 +// remaining numeric arguments, putting them into m and n +void process_twonumargs( char *name, int argc, char **argv, int *m, int *n ) +{ + int arg=1; + if( argc>1 && strcmp( argv[arg], "-d" ) == 0 ) + { + debug = true; + arg++; + } + + int left = argc-arg; + if( left != 2 ) + { + fprintf( stderr, "Usage: %s [-d] m n\n", name ); + exit(1); + } + + // elements are in argv[arg] and argv[arg+1] + + if( debug ) + { + printf( "debug: remaining arguments are in arg=%d, " + "firstn=%s, secondn=%s\n", + arg, argv[arg], argv[arg+1] ); + } + + *m = atoi( argv[arg++] ); + *n = atoi( argv[arg] ); +} + +// int arr[100]; +// int nel = process_listnumargs( name, argc, argv, arr, 100 ); +// Process the -d flag, and check that there are >= 2 +// remaining numeric arguments, putting them into arr[0..nel-1] +// and returning nel. +int process_listnumargs( char *name, int argc, char **argv, int *arr, int maxel ) +{ + int arg=1; + if( argc>1 && strcmp( argv[arg], "-d" ) == 0 ) + { + debug = true; + arg++; + } + + int left = argc-arg; + if( left < 2 ) + { + fprintf( stderr, "Usage: %s [-d] list_of_numeric_args\n", name ); + exit(1); + } + if( left > maxel ) + { + fprintf( stderr, "%s: more than %d args\n", name, maxel ); + exit(1); + } + + // elements are in argv[arg], argv[arg+1]... + + if( debug ) + { + printf( "debug: remaining arguments are in arg=%d, " + "firstn=%s, secondn=%s..\n", + arg, argv[arg], argv[arg+1] ); + } + + int nel = 0; + for( int i=arg; i<argc; i++ ) + { + arr[nel++] = atoi( argv[i] ); + } + arr[nel] = -1; + return nel; +} diff --git a/challenge-173/duncan-c-white/C/args.h b/challenge-173/duncan-c-white/C/args.h new file mode 100644 index 0000000000..06ce79a696 --- /dev/null +++ b/challenge-173/duncan-c-white/C/args.h @@ -0,0 +1,7 @@ +extern bool debug; + +extern void process_flag_noarg( char * name, int argc, char ** argv ); +extern void process_onenumarg_default( char * name, int argc, char ** argv, int defvalue, int * n ); +extern void process_onenumarg( char * name, int argc, char ** argv, int * n ); +extern void process_twonumargs( char * name, int argc, char ** argv, int * m, int * n ); +extern int process_listnumargs( char * name, int argc, char ** argv, int * arr, int maxel ); diff --git a/challenge-173/duncan-c-white/C/ch-1.c b/challenge-173/duncan-c-white/C/ch-1.c new file mode 100644 index 0000000000..fbbf1eafab --- /dev/null +++ b/challenge-173/duncan-c-white/C/ch-1.c @@ -0,0 +1,91 @@ +/* + * Task 1 - Esthetic Number + * + * GUEST LANGUAGE: THIS IS THE C VERSION OF ch-1.pl. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +//#include <stdint.h> +#include <string.h> +#include <assert.h> + +#include "args.h" + + + +// +// bool isesth = is_esthetic( n, msgbuf, bufsize ); +// Determine whether n is esthetic, returning the +// boolean answer to the question "is it esthetic?", +// and using msgbuf (a writable string buf of size bufsize) +// to store a printable explanation of why - or why not - +// n is esthetic, in the above format. +// |5 - 4| = |4 - 5| = |5 - 6| = 1 +// or |2 - 0| != 1 +// +bool is_esthetic( int n, char *msgbuf, int bufsize ) +{ + if( n<10 ) + { + assert( bufsize>20 ); + strcpy( msgbuf, "because no single digit is" ); + return 0; + } + + // convert n to string form (for easier access to digits) + char dig[100]; + sprintf( dig, "%d", n ); + int ndig = strlen(dig); + + // look for any pair of digits not differing by 1 + for( int i=0; i<ndig-1; i++ ) + { + char a = dig[i]; + char b = dig[i+1]; + if( abs(a-b) != 1 ) + { + assert( bufsize>20 ); + sprintf( msgbuf, "|%c - %c| != 1", a, b ); + return 0; + } + } + + // ok, all pairs of digits differ by 1.. form msgbuf + strcpy( msgbuf, "" ); + int mlen = 0; + for( int i=0; i<ndig-1; i++ ) + { + char a = dig[i]; + char b = dig[i+1]; + char msg[100]; + sprintf( msg, "|%c - %c| = ", a, b ); + mlen += strlen(msg); + assert( mlen < bufsize ); + strcat( msgbuf, msg ); + } + mlen += 4; + assert( mlen < bufsize ); + strcat( msgbuf, "1" ); + return 1; +} + + +int main( int argc, char **argv ) +{ + int n; + process_onenumarg( "esthetic-number", argc, argv, &n ); + + char msg[1024]; + bool isesth = is_esthetic( n, msg, sizeof(msg) ); + if( debug ) + { + char *not = isesth ? "": " not"; + printf( "%d is%s an esthetic number as %s\n", n, not, msg ); + } else + { + puts( isesth ? "yes" : "no" ); + } + return 0; +} diff --git a/challenge-173/duncan-c-white/C/ch-2.c b/challenge-173/duncan-c-white/C/ch-2.c new file mode 100644 index 0000000000..e438720790 --- /dev/null +++ b/challenge-173/duncan-c-white/C/ch-2.c @@ -0,0 +1,58 @@ +/* + * Task 2 - Sylvester's sequence + * + * GUEST LANGUAGE: THIS IS THE C VERSION OF ch-2.pl. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <stdint.h> +#include <string.h> +#include <assert.h> +#include <unistd.h> +#include <ctype.h> + +// let's use the Gnu Multi Precision library +#include <gmp.h> + +#include "args.h" + + +int main( int argc, char **argv ) +{ + int n; + process_onenumarg_default( "sylvester-numbers", argc, argv, 10, &n ); + + // set p to 2 + mpz_t p; + mpz_init_set_str( p, "2", 10 ); + + // sigh: need "one" + mpz_t one; + mpz_init_set_str( one, "1", 10 ); + + puts( "2" ); + + mpz_t next; + mpz_init( next ); + + for( int i; i<n-1; i++ ) + { + // set next to p + 1; + mpz_add( next, p, one ); + + // print next: + char *buf; + buf = mpz_get_str( NULL, 10, next ); + puts( buf ); + free( buf ); + + // p *= next; + mpz_mul( p, p, next ); + } + mpz_clear( next ); + mpz_clear( p ); + mpz_clear( one ); + return 0; +} diff --git a/challenge-173/duncan-c-white/README b/challenge-173/duncan-c-white/README index 755694b9fc..807a2f3dfa 100644 --- a/challenge-173/duncan-c-white/README +++ b/challenge-173/duncan-c-white/README @@ -1,33 +1,48 @@ -Task 1: Abundant Number +Task 1: Esthetic Number -Write a script to generate first 20 Abundant Odd Numbers. +You are given a positive integer, $n. -According to wikipedia: A number n for which the sum of proper divisors -(divisors from 1 but less than n) s(n) > n. +Write a script to find out if the given number is Esthetic Number. -For example, 945 is the first Abundant Odd Number. +An esthetic number is a positive integer where every adjacent digit +differs from its neighbour by +-1. -Sum of divisors: -1 + 3 + 5 + 7 + 9 + 15 + 21 + 27 + 35 + 45 + 63 + 105 + 135 + 189 + 315 = 975 +For example, -MY NOTES: ok, sounds easy, and at least it's nowt to do with Primes:-) +5456 is an esthetic number as |5 - 4| = |4 - 5| = |5 - 6| = 1 +120 is not an esthetic numner as |2 - 0| != 1 + +MY NOTES: ok, sounds quite easy. Let's make it slightly harder by allowing +ourselves (in debug mode) to reproduce the examples as written.. although +note that I've cheated slighltly: I've simplified the "not" output format +above to show only the first "|a-b| != 1", because it's not quite clear +what the output should be in all cases. GUEST LANGUAGE: As a bonus, I also had a go at translating ch-1.pl into C (look in the C directory for that). -Task 2: First-class Function +Task 2: Sylvester's sequence -Create sub compose($f, $g) which takes in two parameters $f and $g as -subroutine refs and returns subroutine ref i.e. compose($f, $g)->($x) -= $f->($g->($x)) +Write a script to generate first 10 members of Sylvester's sequence. For +more informations, please refer to the wikipedia page: + https://en.wikipedia.org/wiki/Sylvester%27s_sequence -e.g. +(In summary, each term of the sequence is the product of the previous +terms, plus one. The first few terms of the sequence are 2, 3, 7, 43, 1807) -$f = (one or more parameters function) -$g = (one or more parameters function) +Output -$h = compose($f, $g) -$f->($g->($x,$y, ..)) == $h->($x, $y, ..) for any $x, $y, ... +2 +3 +7 +43 +1807 +3263443 +10650056950807 +113423713055421844361000443 +12864938683278671740537145998360961546653259485195807 +165506647324519964198468195444439180017513152706377497841851388766535868639572406808911988131737645185443 -MY NOTES: An interesting question at last. Think it's quite easy.. +MY NOTES: Also very easy, although the numbers grow ridiculously fast. +Sounds like a job for BigInt. diff --git a/challenge-173/duncan-c-white/perl/ch-1.pl b/challenge-173/duncan-c-white/perl/ch-1.pl new file mode 100755 index 0000000000..89fcf6e671 --- /dev/null +++ b/challenge-173/duncan-c-white/perl/ch-1.pl @@ -0,0 +1,90 @@ +#!/usr/bin/perl +# +# Task 1: Esthetic Number +# +# You are given a positive integer, $n. +# +# Write a script to find out if the given number is Esthetic Number. +# +# An esthetic number is a positive integer where every adjacent digit +# differs from its neighbour by +-1. +# +# For example, +# +# 5456 is an esthetic number as |5 - 4| = |4 - 5| = |5 - 6| = 1 +# 120 is not an esthetic numner as |2 - 0| != 1 +# +# MY NOTES: ok, sounds quite easy. Let's make it slightly harder by allowing +# ourselves (in debug mode) to reproduce the examples as written.. although +# note that I've cheated slighltly: I've simplified the "not" output format +# above to show only the first "|a-b| != 1", because it's not quite clear +# what the output should be in all cases. +# +# GUEST LANGUAGE: As a bonus, I also had a go at translating ch-1.pl +# into C (look in the C directory for that). +# + +use strict; +use warnings; +use feature 'say'; +use Getopt::Long; +use Data::Dumper; + + +my $debug=0; +die "Usage: esthetic-number [--debug] N\n" + unless GetOptions( "debug"=>\$debug ) && @ARGV==1; +my $n = shift; + +# +# my( $isesth, $mesg ) = is_esthetic( $n ); +# Determine whether $n is esthetic, returning a pair +# ($isesth, $mesg). $isesth is the boolean answer to the +# question "is it esthetic?", and $mesg is a printable +# explanation of why - or why not - in the above format. +# |5 - 4| = |4 - 5| = |5 - 6| = 1 +# or |2 - 0| != 1 +# +sub is_esthetic +{ + my( $n ) = @_; + + return (0, "because no single digit is") if $n<10; + + # let's form a list of [prevdig, nextdig, diff] triples + my @dig = split( //, $n ); + my @trips = map { + my $a = $dig[$_]; + my $b = $dig[$_+1]; + [ $a, $b, abs($a-$b) ] + } 0..$#dig-1; + + #die Dumper \@trips; + my @not1 = grep { $trips[$_][2] != 1 } 0..$#trips; + #die Dumper \@not1; + + if( @not1 ) + { + my $not = $trips[shift @not1]; + my( $a, $b, $diff ) = @$not; + return ( 0, "|$a - $b| != 1" ); + } + + my $mesg = join( " = ", map { + my $not = $trips[$_]; + my( $a, $b, $diff ) = @$not; + "|$a - $b|" + } 0..$#trips ) . " = 1"; + return ( 1, $mesg ); +} + + +my( $isesth, $mesg ) = is_esthetic( $n ); +if( $debug ) +{ + my $not = $isesth ? "": " not"; + say "$n is$not an esthetic number as $mesg"; +} else +{ + say $isesth ? "yes" : "no"; +} diff --git a/challenge-173/duncan-c-white/perl/ch-2.pl b/challenge-173/duncan-c-white/perl/ch-2.pl new file mode 100755 index 0000000000..6e2decd61f --- /dev/null +++ b/challenge-173/duncan-c-white/perl/ch-2.pl @@ -0,0 +1,59 @@ +#!/usr/bin/perl +# +# Task 2: Sylvester's sequence +# +# Write a script to generate first 10 members of Sylvester's sequence. For +# more informations, please refer to the wikipedia page: +# https://en.wikipedia.org/wiki/Sylvester%27s_sequence +# +# (In summary, each term of the sequence is the product of the previous +# terms, plus one. The first few terms of the sequence are 2, 3, 7, 43, 1807) +# +# Output +# +# 2 +# 3 +# 7 +# 43 +# 1807 +# 3263443 +# 10650056950807 +# 113423713055421844361000443 +# 12864938683278671740537145998360961546653259485195807 +# 165506647324519964198468195444439180017513152706377497841851388766535868639572406808911988131737645185443 +# +# MY NOTES: Also very easy, although the numbers grow ridiculously fast. +# Sounds like a job for BigInt. +# +# You are given an array of integers. Write a script to compute the +# five-number summary of the given set of integers. +# You can find the definition and example in the wikipedia page: +# https://en.wikipedia.org/wiki/Five-number_summary +# +# MY NOTES: Nice and simple: sort the data, pick the median, first and third +# quartile values. Note that the median can be the average (mean) of the +# two central values if the #values is even. +# + +use strict; +use warnings; +use feature 'say'; +use Getopt::Long; +use Data::Dumper; +use bigint; + +my $debug=0; +die "Usage: sylvester-numbers [--debug] N (default 10)\n" + unless GetOptions( "debug"=>\$debug ) && @ARGV<2; + +my $n = shift // 10; + +my $p = 2; +say $p; + +foreach my $i (1..$n-1) +{ + my $next = $p + 1; + say $next; + $p *= $next; +} |
