aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordcw <d.white@imperial.ac.uk>2022-07-19 21:36:06 +0100
committerdcw <d.white@imperial.ac.uk>2022-07-19 21:36:06 +0100
commitebff3d92804951f510087c8e24d5447d611c6a59 (patch)
tree249431366865da2c59560eb165ab72006d4f1d2d
parentcbcd936c890a9608f5c7a89322aefae1c0b2bb97 (diff)
downloadperlweeklychallenge-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/.cbuild3
-rw-r--r--challenge-173/duncan-c-white/C/Makefile14
-rw-r--r--challenge-173/duncan-c-white/C/README9
-rw-r--r--challenge-173/duncan-c-white/C/args.c174
-rw-r--r--challenge-173/duncan-c-white/C/args.h7
-rw-r--r--challenge-173/duncan-c-white/C/ch-1.c91
-rw-r--r--challenge-173/duncan-c-white/C/ch-2.c58
-rw-r--r--challenge-173/duncan-c-white/README51
-rwxr-xr-xchallenge-173/duncan-c-white/perl/ch-1.pl90
-rwxr-xr-xchallenge-173/duncan-c-white/perl/ch-2.pl59
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;
+}