diff options
| author | Mohammad S Anwar <Mohammad.Anwar@yahoo.com> | 2022-10-24 01:07:44 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-10-24 01:07:44 +0100 |
| commit | d3136e0cdc4a186e82e8671ea3971852b569b598 (patch) | |
| tree | 13578a954fbd290de64cf1994bcf299cd5b13a77 | |
| parent | 638ad242421265d42efb750ae31416f886fe23c3 (diff) | |
| parent | 464e5ff7037bdae758d80848f499a2bb53f5caee (diff) | |
| download | perlweeklychallenge-club-d3136e0cdc4a186e82e8671ea3971852b569b598.tar.gz perlweeklychallenge-club-d3136e0cdc4a186e82e8671ea3971852b569b598.tar.bz2 perlweeklychallenge-club-d3136e0cdc4a186e82e8671ea3971852b569b598.zip | |
Merge pull request #6949 from dcw803/master
imported my solutions to both tasks in C and Perl
| -rw-r--r-- | challenge-187/duncan-c-white/C/.cbuild | 2 | ||||
| -rw-r--r-- | challenge-187/duncan-c-white/C/Makefile | 18 | ||||
| -rw-r--r-- | challenge-187/duncan-c-white/C/README | 11 | ||||
| -rw-r--r-- | challenge-187/duncan-c-white/C/args.c | 207 | ||||
| -rw-r--r-- | challenge-187/duncan-c-white/C/args.h | 11 | ||||
| -rw-r--r-- | challenge-187/duncan-c-white/C/ch-1.c | 116 | ||||
| -rw-r--r-- | challenge-187/duncan-c-white/C/ch-2.c | 188 | ||||
| -rw-r--r-- | challenge-187/duncan-c-white/C/parseints.c | 105 | ||||
| -rw-r--r-- | challenge-187/duncan-c-white/C/parseints.h | 1 | ||||
| -rw-r--r-- | challenge-187/duncan-c-white/C/printarray.c | 39 | ||||
| -rw-r--r-- | challenge-187/duncan-c-white/C/printarray.h | 1 | ||||
| -rw-r--r-- | challenge-187/duncan-c-white/README | 93 | ||||
| -rwxr-xr-x | challenge-187/duncan-c-white/perl/ch-1.pl | 127 | ||||
| -rwxr-xr-x | challenge-187/duncan-c-white/perl/ch-2.pl | 114 |
14 files changed, 1010 insertions, 23 deletions
diff --git a/challenge-187/duncan-c-white/C/.cbuild b/challenge-187/duncan-c-white/C/.cbuild index 624a95ebfb..a14ec76520 100644 --- a/challenge-187/duncan-c-white/C/.cbuild +++ b/challenge-187/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-187/duncan-c-white/C/Makefile b/challenge-187/duncan-c-white/C/Makefile new file mode 100644 index 0000000000..34d8a4d520 --- /dev/null +++ b/challenge-187/duncan-c-white/C/Makefile @@ -0,0 +1,18 @@ +# 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 parseints.o printarray.o +ch-2.o: ch-2.c args.h parseints.h printarray.h +parseints.o: parseints.c args.h parseints.h printarray.h +printarray.o: printarray.c + diff --git a/challenge-187/duncan-c-white/C/README b/challenge-187/duncan-c-white/C/README new file mode 100644 index 0000000000..b7043e9cbb --- /dev/null +++ b/challenge-187/duncan-c-white/C/README @@ -0,0 +1,11 @@ +Thought I'd also have a go at translating ch-1.pl into C.. + +Of course, it can only deal with lists of integers, so the original +examples have to change. + +It produce identical (non-debugging) output to my Perl original. + +It uses 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]. diff --git a/challenge-187/duncan-c-white/C/args.c b/challenge-187/duncan-c-white/C/args.c new file mode 100644 index 0000000000..d4a2d38b9a --- /dev/null +++ b/challenge-187/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-187/duncan-c-white/C/args.h b/challenge-187/duncan-c-white/C/args.h new file mode 100644 index 0000000000..8844a8f9c4 --- /dev/null +++ b/challenge-187/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-187/duncan-c-white/C/ch-1.c b/challenge-187/duncan-c-white/C/ch-1.c new file mode 100644 index 0000000000..c94c3e9bd8 --- /dev/null +++ b/challenge-187/duncan-c-white/C/ch-1.c @@ -0,0 +1,116 @@ +// +// Task 1: Days Together +// +// 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 dim[] = { -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + +// int day_in_year = yearday( ddmm ); +// Check whether $ddmm is a valid date of format dd-mm where dd is 1..31 +// and mm is 1..12 (and dd <= days_in_month(mm)), returning the day number +// in the year if it is, or -1 if it is invalid. +// +int yearday( char *ddmm ) +{ + // validate overall shape /^(\d\d?)-(\d\d?)$/ + int d, m; + if( sscanf( ddmm, "%d-%d", &d, &m ) != 2 ) return -1; + + if( m < 1 || m > 12 ) return -1; + + if( d < 1 || d > dim[m] ) return -1; + + int dayno = 0; + for( int i=1; i<m; i++ ) + { + dayno += dim[i]; + } + dayno += d; + return dayno; +} + + +#define min(a,b) ((a)<(b)?(a):(b)) +#define max(a,b) ((a)>(b)?(a):(b)) + + +// +// +// int noverlap = overlapdays( sd1d, ed1d, sd2d, ed2d ); +// Find out the number of overlapping days between the two ranges +// of dates, as the task describes. Each date is represented by +// a logical day-number-in-the-year. Return 0 if no overlap. +int overlapdays( int sd1d, int ed1d, int sd2d, int ed2d ) +{ + // none if one range finishes before the other + if( ed1d < sd2d || ed2d < sd1d ) return 0; + + int csd = max(sd1d,sd2d); // common start date + int ced = min(ed1d,ed2d); // common end date + + return 1+ced-csd; +} + + +int main( int argc, char **argv ) +{ + int argno = process_flag_n_args( "overlapping-days", argc, argv, + 4, "dd-mm-sd1 dd-mm-ed1 dd-mm-sd2 dd-mm-ed2" ); + + if( debug ) + { + printf( "debug: argno=%d, firstarg=%s\n", argno, argv[argno] ); + } + + char *date = argv[argno++]; + int sd1d = yearday( date ); // days since start of year for sd1 + if( sd1d < 1 ) + { + fprintf( stderr, "Bad dd-mm-sd1 (%s)\n", date ); + exit(1); + } + + date = argv[argno++]; + int ed1d = yearday( date ); // days since start of year for ed1 + if( ed1d < 1 ) + { + fprintf( stderr, "Bad dd-mm-ed1 (%s)\n", date ); + exit(1); + } + + date = argv[argno++]; + int sd2d = yearday( date ); // days since start of year for sd2 + if( sd2d < 1 ) + { + fprintf( stderr, "Bad dd-mm-sd2 (%s)\n", date ); + exit(1); + } + + date = argv[argno++]; + int ed2d = yearday( date ); // days since start of year for ed2 + if( ed2d < 1 ) + { + fprintf( stderr, "Bad dd-mm-ed2 (%s)\n", date ); + exit(1); + } + + printf( "sd1:%d, ed1:%d, sd2:%d, ed2:%d\n", sd1d, ed1d, sd2d, ed2d ); + + int noverlap = overlapdays( sd1d, ed1d, sd2d, ed2d ); + printf( "%d days\n", noverlap ); + + return 0; +} diff --git a/challenge-187/duncan-c-white/C/ch-2.c b/challenge-187/duncan-c-white/C/ch-2.c new file mode 100644 index 0000000000..5d3eeb6cd7 --- /dev/null +++ b/challenge-187/duncan-c-white/C/ch-2.c @@ -0,0 +1,188 @@ +// +// Task 2: Magical Triplets +// +// 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" + + +typedef struct { + int a, b, c; + int sum; // computed field: a+b+c +} triplet; + + +typedef struct // a dynamic list of triplets +{ + int n, max; + int maxsum; + triplet *t; // dynarray t[max] allocated, t[0..n-1] in use +} tlist; + + +// tlist t; +// bool alreadyseen = add_tlist( a, b, c, &t ); +// Add the triple (a,b,c) to tlist t unless it's already +// present. Return true if it was already present, else return false. +bool add_tlist( int a, int b, int c, tlist *t ) +{ + for( int i=0; i<t->n; i++ ) + { + triplet *p = &(t->t[i]); + if( p->a == a && p->b == b && p->c == c ) + { + return true; + } + } + // not found, add (a,b,c) to t + if( t->n == t->max ) + { + t->max += 100; + t->t = realloc( t->t, t->max ); + assert( t->t != NULL ); + } + triplet *p = &(t->t[t->n++]); + p->a = a; + p->b = b; + p->c = c; + // keep track of triplet sum, and tlist maxsum so far + p->sum = a+b+c; + if( p->sum > t->maxsum ) + { + t->maxsum = p->sum; + } + return false; +} + + +// showtlist( FILE *out, char *name, tlist *t ); +// Display t on out. +void showtlist( FILE *out, char *name, tlist *t ) +{ + fprintf( out, "%s has %d triples, max sum=%d\n", + name, t->n, t->maxsum ); + for( int i=0; i<t->n; i++ ) + { + triplet *p = &(t->t[i]); + fprintf( out, "%d+%d+%d=%d\n", p->a, p->b, p->c, p->sum ); + } +} + + +// freetlist( t ); +// Free the tlist t. +void freetlist( tlist *t ) +{ + free( t->t ); + free( t ); +} + + +// tlist *t = pass1( x, nel ); +// generate all triples of 3 distinct elements in x (in +// any order) and find those triples that pass rules 1..3, +// building and returning a tlist t of the triplets found. +// Note that a tlist keeps track of the triplet sums, and +// even the current maximum sum, so it's more like pass1+2 +// of the original Perl code. +// Note that the returned value t must be freed by the caller after use. +// +tlist *pass1( int *x, int nel ) +{ + tlist *result = malloc( sizeof(tlist) ); + assert( result != NULL ); + result->max = 100; + result->n = 0; + result->maxsum = 0; + result->t = malloc( result->max * sizeof(triplet) ); + assert( result->t != NULL ); + + for( int p1=0; p1<nel; p1++ ) + { + for( int p2=0; p2<nel; p2++ ) + { + if( p1==p2 ) continue; + for( int p3=0; p3<nel; p3++ ) + { + if( p1==p3 || p2==p3 ) continue; + int a = x[p1]; + int b = x[p2]; + int c = x[p3]; + if( a+b<=c || b+c<=a || a+c<=b ) continue; + if( add_tlist( a, b, c, result ) ) continue; + if( debug ) + { + printf( "debug: semi-magic triple %d, %d, %d, sum=%d\n", a, b, c, a+b+c ); + //showtlist( stdout, "s-m-ts", result ); + } + } + } + } + + return result; +} + + +int main( int argc, char **argv ) +{ + int argno = process_flag_n_args( "magic-triple", argc, argv, + 1, "csvlist" ); + + if( debug ) + { + printf( "debug: argno=%d, firstarg=%s\n", argno, argv[argno] ); + } + + int nel; + int *x = parse_int_args( argc, argv, argno, &nel ); + nel--; + + if( nel<3 ) + { + fprintf( stderr, "magic-triple: csvlist %s must contain at least 3 numbers\n", argv[argno] ); + exit(1); + } + + if( debug ) + { + printf( "nel=%d, x=", nel ); + print_int_array( 70, nel, x, ',', stdout ); + putchar( '\n' ); + } + + // pass 1 - generate all triples of 3 distinct elements in x (in + // any order) and find those triples that pass rules 1..3 + tlist *p1t = pass1( x, nel ); + showtlist( stdout, "pass1 triples", p1t ); + + // if there are NO triplets found obeying rules 1..3, report failure + if( p1t->n == 0 ) + { + printf( "No magic triplets found\n" ); + exit(0); + } + + // pass2: identify which of those triples has the maxsum && has a>=b>=c + for( int i=0; i<p1t->n; i++ ) + { + triplet *p = &(p1t->t[i]); + if( p->sum != p1t->maxsum ) continue; + if( p->a < p->b || p->b < p->c ) continue; + printf( "Found magic triple %d, %d, %d\n", p->a, p->b, p->c ); + } + + freetlist( p1t ); + + free( x ); + return 0; +} diff --git a/challenge-187/duncan-c-white/C/parseints.c b/challenge-187/duncan-c-white/C/parseints.c new file mode 100644 index 0000000000..1b188afe8d --- /dev/null +++ b/challenge-187/duncan-c-white/C/parseints.c @@ -0,0 +1,105 @@ +// Simple routine to parse one or more arguments, +// looking for individual +ints or comma-separated +// lists of +ints. +// + +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> +#include <ctype.h> +#include <assert.h> + +#include "args.h" +#include "printarray.h" +#include "parseints.h" + +typedef struct +{ + int nel; // current number of elements + int maxel; // maximum number of elements allocated + int *list; // malloc()d list of integers +} intlist; + + +// +// intlist il.. then initialize il.. then: +// add_one( element, &il ); +// +static void add_one( int x, intlist *p ) +{ + if( p->nel > p->maxel ) + { + p->maxel += 128; + p->list = realloc( p->list, p->maxel ); + assert( p->list ); + } + if( debug ) + { + printf( "PIA: appending %d to result at " + "pos %d\n", x, p->nel ); + } + p->list[p->nel++] = x; +} + + +// +// intlist il.. then initialize il.. then: +// add_one_arg( argstr, &il ); +// +static void add_one_arg( char *argstr, intlist *p ) +{ + int x; + if( !check_unsigned_int(argstr,&x) ) + { + fprintf( stderr, "PIA: arg %s must be +int\n", argstr ); + exit(1); + } + add_one( x, p ); +} + + +// +// int nel; +// int *ilist = parse_int_args( argc, argv, argno, &nel ); +// process all arguments argv[argno..argc-1], extracting either +// single ints or comma-separated lists of ints from those arguments, +// accumulate all integers in a dynarray list, storing the total number +// of elements in nel. This list must be freed by the caller. +int *parse_int_args( int argc, char **argv, int argno, int *nel ) +{ + int *result = malloc( 128 * sizeof(int) ); + assert( result ); + intlist il = { 0, 128, result }; + + if( debug ) + { + printf( "PIA: parsing ints from args %d..%d\n", argno, argc-1 ); + } + for( int i=argno; i<argc; i++ ) + { + assert( strlen(argv[i]) < 1024 ); + char copy[1024]; + strcpy( copy, argv[i] ); + char *com; + char *s; + for( s=copy; (com = strchr(s,',')) != NULL; s=com+1 ) + { + *com = '\0'; + add_one_arg( s, &il ); + } + add_one_arg( s, &il ); + } + + add_one( -1, &il ); + + if( debug ) + { + printf( "PIA: final list is " ); + print_int_array( 80, il.nel, il.list, ',', stdout ); + putchar( '\n' ); + } + + *nel = il.nel; + return il.list; +} diff --git a/challenge-187/duncan-c-white/C/parseints.h b/challenge-187/duncan-c-white/C/parseints.h new file mode 100644 index 0000000000..da5e145a86 --- /dev/null +++ b/challenge-187/duncan-c-white/C/parseints.h @@ -0,0 +1 @@ +extern int * parse_int_args( int argc, char ** argv, int argno, int * nel ); diff --git a/challenge-187/duncan-c-white/C/printarray.c b/challenge-187/duncan-c-white/C/printarray.c new file mode 100644 index 0000000000..ddee597df3 --- /dev/null +++ b/challenge-187/duncan-c-white/C/printarray.c @@ -0,0 +1,39 @@ +#include <stdio.h> +#include <string.h> + + +// print_int_array( maxw, nelements, results[], sep, outfile ); +// format results[0..nelements-1] as a <sep> separated +// list onto outfile with lines <= maxw chars long. +// produces a whole number of lines of output - without the trailing '\n' +void print_int_array( int maxw, int nel, int *results, char sep, FILE *out ) +{ + int linelen = 0; + for( int i=0; i<nel; i++ ) + { + char buf[100]; + sprintf( buf, "%d", results[i] ); + int len = strlen(buf); + if( linelen + len + 2 > maxw ) + { + fputc( '\n', out ); + linelen = 0; + } else if( i>0 ) + { + fputc( ' ', out ); + linelen++; + } + + linelen += len; + fprintf( out, "%s", buf ); + if( i<nel-1 ) + { + fputc( sep, out ); + linelen++; + } + } + //if( linelen>0 ) + //{ + // fputc( '\n', out ); + //} +} diff --git a/challenge-187/duncan-c-white/C/printarray.h b/challenge-187/duncan-c-white/C/printarray.h new file mode 100644 index 0000000000..40efb83277 --- /dev/null +++ b/challenge-187/duncan-c-white/C/printarray.h @@ -0,0 +1 @@ +extern void print_int_array( int maxw, int nel, int * results, char sep, FILE * out ); diff --git a/challenge-187/duncan-c-white/README b/challenge-187/duncan-c-white/README index 44c69614fa..ce8d8f7676 100644 --- a/challenge-187/duncan-c-white/README +++ b/challenge-187/duncan-c-white/README @@ -1,40 +1,89 @@ -Task 1: Zip List +Task 1: Days Together -You are given two list @a and @b of same size. -Create a subroutine sub zip(@a, @b) that merge the two list as shown in -the example below. +Two friends, Foo and Bar gone on holidays seperately to the same city. You +are given their schedule i.e. start date and end date. -Example +To keep the task simple, the date is in the form DD-MM and all dates +belong to the same calendar year i.e. between 01-01 and 31-12. Also the +year is non-leap year and both dates are inclusive. -Input: @a = qw/1 2 3/; @b = qw/a b c/; -Output: zip(@a, @b) should return qw/1 a 2 b 3 c/; - zip(@b, @a) should return qw/a 1 b 2 c 3/; +Write a script to find out for the given schedule, how many days they +spent together in the city, if at all. +Example 1 + +Input: Foo => SD: '12-01' ED: '20-01' + Bar => SD: '15-01' ED: '18-01' + +Output: 4 days + +Example 2 + +Input: Foo => SD: '02-03' ED: '12-03' + Bar => SD: '13-03' ED: '14-03' + +Output: 0 day + +Example 3 + +Input: Foo => SD: '02-03' ED: '12-03' + Bar => SD: '11-03' ED: '15-03' + +Output: 2 days -MY NOTES: very easy, except for the fact that a Perl subroutine CAN'T -take 2 arrays. Guess he meant array-refs? +Example 4 + +Input: Foo => SD: '30-03' ED: '05-04' + Bar => SD: '28-03' ED: '02-04' + +Output: 4 days + +MY NOTES: pretty easy. Let's do it by hand (no Date modules to inc-date) +given all the constraints, same year, non-leap year. GUEST LANGUAGE: As a bonus, I also had a go at translating ch-1.pl -into C (look in the C directory for that). Of course, that could -only deal with lists of integers, so the examples above have to change. +into C (look in the C directory for that). + + +Task 2: Magical Triplets +You are given a list of positive numbers, @n, having at least 3 numbers. -Task 2: Unicode Makeover +Write a script to find the triplets (a, b, c) from the given list that +satisfies the following rules. -You are given a string with possible unicode characters. -Create a subroutine sub makeover($str) that replace the unicode characters with ascii equivalent. For this task, let us assume it only contains alphabets. +1. a + b > c +2. b + c > a +3. a + c > b +4. a + b + c is maximum. + +In case, you end up with more than one triplets having the maximum then +pick the triplet where a >= b >= c. Example 1 -Input: $str = 'ÃÊÍÒÙ'; -Output: 'AEIOU' + Input: @n = (1, 2, 3, 2); + Output: (3, 2, 2) Example 2 -Input: $str = 'âÊíÒÙ'; -Output: 'aEiOU' + Input: @n = (1, 3, 2); + Output: () + +Example 3 + + Input: @n = (1, 1, 2, 3); + Output: () + +Example 4 + + Input: @n = (2, 4, 3); + Output: (4, 3, 2) +MY NOTES: Ok, sounds like generate+test. Find all triples. Find +triples that pass tests (1)..(3). Then find which triples have the +maximum sum. If only, that's the answer. If more than one, use the +tie break rule. -MY NOTES: Unicode: just say no - hell no. -My terminal doesn't even display the horrible input strings right. -I'm not doing this. Forget it. +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-187/duncan-c-white/perl/ch-1.pl b/challenge-187/duncan-c-white/perl/ch-1.pl new file mode 100755 index 0000000000..4de13bf986 --- /dev/null +++ b/challenge-187/duncan-c-white/perl/ch-1.pl @@ -0,0 +1,127 @@ +#!/usr/bin/perl +# +# Task 1: Days Together +# +# Two friends, Foo and Bar gone on holidays seperately to the same city. You +# are given their schedule i.e. start date and end date. +# +# To keep the task simple, the date is in the form DD-MM and all dates +# belong to the same calendar year i.e. between 01-01 and 31-12. Also the +# year is non-leap year and both dates are inclusive. +# +# Write a script to find out for the given schedule, how many days they +# spent together in the city, if at all. +# +# Example 1 +# +# Input: Foo => SD: '12-01' ED: '20-01' +# Bar => SD: '15-01' ED: '18-01' +# +# Output: 4 days +# +# Example 2 +# +# Input: Foo => SD: '02-03' ED: '12-03' +# Bar => SD: '13-03' ED: '14-03' +# +# Output: 0 day +# +# Example 3 +# +# Input: Foo => SD: '02-03' ED: '12-03' +# Bar => SD: '11-03' ED: '15-03' +# +# Output: 2 days +# +# Example 4 +# +# Input: Foo => SD: '30-03' ED: '05-04' +# Bar => SD: '28-03' ED: '02-04' +# +# Output: 4 days +# +# MY NOTES: pretty easy. Let's do it by hand (no Date modules to inc-date) +# given all the constraints, same year, non-leap year. +# +# 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 feature 'state'; +use Getopt::Long; +use Data::Dumper; +use List::Util qw(min max); +use Function::Parameters; + + +my $debug=0; +die "Usage: overlapping-days [--debug] dd-mm-sd1 dd-mm-ed1 dd-mm-sd2 dd-mm-ed2\n" + unless GetOptions( "debug"=>\$debug ) && @ARGV==4; + + +my @dim = ( -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ); + +=pod + +=head2 my $day_in_year = yearday( $ddmm ); + +Check whether $ddmm is a valid date of format dd-mm where dd is 1..31 +and mm is 1..12 (and dd <= days_in_month(mm)), returning the day number +in the year if it is, or -1 if it is invalid. + +=cut +fun yearday( $ddmm ) +{ + return -1 unless $ddmm =~ /^(\d\d?)-(\d\d?)$/; + my( $d, $m ) = ( $1, $2 ); + return -1 if $m < 1 || $m > 12; + return -1 if $d < 1 || $d > $dim[$m]; + my $dayno = 0; + for( my $i=1; $i<$m; $i++ ) + { + $dayno += $dim[$i]; + } + $dayno += $d; + return $dayno; +} + + +my( $sd1, $ed1, $sd2, $ed2 ) = @ARGV; +my $sd1d = yearday( $sd1 ); # days since start of year for sd1 +die "Bad dd-mm-sd1 ($sd1)\n" if $sd1d<1; +my $ed1d = yearday( $ed1 ); +die "Bad dd-mm-ed1 ($ed1)\n" if $ed1d<1; +my $sd2d = yearday( $sd2 ); +die "Bad dd-mm-sd2 ($sd2)\n" if $sd2d<1; +my $ed2d = yearday( $ed2 ); +die "Bad dd-mm-ed2 ($ed2)\n" if $ed2d<1; + +say "sd1:$sd1d, ed1:$ed1d, sd2:$sd2d, ed2:$ed2d"; + + +=pod + +=head2 my $noverlap = overlapdays( $sd1d, $ed1d, $sd2d, $ed2d ); + +Find out the number of overlapping days between the two ranges +of dates, as the task describes. Each date is represented by a logical +day-number-in-the-year. Return 0 if no overlap. + +=cut +fun overlapdays( $sd1d, $ed1d, $sd2d, $ed2d ) +{ + # none if one range finishes before the other + return 0 if $ed1d < $sd2d || $ed2d < $sd1d; + + my $csd = max($sd1d,$sd2d); # common start date + my $ced = min($ed1d,$ed2d); # common end date + + return 1+$ced-$csd; +} + + +my $noverlap = overlapdays( $sd1d, $ed1d, $sd2d, $ed2d ); +say "$noverlap days"; diff --git a/challenge-187/duncan-c-white/perl/ch-2.pl b/challenge-187/duncan-c-white/perl/ch-2.pl new file mode 100755 index 0000000000..04e0ffe055 --- /dev/null +++ b/challenge-187/duncan-c-white/perl/ch-2.pl @@ -0,0 +1,114 @@ +#!/usr/bin/perl +# +# Task 2: Magical Triplets +# +# You are given a list of positive numbers, @n, having at least 3 numbers. +# +# Write a script to find the triplets (a, b, c) from the given list that +# satisfies the following rules. +# +# 1. a + b > c +# 2. b + c > a +# 3. a + c > b +# 4. a + b + c is maximum. +# +# In case, you end up with more than one triplets having the maximum then +# pick the triplet where a >= b >= c. +# +# Example 1 +# +# Input: @n = (1, 2, 3, 2); +# Output: (3, 2, 2) +# +# Ex |
