diff options
| -rw-r--r-- | challenge-184/duncan-c-white/C/.cbuild | 2 | ||||
| -rw-r--r-- | challenge-184/duncan-c-white/C/Makefile | 16 | ||||
| -rw-r--r-- | challenge-184/duncan-c-white/C/README | 5 | ||||
| -rw-r--r-- | challenge-184/duncan-c-white/C/args.c | 207 | ||||
| -rw-r--r-- | challenge-184/duncan-c-white/C/args.h | 11 | ||||
| -rw-r--r-- | challenge-184/duncan-c-white/C/ch-1.c | 68 | ||||
| -rw-r--r-- | challenge-184/duncan-c-white/C/ch-2.c | 140 | ||||
| -rwxr-xr-x | challenge-184/duncan-c-white/C/ch-2.pl | 54 | ||||
| -rw-r--r-- | challenge-184/duncan-c-white/README | 79 | ||||
| -rwxr-xr-x | challenge-184/duncan-c-white/perl/ch-1.pl | 57 | ||||
| -rwxr-xr-x | challenge-184/duncan-c-white/perl/ch-2.pl | 54 |
11 files changed, 633 insertions, 60 deletions
diff --git a/challenge-184/duncan-c-white/C/.cbuild b/challenge-184/duncan-c-white/C/.cbuild index 624a95ebfb..a14ec76520 100644 --- a/challenge-184/duncan-c-white/C/.cbuild +++ b/challenge-184/duncan-c-white/C/.cbuild @@ -1,4 +1,4 @@ -BUILD = ch-1 +BUILD = ch-1 ch-2 CFLAGS = -Wall -g #LDFLAGS = -lm #CFLAGS = -g diff --git a/challenge-184/duncan-c-white/C/Makefile b/challenge-184/duncan-c-white/C/Makefile new file mode 100644 index 0000000000..8d85c7d16d --- /dev/null +++ b/challenge-184/duncan-c-white/C/Makefile @@ -0,0 +1,16 @@ +# 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 +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-184/duncan-c-white/C/README b/challenge-184/duncan-c-white/C/README new file mode 100644 index 0000000000..32275a43e9 --- /dev/null +++ b/challenge-184/duncan-c-white/C/README @@ -0,0 +1,5 @@ +Thought I'd also have a go at translating ch-1.pl and ch-2.pl into C.. + +Both produce identical (non-debugging) output to my Perl originals. + +Both use the command-line argument processing module args.[ch]. diff --git a/challenge-184/duncan-c-white/C/args.c b/challenge-184/duncan-c-white/C/args.c new file mode 100644 index 0000000000..d4a2d38b9a --- /dev/null +++ b/challenge-184/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-184/duncan-c-white/C/args.h b/challenge-184/duncan-c-white/C/args.h new file mode 100644 index 0000000000..8844a8f9c4 --- /dev/null +++ b/challenge-184/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-184/duncan-c-white/C/ch-1.c b/challenge-184/duncan-c-white/C/ch-1.c new file mode 100644 index 0000000000..3996388c8b --- /dev/null +++ b/challenge-184/duncan-c-white/C/ch-1.c @@ -0,0 +1,68 @@ +// +// Task 1: Sequence Number +// +// C version. +// + +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> +#include <ctype.h> +#include <assert.h> + +#include "args.h" + + +// +// seqno( strbuf ); +// Given a writable string in the format aa9999 i.e. first 2 characters +// can be anything 'a-z' followed by 4 digits '0-9', +// replace the first two characters with sequence starting +// with '00', '01', '02' etc. +// +static void seqno( char *strbuf ) +{ + static int seqno = 0; + if( strlen(strbuf)!=6 || !isalpha(strbuf[0]) || !isalpha(strbuf[1]) + || !isdigit(strbuf[2]) || !isdigit(strbuf[3]) || ! isdigit(strbuf[4]) + || !isdigit(strbuf[5]) ) + { + fprintf( stderr, "bad format %s: not lldddd\n", strbuf ); + exit(1); + } + int x = seqno++; + strbuf[0] = '0' + x/10; + strbuf[1] = '0' + x%10; +} + + +int main( int argc, char **argv ) +{ + int argno = process_flag_n_m_args( "sequence-number", argc, argv, + 1, 100000, "list of strings" ); + + int numarrays = argc-argno; + if( debug ) + { + printf( "debug: numarrays=%d\n", numarrays ); + } + + int i; + bool isfirst=true; + for( i=argno; i<argc; i++ ) + { + if( !isfirst ) + { + putchar(','); + } + isfirst=false; + char arg[10]; + strcpy( arg, argv[i] ); + seqno( arg ); + printf( "%s", arg ); + } + putchar('\n'); + + return 0; +} diff --git a/challenge-184/duncan-c-white/C/ch-2.c b/challenge-184/duncan-c-white/C/ch-2.c new file mode 100644 index 0000000000..1a56dc6478 --- /dev/null +++ b/challenge-184/duncan-c-white/C/ch-2.c @@ -0,0 +1,140 @@ +// +// Task 2: Split Array +// +// C version. +// + +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> +#include <ctype.h> +#include <assert.h> + +#include "args.h" + + +// +// process_one_el( el, outp, wantnum, appanyp ); +// Given an element string argument (el), which should be EITHER be a +// number or a letter/word, and an output pointer outp, and a boolean +// (wantnum) telling us whether to search for numbers or letters, and +// a ptr-to-a-boolean (appanyp) which says whether or not we've yet +// appended anything to outp, check whether the element should +// be included, and append it to outp if it is, modifying *appanyp. +// +static void process_one_el( char *el, char *outp, bool wantnum, bool *anyp ) +{ + if( debug ) + { + printf( "debug: pel: el=%s\n", el ); + } + + if( ! (wantnum && isdigit(*el)) && ! ( !wantnum && isalpha(*el)) ) + { + return; + } + + for( ; *outp; outp++ ) /*EMPTY*/; + + if( debug ) + { + printf( "debug: pel: good el=%s, outp=%s\n", el, outp ); + } + + if( ! *anyp ) + { + *outp++ = '['; + *anyp = true; + } else + { + *outp++ = ','; + } + strcpy( outp, el ); +} + + +// +// onepass( arg, outp, wantnum ); +// Given a modifiable string argument (arg), which should be a +// space-sep-values-string, and an output pointer outp, and a boolean +// (wantnum) telling us whether to search for numbers (if wantnum) +// or letters (if !wantnum), append well formatted lists of such elements +// from arg to outp. +// +static void onepass( char *arg, char *outp, bool wantnum ) +{ + bool appany = false; // have we yet appended anything to outp? + + char *p; + char *end; + for( p=arg; (end=strchr(p,' '))!= NULL; p=end+1 ) + { + *end = '\0'; + process_one_el( p, outp, wantnum, &appany ); + *end = ' '; + } + process_one_el( p, outp, wantnum, &appany ); + if( appany ) + { + strcat( outp, "], " ); + } +} + + +// +// process( char *arg, char *letp, char *nump ); +// Given a string argument (arg), which should be a csv-string +// and a letter-string-pointer (letp) and a number-string-pointer (nump) +// append well formatted lists of letters in arg to letp, and +// append well formatted lists of numbers in arg to letp. +// +static void process( char *arg, char *letp, char *nump ) +{ + // convert commas to spaces + for( char *p=arg; *p; p++ ) + { + if( *p == ',' ) *p = ' '; + } + + // append any numbers in arg to nump + onepass( arg, nump, true ); + + // append any letters in arg to letp + onepass( arg, letp, false ); +} + + +int main( int argc, char **argv ) +{ + int argno = process_flag_n_m_args( "split-array", argc, argv, + 1, 100000, "array of csv-strings" ); + + int numstrings = argc-argno; + if( debug ) + { + printf( "debug: numstrings=%d\n", numstrings ); + } + + char letstr[1024]; + char numstr[1024]; + strcpy( letstr, "" ); + strcpy( numstr, "" ); + + char *lp = letstr; + char *np = numstr; + + int i; + for( i=argno; i<argc; i++ ) + { + process( argv[i], lp, np ); + lp += strlen(lp); + np += strlen(np); + } + numstr[strlen(numstr)-2] = '\0'; + letstr[strlen(letstr)-2] = '\0'; + + printf( "Output: [%s] and [%s]\n", numstr, letstr ); + + return 0; +} diff --git a/challenge-184/duncan-c-white/C/ch-2.pl b/challenge-184/duncan-c-white/C/ch-2.pl new file mode 100755 index 0000000000..70c0d83b3f --- /dev/null +++ b/challenge-184/duncan-c-white/C/ch-2.pl @@ -0,0 +1,54 @@ +#!/usr/bin/perl +# +# Task 2: Split Array +# +# You are given list of strings containing 0-9 and a-z separated by space only. +# Write a script to split the data into two arrays, one for integers and +# one for alphabets only. +# +# Example 1 +# +# Input: @list = ( 'a 1 2 b 0', '3 c 4 d') +# Output: [[1,2,0], [3,4]] and [['a','b'], ['c','d']] +# +# Example 2 +# +# Input: @list = ( '1 2', 'p q r', 's 3', '4 5 t') +# Output: [[1,2], [3], [4,5]] and [['p','q','r'], ['s'], ['t']] +# +# MY NOTES: Also seems pretty simple. +# +# GUEST LANGUAGE: As a bonus, I also had a go at translating ch-2.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: split-array [--debug] 'csv_string'+\n" + unless GetOptions( "debug"=>\$debug ) && @ARGV>0; + +my @num; +my @let; + +foreach my $list (@ARGV) +{ + $list =~ tr/,/ /; + my @x = split(/\s+/,$list); + my @a = grep { /\d/ } @x; + push @num, [ @a ] if @a; + @a = grep { /[a-z]/ } @x; + push @let, [ @a ] if @a; +} + +#say Dumper(\@let); +#say Dumper(\@num); + +my $letstr = "[". join( ', ', map { "[".join(',',@$_)."]" } @let ) . "]"; +my $numstr = "[". join( ', ', map { "[".join(',',@$_)."]" } @num ) . "]"; + +say "Output: $numstr and $letstr"; diff --git a/challenge-184/duncan-c-white/README b/challenge-184/duncan-c-white/README index 8b1fb7e81b..2cd8d35c5f 100644 --- a/challenge-184/duncan-c-white/README +++ b/challenge-184/duncan-c-white/README @@ -1,82 +1,43 @@ -Task 1: Unique Array +Task 1: Sequence Number -You are given list of arrayrefs. -Write a script to remove the duplicate arrayrefs from the given list. +You are given list of strings in the format aa9999 i.e. first 2 characters +can be anything 'a-z' followed by 4 digits '0-9'. +Write a script to replace the first two characters with sequence starting +with '00', '01', '02' etc. Example 1 -Input: @list = ([1,2], [3,4], [5,6], [1,2]) -Output: ([1,2], [3,4], [5,6]) + Input: @list = ( 'ab1234', 'cd5678', 'ef1342') + Output: ('001234', '015678', '021342') Example 2 -Input: @list = ([9,1], [3,7], [2,5], [2,5]) -Output: ([9, 1], [3,7], [2,5]) + Input: @list = ( 'pq1122', 'rs3334') + Output: ('001122', '013334') -MY NOTES: nice and easy, only challenge is how to store a representation -of an entire array as a hash key: obvious option is to join(',',@items) +MY NOTES: nice and easy. Trivial in fact. GUEST LANGUAGE: As a bonus, I also had a go at implementing ch-1.pl -into C (look in the C directory for that). It's not a direct translation -of the Perl solution because that involves sets of joined strings, instead -it does it the obvious low-tech way: finding duplicate arrays and deleting -them. +into C (look in the C directory for that). -Task 2: Date Difference +Task 2: Split Array -You are given two dates, $date1 and $date2 in the format YYYY-MM-DD. -Write a script to find the difference between the given dates in terms on years and days only. +You are given list of strings containing 0-9 and a-z separated by space only. +Write a script to split the data into two arrays, one for integers and +one for alphabets only. Example 1 -Input: $date1 = '2019-02-10' - $date2 = '2022-11-01' -Output: 3 years 264 days + Input: @list = ( 'a 1 2 b 0', '3 c 4 d') + Output: [[1,2,0], [3,4]] and [['a','b'], ['c','d']] Example 2 -Input: $date1 = '2020-09-15' - $date2 = '2022-03-29' -Output: 1 year 195 days - -Example 3 - -Input: $date1 = '2019-12-31' - $date2 = '2020-01-01' -Output: 1 day - -Example 4 - -Input: $date1 = '2019-12-01' - $date2 = '2019-12-31' -Output: 30 days - -Example 5 - -Input: $date1 = '2019-12-31' - $date2 = '2020-12-31' -Output: 1 year - -Example 6 - -Input: $date1 = '2019-12-31' - $date2 = '2021-12-31' -Output: 2 years - -Example 7 - -Input: $date1 = '2020-09-15' - $date2 = '2021-09-16' -Output: 1 year 1 day - -Example 8 - -Input: $date1 = '2019-09-15' - $date2 = '2021-09-16' -Output: 2 years 1 day + Input: @list = ( '1 2', 'p q r', 's 3', '4 5 t') + Output: [[1,2], [3], [4,5]] and [['p','q','r'], ['s'], ['t']] -MY NOTES: Should be a simple task for Date::Simple or Date::Manup. +MY NOTES: Also seems pretty simple. GUEST LANGUAGE: As a bonus, I also had a go at translating ch-2.pl into C (look in the C directory for that). diff --git a/challenge-184/duncan-c-white/perl/ch-1.pl b/challenge-184/duncan-c-white/perl/ch-1.pl new file mode 100755 index 0000000000..a3067e1622 --- /dev/null +++ b/challenge-184/duncan-c-white/perl/ch-1.pl @@ -0,0 +1,57 @@ +#!/usr/bin/perl +# +# Task 1: Sequence Number +# +# You are given list of strings in the format aa9999 i.e. first 2 characters +# can be anything 'a-z' followed by 4 digits '0-9'. +# Write a script to replace the first two characters with sequence starting +# with '00', '01', '02' etc. +# +# Example 1 +# +# Input: @list = ( 'ab1234', 'cd5678', 'ef1342') +# Output: ('001234', '015678', '021342') +# +# Example 2 +# +# Input: @list = ( 'pq1122', 'rs3334') +# Output: ('001122', '013334') +# +# MY NOTES: nice and easy. Trivial in fact. +# +# GUEST LANGUAGE: As a bonus, I also had a go at implementing ch-1.pl +# into C (look in the C directory for that). +# + +use strict; +use warnings; +use feature 'say'; +use feature 'state'; +use Getopt::Long; +use Data::Dumper; + + +my $debug=0; +die "Usage: sequence-number [--debug] string+\n" + unless GetOptions( "debug"=>\$debug ) && @ARGV>0; + +# +# my $seqstr = seqno( $str ); +# Given a string in the format aa9999 i.e. first 2 characters +# can be anything 'a-z' followed by 4 digits '0-9', +# replace the first two characters with sequence starting +# with '00', '01', '02' etc. +# +sub seqno +{ + my( $str ) = @_; + state $seqno = 0; + die "bad format $str: not lldddd\n" unless $str =~ /^(\w\w)(\d\d\d\d)$/; + $str = sprintf( "%02d%s", $seqno++, $2 ); + return $str; +} + + +my @list = @ARGV; + +say join( ',', map { seqno($_) } @list ); diff --git a/challenge-184/duncan-c-white/perl/ch-2.pl b/challenge-184/duncan-c-white/perl/ch-2.pl new file mode 100755 index 0000000000..70c0d83b3f --- /dev/null +++ b/challenge-184/duncan-c-white/perl/ch-2.pl @@ -0,0 +1,54 @@ +#!/usr/bin/perl +# +# Task 2: Split Array +# +# You are given list of strings containing 0-9 and a-z separated by space only. +# Write a script to split the data into two arrays, one for integers and +# one for alphabets only. +# +# Example 1 +# +# Input: @list = ( 'a 1 2 b 0', '3 c 4 d') +# Output: [[1,2,0], [3,4]] and [['a','b'], ['c','d']] +# +# Example 2 +# +# Input: @list = ( '1 2', 'p q r', 's 3', '4 5 t') +# Output: [[1,2], [3], [4,5]] and [['p','q','r'], ['s'], ['t']] +# +# MY NOTES: Also seems pretty simple. +# +# GUEST LANGUAGE: As a bonus, I also had a go at translating ch-2.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: split-array [--debug] 'csv_string'+\n" + unless GetOptions( "debug"=>\$debug ) && @ARGV>0; + +my @num; +my @let; + +foreach my $list (@ARGV) +{ + $list =~ tr/,/ /; + my @x = split(/\s+/,$list); + my @a = grep { /\d/ } @x; + push @num, [ @a ] if @a; + @a = grep { /[a-z]/ } @x; + push @let, [ @a ] if @a; +} + +#say Dumper(\@let); +#say Dumper(\@num); + +my $letstr = "[". join( ', ', map { "[".join(',',@$_)."]" } @let ) . "]"; +my $numstr = "[". join( ', ', map { "[".join(',',@$_)."]" } @num ) . "]"; + +say "Output: $numstr and $letstr"; |
