aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohammad S Anwar <mohammad.anwar@yahoo.com>2022-11-21 04:33:55 +0000
committerMohammad S Anwar <mohammad.anwar@yahoo.com>2022-11-21 04:33:55 +0000
commitbdccbbe2cc6e55ddf50528a3af57450dd1f2aeef (patch)
tree0413c1787c5ee053410ca42037a6ce95940f5585
parent772c91d3484224c25a3be7da7c8affe592707f39 (diff)
parent01c3a8edf4660d2356c6d353b56e493fa3a31c03 (diff)
downloadperlweeklychallenge-club-bdccbbe2cc6e55ddf50528a3af57450dd1f2aeef.tar.gz
perlweeklychallenge-club-bdccbbe2cc6e55ddf50528a3af57450dd1f2aeef.tar.bz2
perlweeklychallenge-club-bdccbbe2cc6e55ddf50528a3af57450dd1f2aeef.zip
Merge branch 'master' of https://github.com/manwar/perlweeklychallenge-club
-rw-r--r--challenge-190/duncan-c-white/README2
-rw-r--r--challenge-190/duncan-c-white/pascal/Makefile12
-rw-r--r--challenge-190/duncan-c-white/pascal/ch-1.pas158
-rw-r--r--challenge-190/duncan-c-white/pascal/ch-2.c133
-rw-r--r--challenge-190/duncan-c-white/pascal/ch-2.pas239
-rw-r--r--challenge-191/duncan-c-white/C/Makefile19
-rw-r--r--challenge-191/duncan-c-white/C/README10
-rw-r--r--challenge-191/duncan-c-white/C/args.c207
-rw-r--r--challenge-191/duncan-c-white/C/args.h11
-rw-r--r--challenge-191/duncan-c-white/C/ch-1.c66
-rw-r--r--challenge-191/duncan-c-white/C/ch-2.c90
-rw-r--r--challenge-191/duncan-c-white/C/nextintperm.c63
-rw-r--r--challenge-191/duncan-c-white/C/nextintperm.h1
-rw-r--r--challenge-191/duncan-c-white/C/parseints.c114
-rw-r--r--challenge-191/duncan-c-white/C/parseints.h1
-rw-r--r--challenge-191/duncan-c-white/C/printarray.c39
-rw-r--r--challenge-191/duncan-c-white/C/printarray.h1
-rw-r--r--challenge-191/duncan-c-white/README106
-rwxr-xr-xchallenge-191/duncan-c-white/perl/ch-1.pl78
-rwxr-xr-xchallenge-191/duncan-c-white/perl/ch-2.pl134
20 files changed, 1439 insertions, 45 deletions
diff --git a/challenge-190/duncan-c-white/README b/challenge-190/duncan-c-white/README
index 9edc65e930..113911c007 100644
--- a/challenge-190/duncan-c-white/README
+++ b/challenge-190/duncan-c-white/README
@@ -29,6 +29,8 @@ MY NOTES: very easy.
GUEST LANGUAGE: As a bonus, I also had a go at translating ch-1.pl
into C (look in the C directory for the translation)
+After the deadline, I added a Pascal version of ch-1.pl (look in the
+pascal directory for that).
Task 2: Decoded List
diff --git a/challenge-190/duncan-c-white/pascal/Makefile b/challenge-190/duncan-c-white/pascal/Makefile
new file mode 100644
index 0000000000..ad308de958
--- /dev/null
+++ b/challenge-190/duncan-c-white/pascal/Makefile
@@ -0,0 +1,12 @@
+BUILD = ch-1 #ch-2
+
+all: $(BUILD)
+
+clean:
+ /bin/rm -f $(BUILD) *.o core a.out
+
+ch-1: ch-1.pas
+ fpc ch-1.pas
+
+ch-2: ch-2.pas
+ fpc ch-2.pas
diff --git a/challenge-190/duncan-c-white/pascal/ch-1.pas b/challenge-190/duncan-c-white/pascal/ch-1.pas
new file mode 100644
index 0000000000..e6eb830bb6
--- /dev/null
+++ b/challenge-190/duncan-c-white/pascal/ch-1.pas
@@ -0,0 +1,158 @@
+(*
+ * Task 1: Capital Detection
+ *
+ * GUEST LANGUAGE: THIS IS THE PASCAL VERSION OF ch-1.pl, suitable for
+ * the Free Pascal compiler.
+ *)
+
+uses sysutils;
+
+type strarray = array [0..100] of string;
+
+var debug : boolean;
+
+
+(* process_args_exactly_n( n, str[] );
+ * Process command line arguments,
+ * specifically process the -d flag,
+ * check that there are exactly n remaining arguments,
+ * copy remaining args to str[n], a string array
+ *)
+procedure process_args_exactly_n( n : integer; var str : strarray );
+
+(* note: paramStr(i)); for i in 1 to paramCount() *)
+
+var
+ nparams : integer;
+ nel : integer;
+ arg : integer;
+ i : integer;
+ p : string;
+
+begin
+ nparams := paramCount();
+
+ arg := 1;
+ if (nparams>0) and SameText( paramStr(arg), '-d' ) then
+ begin
+ debug := true;
+ arg := 2;
+ end;
+
+ nel := 1+nparams-arg;
+ if nel <> n then
+ begin
+ writeln( stderr,
+ 'Usage: cap-det [-d] string' );
+ halt;
+ end;
+
+
+ // elements are in argv[arg..nparams], copy them to str[]
+
+ for i := arg to nparams do
+ begin
+ p := paramStr(i);
+ str[i-arg] := p;
+ end;
+end;
+
+
+const
+ Upper = ['A'..'Z'];
+ Lower = ['a'..'z'];
+
+
+function capdetect( str : string ) : boolean;
+var
+ alllower, allupper : boolean;
+ len, i : integer;
+begin
+ len := length(str);
+ if debug then
+ begin
+ writeln( 'debug: capdetect(', str, '): entry, str1=', str[1] );
+ end;
+ if str[1] in Upper then
+ begin
+ if debug then
+ begin
+ writeln( 'debug: capdetect(', str, '): starts with upper' );
+ end;
+ alllower := true;
+ allupper := true;
+ for i := 2 to len do
+ begin
+ if not( str[i] in Lower) then
+ begin
+ if debug then
+ begin
+ writeln( 'debug: capdetect(', str, '): found ', str[i], ' not lower case' );
+ end;
+ alllower := false;
+ end;
+ if not( str[i] in Upper) then
+ begin
+ if debug then
+ begin
+ writeln( 'debug: capdetect(', str, '): found ', str[i], ' not upper case' );
+ end;
+ allupper := false;
+ end;
+ end;
+ if alllower or allupper then exit( true );
+ end else if str[1] in Lower then
+ begin
+ if debug then
+ begin
+ writeln( 'debug: capdetect(', str, '): starts with lower' );
+ end;
+ alllower := true;
+ for i := 2 to len do
+ begin
+ if not( str[i] in Lower) then
+ begin
+ writeln( 'debug: capdetect(', str, '): found ', str[i], ' not lower case' );
+ alllower := false;
+ end;
+ end;
+ if alllower then exit( true );
+ end;
+ exit( false );
+end;
+
+
+procedure main;
+
+var
+ strarr : strarray;
+ str : string;
+ ok : boolean;
+
+begin
+ debug := false;
+
+ process_args_exactly_n( 1, strarr );
+ str := strarr[0];
+
+ if debug
+ then begin
+ writeln( 'debug: str=', str );
+ end;
+
+ ok := capdetect( str );
+
+ if ok then
+ begin
+ writeln( 1 );
+ end else
+ begin
+ writeln( 0 );
+ end;
+
+end;
+
+
+begin
+ main;
+end.
diff --git a/challenge-190/duncan-c-white/pascal/ch-2.c b/challenge-190/duncan-c-white/pascal/ch-2.c
new file mode 100644
index 0000000000..daca37a01d
--- /dev/null
+++ b/challenge-190/duncan-c-white/pascal/ch-2.c
@@ -0,0 +1,133 @@
+//
+// Task 2: Decoded List
+//
+// C version.
+//
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "args.h"
+
+
+typedef char bigstr[1024];
+
+
+char enc[27]; // element 0 not used
+
+
+//
+// decode_all( str, prefix, results[], &nr );
+// Decode str, taking 1 or 2 digits off the front (as long
+// as the number that results is between 1..26), producing
+// all the possible decodings (adding prefix to each decoding
+// that we produce)
+//
+void decode_all( char *str, char *prefix, bigstr *results, int *nr )
+{
+ if( *str == '\0' )
+ {
+ int i = (*nr);
+ strcpy( results[i], prefix );
+ if( debug )
+ {
+ printf( "found solution %d = %s\n", i, prefix );
+ }
+ (*nr)++;
+ return;
+ }
+
+ // try taking off the first char..
+ char first = *str;
+ char *rem = str+1;
+ if( debug )
+ {
+ printf( "debug: first=%c, rem=%s\n", first, rem );
+ }
+ if( strcmp(rem,"0") != 0 && first != '0')
+ {
+ bigstr p2;
+ strcpy( p2, prefix );
+ char *p = p2+strlen(p2);
+ *p++ = enc[first-'0'];
+ *p++ = '\0';
+ if( debug )
+ {
+ printf( "debug: recurse with rem=%s, first=%c, prefix=%s\n",
+ rem, first, p2 );
+ }
+ decode_all( rem, p2, results, nr );
+ }
+
+ if( strlen(str) > 1 )
+ {
+ // try taking off the first two chars..
+ int first = (*str-'0')*10 + (str[1]-'0');
+ char *rem = str+2;
+ if( debug )
+ {
+ printf( "debug: first=%d, rem=%s\n", first, rem );
+ }
+
+ if( strcmp(rem,"0") != 0 && first <= 26 )
+ {
+ bigstr p2;
+ strcpy( p2, prefix );
+ char *p = p2+strlen(p2);
+ *p++ = enc[first];
+ *p++ = '\0';
+ if( debug )
+ {
+ printf( "debug: recurse with rem=%s, first=%d, prefix=%s\n",
+ rem, first, p2 );
+ }
+ decode_all( rem, p2, results, nr );
+ }
+ }
+}
+
+
+int main( int argc, char **argv )
+{
+ int argno = process_flag_n_args( "decoded-list", argc, argv,
+ 1, "encoded string" );
+
+ char *str = argv[argno++];
+
+ if( debug )
+ {
+ printf( "debug: str=%s\n", str );
+ }
+
+ for( char ch='A'; ch<='Z'; ch++ )
+ {
+ enc[ch-'@'] = ch;
+ if( debug )
+ {
+ printf( "debug: enc[%d] = %c\n", ch-'@', ch );
+ }
+ }
+
+
+ bigstr results[1024];
+ int nr = 0;
+ decode_all( str, "", results, &nr );
+
+ bool first = true;
+ for( int i=0; i<nr; i++ )
+ {
+ if( ! first )
+ {
+ fputs( ", ", stdout );
+ }
+ printf( "%s", results[i] );
+ first = false;
+ }
+ putchar( '\n' );
+
+ return 0;
+}
diff --git a/challenge-190/duncan-c-white/pascal/ch-2.pas b/challenge-190/duncan-c-white/pascal/ch-2.pas
new file mode 100644
index 0000000000..019580cb94
--- /dev/null
+++ b/challenge-190/duncan-c-white/pascal/ch-2.pas
@@ -0,0 +1,239 @@
+(*
+ * TASK #2 - Array Degree
+ *
+ * GUEST LANGUAGE: THIS IS THE Pascal VERSION OF ch-2.{c,pl},
+ * suitable for the Free Pascal compiler.
+ *)
+
+uses sysutils;
+
+const maxints = 256;
+
+type intarray = array [0..maxints-1] of integer;
+
+var debug : boolean;
+
+
+type
+ pair = record
+ el : integer; (* an element *)
+ freq : integer; (* and it's associated frequency *)
+ end;
+
+type
+ pairarray = array [ 1..1000 ] of pair;
+
+
+(* process_args( nel, v );
+ * Process command line arguments,
+ * specifically process the -d flag,
+ * set nel to the number of remaining arguments,
+ * check that all those remaining arguments are +ve numbers,
+ * copy remaining args to a new integer array v.
+ *)
+procedure process_args( var nel : integer; var v : intarray );
+
+(* note: paramStr(i)); for i in 1 to paramCount() *)
+
+var
+ nparams : integer;
+ arg : integer;
+ i : integer;
+ p : string;
+
+begin
+ nparams := paramCount();
+
+ arg := 1;
+ if (nparams>0) and SameText( paramStr(arg), '-d' ) then
+ begin
+ debug := true;
+ arg := 2;
+ end;
+
+ nel := 1+nparams-arg;
+ if nel < 2 then
+ begin
+ writeln( stderr,
+ 'Usage: summations [-d] list of +ve numbers' );
+ halt;
+ end;
+
+ if nel > maxints then
+ begin
+ writeln( stderr,
+ 'summations too many numbers (max ',
+ maxints, ')' );
+ halt;
+ end;
+
+ if debug then
+ begin
+ writeln( 'debug: arg', arg, ', nparams=', nparams, ', nel=',
+ nel );
+ end;
+
+ // elements are in argv[arg..nparams], copy them to v[]
+
+ // check that all remaining arguments are +ve integers,
+ // and then copy them to v[]
+ for i := arg to nparams do
+ begin
+ p := paramStr(i);
+ if (p[1] < '0') or (p[1] > '9') then
+ begin
+ writeln( stderr,
+ 'summations arg ', i,
+ ' (', p, ') is not a +ve number' );
+ halt;
+ end;
+ v[i-arg] := StrToInt( p );
+ end;
+end;
+
+
+(*
+ * rement the frequency of el in freq (adding an element if
+ * it's not there yet)
+ *)
+procedure incfreq( var freq : pairarray; var np : integer; el : integer );
+
+var
+ i : integer;
+ over : boolean;
+
+begin
+ over := false;
+ for i:=0 to np-1 do
+ begin
+ if not over and (freq[i].el = el)
+ then begin
+ inc( freq[i].freq );
+ over := true;
+ end;
+ end;
+ if not over then
+ begin;
+ freq[np].el := el;
+ freq[np].freq := 1;
+ inc( np );
+ end;
+end;
+
+
+
+(*
+ * int deg = degree( arr, f, t );
+ * Calculate the degree (max frequency) of array[f..t].
+ *)
+function degree( arr : intarray; f, t : integer ) : integer;
+
+var
+ i, max : integer;
+ np : integer; (* number of pairs in freq *)
+ freq : pairarray;
+
+begin
+ np := 0;
+
+ for i:=f to t
+ do begin
+ incfreq( freq, np, arr[i] );
+ end;
+
+ (* now find the maximum frequency in freq[] *)
+ max := 0;
+ for i:=0 to np-1
+ do begin
+ if freq[i].freq > max
+ then begin
+ max := freq[i].freq;
+ end;
+ end;
+ degree := max;
+end;
+
+
+(*
+ * makeslicestr( arr, f, t, slicestr );
+ * Build slicestr, a plain text string containing all elements
+ * arr[f..t], comma separated
+ * Sort of like slicestr = join(',', arr[f..t]);
+ *)
+procedure makeslicestr( arr : intarray; f, t : integer; var slicestr : ansistring );
+
+var
+ i : integer;
+
+begin
+ slicestr := '';
+ for i:=f to t
+ do begin
+ if i>f
+ then begin
+ AppendStr( slicestr, ',' );
+ end;
+ AppendStr( slicestr, IntToStr( arr[i] ) );
+ end;
+end;
+
+
+procedure main;
+
+var
+ nel : integer;
+ ilist : intarray;
+ wholedeg : integer;
+ slicestr : ansistring;
+ smallarray : ansistring;
+ smallestarraysize : integer;
+ f, t : integer;
+ deg, size : integer;
+
+begin
+ debug := false;
+
+ process_args( nel, ilist );
+
+ wholedeg := degree( ilist, 0, nel-1 );
+
+ makeslicestr( ilist, 0, nel-1, slicestr );
+
+ if debug then
+ begin
+ writeln( 'debug: wholedeg = ', wholedeg );
+ end;
+
+ smallestarraysize := nel+1;
+
+ for f:=0 to nel-2 do
+ begin
+ for t:=f+1 to nel-1 do
+ begin
+ deg := degree( ilist, f, t );
+ if deg = wholedeg then
+ begin
+ makeslicestr( ilist, f, t, slicestr );
+ if debug then
+ begin
+ writeln( 'debug: found sub-array ',
+ slicestr, ' with degree ', deg );
+ end;
+
+ size := t+1-f;
+ if size < smallestarraysize then
+ begin
+ smallestarraysize := size;
+ smallarray := slicestr;
+ end;
+ end;
+ end;
+ end;
+
+ writeln( smallarray );
+end;
+
+
+begin
+ main;
+end.
diff --git a/challenge-191/duncan-c-white/C/Makefile b/challenge-191/duncan-c-white/C/Makefile
new file mode 100644
index 0000000000..4deb8e047f
--- /dev/null
+++ b/challenge-191/duncan-c-white/C/Makefile
@@ -0,0 +1,19 @@
+# Makefile rules generated by CB
+CC = gcc
+CFLAGS = -Wall -g
+BUILD = ch-1 ch-2
+
+all: $(BUILD)
+
+clean:
+ /bin/rm -f $(BUILD) *.o core a.out
+
+args.o: args.c
+ch-1: ch-1.o args.o parseints.o printarray.o
+ch-1.o: ch-1.c args.h parseints.h printarray.h
+ch-2: ch-2.o args.o nextintperm.o parseints.o printarray.o
+ch-2.o: ch-2.c args.h nextintperm.h parseints.h printarray.h
+nextintperm.o: nextintperm.c nextintperm.h
+parseints.o: parseints.c args.h parseints.h printarray.h
+printarray.o: printarray.c
+
diff --git a/challenge-191/duncan-c-white/C/README b/challenge-191/duncan-c-white/C/README
new file mode 100644
index 0000000000..7da556012c
--- /dev/null
+++ b/challenge-191/duncan-c-white/C/README
@@ -0,0 +1,10 @@
+Thought I'd also have a go at translating ch-1.pl and ch-2.pl into C..
+
+Both produce near-identical (non-debugging and even debugging) output to my
+Perl originals.
+
+They use several of my regular support modules:
+- a command-line argument processing module args.[ch],
+- a csvlist-of-int parsing module parseints.[ch], and
+- an int-array printing module printarray.[ch].
+- and newly broken out: permutation of an int-array: nextintperm.[ch].
diff --git a/challenge-191/duncan-c-white/C/args.c b/challenge-191/duncan-c-white/C/args.c
new file mode 100644
index 0000000000..d4a2d38b9a
--- /dev/null
+++ b/challenge-191/duncan-c-white/C/args.c
@@ -0,0 +1,207 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.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);
+ }
+}
+
+
+// int argno = process_flag_n_args( name, argc, argv, n, argmsg );
+// Process the -d flag, and check that there are exactly
+// n remaining arguments, return the index position of the first
+// argument. If not, generate a fatal Usage error using the argmsg.
+//
+int process_flag_n_args( char *name, int argc, char **argv, int n, char *argmsg )
+{
+ int arg=1;
+ if( argc>1 && strcmp( argv[arg], "-d" ) == 0 )
+ {
+ debug = true;
+ arg++;
+ }
+
+ int left = argc-arg;
+ if( left != n )
+ {
+ fprintf( stderr, "Usage: %s [-d] %s\n Exactly %d "
+ "arguments needed\n", name, argmsg, n );
+ exit(1);
+ }
+ return arg;
+}
+
+
+// int argno = process_flag_n_m_args( name, argc, argv, min, max, argmsg );
+// Process the -d flag, and check that there are between
+// min and max remaining arguments, return the index position of the first
+// argument. If not, generate a fatal Usage error using the argmsg.
+//
+int process_flag_n_m_args( char *name, int argc, char **argv, int min, int max, char *argmsg )
+{
+ int arg=1;
+ if( argc>1 && strcmp( argv[arg], "-d" ) == 0 )
+ {
+ debug = true;
+ arg++;
+ }
+
+ int left = argc-arg;
+ if( left < min || left > max )
+ {
+ fprintf( stderr, "Usage: %s [-d] %s\n Between %d and %d "
+ "arguments needed\n", name, argmsg, min, max );
+ exit(1);
+ }
+ return arg;
+}
+
+
+// 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 )
+{
+ char argmsg[100];
+ sprintf( argmsg, "[int default %d]", defvalue );
+ int arg = process_flag_n_m_args( name, argc, argv, 0, 1, argmsg );
+
+ *n = arg == argc ? defvalue : 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 = process_flag_n_args( name, argc, argv, 1, "int" );
+
+ // argument is in 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 = process_flag_n_args( name, argc, argv, 2, "int" );
+
+ // arguments are in argv[arg] and argv[arg+1]
+ *m = atoi( argv[arg++] );
+ *n = atoi( argv[arg] );
+}
+
+
+// process_twostrargs() IS DEPRECATED: use process_flag_n_m_args() instead
+
+
+// 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;
+}
+
+
+//
+// bool isint = check_unsigned_int( char *val, int *n );
+// Given an string val, check that there's an unsigned integer
+// in it (after optional whitespace). If there is a valid
+// unsigned integer value, store that integer value in *n and
+// return true; otherwise return false (and don't alter *n).
+bool check_unsigned_int( char *val, int *n )
+{
+ // skip whitespace in val
+ char *p;
+ for( p=val; isspace(*p); p++ )
+ {
+ /*EMPTY*/
+ }
+ if( ! isdigit(*p) ) return false;
+ *n = atoi(p);
+ return true;
+}
+
+
+//
+// bool ok = check_unsigned_real( char *val, double *n );
+// Given an string val, check that there's an unsigned real
+// in it (after optional whitespace). If there is a valid
+// unsigned real value, store that value in *n and
+// return true; otherwise return false (and don't alter *n).
+bool check_unsigned_real( char *val, double *n )
+{
+ // skip whitespace in val
+ char *p;
+ for( p=val; isspace(*p); p++ )
+ {
+ /*EMPTY*/
+ }
+ if( ! isdigit(*p) ) return false;
+ *n = atof(p);
+ return true;
+}
diff --git a/challenge-191/duncan-c-white/C/args.h b/challenge-191/duncan-c-white/C/args.h
new file mode 100644
index 0000000000..8844a8f9c4
--- /dev/null
+++ b/challenge-191/duncan-c-white/C/args.h
@@ -0,0 +1,11 @@
+extern bool debug;
+
+extern void process_flag_noarg( char * name, int argc, char ** argv );
+extern int process_flag_n_args( char * name, int argc, char ** argv, int n, char * argmsg );
+extern int process_flag_n_m_args( char * name, int argc, char ** argv, int min, int max, char * argmsg );
+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 );
+extern bool check_unsigned_int( char * val, int * n );
+extern bool check_unsigned_real( char * val, double * n );
diff --git a/challenge-191/duncan-c-white/C/ch-1.c b/challenge-191/duncan-c-white/C/ch-1.c
new file mode 100644
index 0000000000..c5b4105dba
--- /dev/null
+++ b/challenge-191/duncan-c-white/C/ch-1.c
@@ -0,0 +1,66 @@
+//
+// Task 1: Twice Largest
+//
+// C version.
+//
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "args.h"
+#include "parseints.h"
+#include "printarray.h"
+
+
+int main( int argc, char **argv )
+{
+ int argno = process_flag_n_m_args( "twice-largest", argc, argv,
+ 1, 1000, "csvlist(int)" );
+ int nel;
+ int *list = parse_int_args( argc, argv, argno, &nel );
+
+ if( debug )
+ {
+ printf( "debug: nel=%d\n", nel );
+ print_int_array( 70, nel, list, ',', stdout );
+ putchar('\n');
+ }
+
+ int max = list[0];
+ for( int i=1; i<nel; i++ )
+ {
+ if( list[i] > max ) max = list[i];
+ }
+
+ if( debug )
+ {
+ printf( "debug: max el = %d\n", max );
+ }
+
+ int n = 0;
+ for( int i=0; i<nel; i++ )
+ {
+ if( list[i] != max && max < 2 * list[i] )
+ {
+ n++;
+ if( debug )
+ {
+ printf( "debug: list is not cute because "
+ "%d < 2 * %d\n", max, list[i] );
+ }
+ break;
+ }
+ }
+
+ int result = (n == 0) ? 1 : -1;
+
+ printf( "%d\n", result );
+
+ free( list );
+
+ return 0;
+}
diff --git a/challenge-191/duncan-c-white/C/ch-2.c b/challenge-191/duncan-c-white/C/ch-2.c
new file mode 100644
index 0000000000..74525f5556
--- /dev/null
+++ b/challenge-191/duncan-c-white/C/ch-2.c
@@ -0,0 +1,90 @@
+//
+// Task 2: Cute List
+//
+// C version.
+//
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "args.h"
+#include "parseints.h"
+#include "printarray.h"
+#include "nextintperm.h"
+
+
+//
+// bool iscute = is_cute( arr, n );
+// Return true iff arr[0..n-1] is cute, as in the top spec.
+// Return false otherwise.
+//
+bool is_cute( int *arr, int n )
+{
+ for( int i0=0; i0<n; i0++ )
+ {
+ int index = i0+1; // index base at 1
+ int val = arr[i0];
+ // NOT cute if both are NOT evenly disible by tother
+ if( ( val % index != 0 ) && ( index % val != 0 ) )
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+
+int main( int argc, char **argv )
+{
+ int argno = process_flag_n_args( "cute-list", argc, argv,
+ 1, "N (1..15)" );
+
+ int n = atoi( argv[argno++] );
+ if( n < 1 || n > 15 )
+ {
+ fprintf( stderr, "cute-list: N (%d) must be in range 1..15)\n", n );
+ exit(1);
+ }
+
+ if( debug )
+ {
+ printf( "debug: n=%d\n", n );
+ }
+
+ int list[16];
+ for( int i=0; i<n; i++ )
+ {
+ list[i] = i+1;
+ }
+ if( debug )
+ {
+ printf( "debug: initial list: " );
+ print_int_array( 60, n, list, ',', stdout );
+ putchar( '\n' );
+ }
+
+ int ncute = 0;
+ for( int i=1; ; i++ )
+ {
+ if( is_cute( list, n ) )
+ {
+ if( debug )
+ {
+ printf( "cute perm: " );
+ print_int_array( 60, n, list, ',', stdout );
+ putchar( '\n' );
+ }
+ ncute++;
+ }
+ bool exhausted = next_perm( list, n );
+ if( exhausted ) break;
+ }
+
+ printf( "%d\n", ncute );
+
+ return 0;
+}
diff --git a/challenge-191/duncan-c-white/C/nextintperm.c b/challenge-191/duncan-c-white/C/nextintperm.c
new file mode 100644
index 0000000000..0598ced6b3
--- /dev/null
+++ b/challenge-191/duncan-c-white/C/nextintperm.c
@@ -0,0 +1,63 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+
+#include "nextintperm.h"
+
+
+//
+// book exhausted = next_perm( arr, n );
+// Find and return the next permutation in lexicographic order
+// of @arr[0..n-1]. Return false if @arr is the last permutation.
+// 1. Find the largest index k such that a[k] < a[k + 1].
+// If no such index exists, we've found the last permutation.
+// 2. Find the largest index l greater than k such that a[k] < a[l].
+// 3. Swap the value of a[k] with that of a[l].
+// 4. Reverse the sequence from a[k + 1] up to and including the final element a[n].
+//
+bool next_perm( int *arr, int n )
+{
+ n--;
+
+ int k, l;
+ for( k=n-1; k>=0 && arr[k]>=arr[k+1]; k-- )
+ {
+ }
+ if( k<0 ) return true;
+ for( l=n; l>k && arr[k]>=arr[l]; l-- )
+ {
+ }
+
+ #if 0
+ printf( "next_perm: k=%d, l=%d, arr[k]=%d, arr[l]=%d\n",
+ k, l, arr[k], arr[l] );
+ #endif
+
+ // swap arr[k] and arr[l]
+ int t = arr[k];
+ arr[k] = arr[l];
+ arr[l] = t;
+
+ // reverse arr[k+1]..arr[n]
+ if( k+1 < n )
+ {
+ #if 0
+ printf( "next_perm: reversing arr[%d..%d]\n", k+1, n );
+ #endif
+ int x, y;
+ for( x=k+1, y=n; x<y ; x++, y-- )
+ {
+ int t = arr[x];
+ arr[x] = arr[y];
+ arr[y] = t;
+ }
+ }
+
+ return false;
+}
+
+
diff --git a/challenge-191/duncan-c-white/C/nextintperm.h b/challenge-191/duncan-c-white/C/nextintperm.h
new file mode 100644
index 0000000000..a7