diff options
| author | Mohammad S Anwar <Mohammad.Anwar@yahoo.com> | 2022-08-29 03:32:55 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-08-29 03:32:55 +0100 |
| commit | 2d82d2a1032c93c841e80477dc45b035a5415ea4 (patch) | |
| tree | 25f9e2dbd483a3aeb770685040b51a2d7512ffe7 | |
| parent | 3a5015eee8152b69d7746bb0bba8451e49448c00 (diff) | |
| parent | 023cace3dc87483c840617e2a2a85df30d2c2817 (diff) | |
| download | perlweeklychallenge-club-2d82d2a1032c93c841e80477dc45b035a5415ea4.tar.gz perlweeklychallenge-club-2d82d2a1032c93c841e80477dc45b035a5415ea4.tar.bz2 perlweeklychallenge-club-2d82d2a1032c93c841e80477dc45b035a5415ea4.zip | |
Merge pull request #6662 from dcw803/master
imported my belated attempt at challenge 178, still away last week..
| -rw-r--r-- | challenge-178/duncan-c-white/C/.cbuild | 3 | ||||
| -rw-r--r-- | challenge-178/duncan-c-white/C/Makefile | 14 | ||||
| -rw-r--r-- | challenge-178/duncan-c-white/C/README | 12 | ||||
| -rw-r--r-- | challenge-178/duncan-c-white/C/args.c | 207 | ||||
| -rw-r--r-- | challenge-178/duncan-c-white/C/args.h | 11 | ||||
| -rw-r--r-- | challenge-178/duncan-c-white/C/ch-1.c | 294 | ||||
| -rw-r--r-- | challenge-178/duncan-c-white/C/ch-2a.c | 242 | ||||
| -rw-r--r-- | challenge-178/duncan-c-white/README | 67 | ||||
| -rwxr-xr-x | challenge-178/duncan-c-white/perl/ch-1.pl | 171 | ||||
| -rwxr-xr-x | challenge-178/duncan-c-white/perl/ch-2.pl | 62 | ||||
| -rwxr-xr-x | challenge-178/duncan-c-white/perl/ch-2a.pl | 187 | ||||
| -rw-r--r-- | challenge-179/duncan-c-white/C/.cbuild | 3 | ||||
| -rw-r--r-- | challenge-179/duncan-c-white/C/Makefile | 12 | ||||
| -rw-r--r-- | challenge-179/duncan-c-white/C/README | 8 | ||||
| -rw-r--r-- | challenge-179/duncan-c-white/C/args.c | 207 | ||||
| -rw-r--r-- | challenge-179/duncan-c-white/C/args.h | 11 | ||||
| -rw-r--r-- | challenge-179/duncan-c-white/C/ch-1.c | 261 | ||||
| -rw-r--r-- | challenge-179/duncan-c-white/README | 51 | ||||
| -rwxr-xr-x | challenge-179/duncan-c-white/perl/ch-1.pl | 156 |
19 files changed, 1915 insertions, 64 deletions
diff --git a/challenge-178/duncan-c-white/C/.cbuild b/challenge-178/duncan-c-white/C/.cbuild index aebcd2040a..78560d4ced 100644 --- a/challenge-178/duncan-c-white/C/.cbuild +++ b/challenge-178/duncan-c-white/C/.cbuild @@ -1,3 +1,4 @@ -BUILD = ch-1 ch-2 +BUILD = ch-1 ch-2a CFLAGS = -Wall -g +#LDFLAGS = -lm #CFLAGS = -g diff --git a/challenge-178/duncan-c-white/C/Makefile b/challenge-178/duncan-c-white/C/Makefile new file mode 100644 index 0000000000..be7b4f9d29 --- /dev/null +++ b/challenge-178/duncan-c-white/C/Makefile @@ -0,0 +1,14 @@ +BUILD = ch-1 ch-2a +CC = gcc +CFLAGS = -Wall -g +#LDLIBS = -lm + +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-2a: ch-2a.o args.o +ch-2a.o: ch-2a.c args.h diff --git a/challenge-178/duncan-c-white/C/README b/challenge-178/duncan-c-white/C/README new file mode 100644 index 0000000000..b79f2ee9cb --- /dev/null +++ b/challenge-178/duncan-c-white/C/README @@ -0,0 +1,12 @@ +Thought I'd also have a go at translating ch-1.pl and ch-2.c into C.. + +Both ch-1.c and ch-2.c produce identical (non-debugging) output to my +Perl originals. + +Both use the command-line argument processing module args.[ch]. +I translated IsPrime.pm to isprime.[ch], and wrote an array printing +function in prarray.[ch]. + +Both tasks were very straightforward to translate, it's just that +we have to write a lot more low-level support code that Perl does +for us.. diff --git a/challenge-178/duncan-c-white/C/args.c b/challenge-178/duncan-c-white/C/args.c new file mode 100644 index 0000000000..d4a2d38b9a --- /dev/null +++ b/challenge-178/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-178/duncan-c-white/C/args.h b/challenge-178/duncan-c-white/C/args.h new file mode 100644 index 0000000000..8844a8f9c4 --- /dev/null +++ b/challenge-178/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-178/duncan-c-white/C/ch-1.c b/challenge-178/duncan-c-white/C/ch-1.c new file mode 100644 index 0000000000..a3ad9aee2e --- /dev/null +++ b/challenge-178/duncan-c-white/C/ch-1.c @@ -0,0 +1,294 @@ +// +// Task 1: Quater-imaginary Base conversion +// +// C version. +// + +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> +#include <ctype.h> +#include <assert.h> + +#include "args.h" + +#define BUFSIZE 100 + + +// +// reverse( str ); +// reverse str in place +void reverse( char *str ) +{ + char *p = str + strlen(str) - 1; + for( char *q=str; q<p; q++, p-- ) + { + char t = *p; + *p = *q; + *q = t; + } +} + + +// +// char b4str[BUFSIZE]; +// convert_to_base_neg4( x, b4str ); +// Convert +int x to base -4, storing the base-4 numeral into b4str. +// +void convert_to_base_neg4( int x, char *b4str ) +{ + int origx = x; + *b4str = '\0'; + char *p = b4str; + while( abs(x)>0 ) + { + int d = x/-4; + int m = x + 4*d; + if( m < 0 ) + { + m += 4; + d++; + } + if( debug ) + { + printf( "debug: c_t_b-4(%d): x=%d, d=%d, m=%d\n", + origx, x, d, m ); + } + *p++ = m+'0'; + x = d; + } + *p = '\0'; + + if( p == b4str ) + { + *p++ = '0'; + *p = '\0'; + } + + reverse( b4str ); + + if( debug ) + { + printf( "debug: c_t_b-4(%d): result = %s\n", origx, b4str ); + } +} + + +// +// my $qistr = convert_to( $n ); +// Convert +int $n to q-i, return the q-i numeral. +// +// char qistr[BUFSIZE]; +// convert_to( x, qistr ); +// Convert +int x to qi base, storing the qi numeral into qistr. +// +void convert_to( int x, char *qistr ) +{ + char b4str[BUFSIZE]; + convert_to_base_neg4( x, b4str ); + + if( debug ) + { + printf( "debug: to(%d) base-4 = %s\n", x, b4str ); + } + + // copy the b4str to qistr, adding '0' between every pair of digits + char *s = b4str; + char *d=qistr; + + *d++ = *s++; + + for( ; *s; s++ ) + { + *d++ = '0'; + *d++ = *s; + } +} + + +// +// int n = convert_from_base_neg4( char *bstr ); +// Given bstr, a base -4 numeral representing a +int, +// return that int. +// +int convert_from_base_neg4( char *bstr ) +{ + int n = 0; + int currpow = 1; + int len = strlen(bstr)-1; + for( char *p= bstr+len; p>=bstr; p-- ) + { + int d = *p-'0'; + if( debug ) + { + printf( "debug: c_f_b-4(%s): digit %d, currpow %d, " + "n %d\n", bstr, d, currpow, n ); + } + n += d * currpow; + currpow *= -4; + } + if( debug ) + { + printf( "debug: c_f_b-4(%s): result is %d\n", bstr, n ); + } + return n; +} + + +// +// int n = convert_from( char *qinum ); +// Given a q-i numeral qinum (a string using only digits 0..3), +// convert it from q-i to a plain +int. +// +int convert_from( char *qinum ) +{ + char bstr[BUFSIZE]; + + // convert qinum into a base -4 string, checking that the + // imaginary columns in qinum are all 0 as we go. + *bstr = '\0'; + bool odd = false; + char *d = bstr; + char *s; + for( s = qinum; *s; s++ ) /*EMPTY*/; + s--; + for( ; s>=qinum; s-- ) + { + char dig = *s; + if( odd ) + { + if( dig != '0' ) + { + fprintf( stderr, "convert_from( %s ): digit %c" + " should be zero\n", qinum, dig ); + exit(1); + } + } else + { + *d++ = dig; + } + odd = !odd; + } + *d = '\0'; + if( bstr[0] == '\0' ) + { + bstr[0] = '0'; + bstr[1] = '\0'; + } + + reverse( bstr ); + + if( debug ) + { + printf( "debug: cf(%s), bstr = %s\n", qinum, bstr ); + } + + // now convert that.. + return convert_from_base_neg4( bstr ); +} + + +// +// bool ok = validate_all0to3( val ); +// Return true iff val only contains [0-3] digits. +// +bool validate_all0to3( char *val ) +{ + int bad=0; + for( char *p=val; *p; p++ ) + { + if( *p < '0' || *p > '3' ) bad++; + } + return bad==0; +} + + +int main( int argc, char **argv ) +{ + int argno = process_flag_n_args( "quater-imaginary-base", argc, argv, + 2, "to/tobase-4/from/frombase-4/check val" ); + char *dir = argv[argno++]; // to/tobase-4/from/frombase-4/check + char *val = argv[argno]; // value string (either +int or qistr) + + if( strcmp( dir, "to" ) == 0 ) + { + int n; + if( !check_unsigned_int(val,&n) ) + { + fprintf( stderr, "quater-imaginary-base: to %s: " + "must be +int\n", val ); + exit(1); + } + if( debug ) + { + printf( "debug: to(%d)\n", n ); + } + char cistr[BUFSIZE]; + convert_to( n, cistr ); + printf( "%s\n", cistr ); + } else if( strcmp( dir, "tobase-4" ) == 0 ) + { + int n; + if( !check_unsigned_int(val,&n) ) + { + fprintf( stderr, "quater-imaginary-base: tobase-4 " + "%s: must be +int\n", val ); + exit(1); + } + if( debug ) + { + printf( "debug: to(%d)\n", n ); + } + char b4str[BUFSIZE]; + convert_to_base_neg4( n, b4str ); + printf( "%s\n", b4str ); + } else if( strcmp( dir, "from" ) == 0 ) + { + bool ok = validate_all0to3( val ); + if( !ok ) + { + fprintf( stderr, "quater-imaginary-base: from %s: " + "all digits must be 0..3\n", val ); + exit(1); + } + int n = convert_from( val ); + printf( "qi value %s = %d\n", val, n ); + } else if( strcmp( dir, "frombase-4" ) == 0 ) + { + bool ok = validate_all0to3( val ); + if( !ok ) + { + fprintf( stderr, "quater-imaginary-base: frombase-4 " + "%s: all digits must be 0..3\n", val ); + exit(1); + } + int n = convert_from_base_neg4( val ); + printf( "base -4 value %s = %d\n", val, n ); + } else if( strcmp( dir, "check" ) == 0 ) + { + int n; + if( !check_unsigned_int(val,&n) ) + { + fprintf( stderr, "quater-imaginary-base: check %s: " + "must be +int\n", val ); + exit(1); + } + printf( "checking first %d conversions back-convert ok\n", n ); + for( int x=0; x<n; x++ ) + { + char cistr[BUFSIZE]; + convert_to( x, cistr ); + //printf( "%s\n", cistr ); + + int back = convert_from( cistr ); + assert( x==back ); + } + } else + { + fprintf( stderr, "quater-imaginary-base: direction %s must " + "be to/tobase-4/from/frombase-4/check\n", dir ); + exit(1); + } + return 0; +} diff --git a/challenge-178/duncan-c-white/C/ch-2a.c b/challenge-178/duncan-c-white/C/ch-2a.c new file mode 100644 index 0000000000..96f56386a0 --- /dev/null +++ b/challenge-178/duncan-c-white/C/ch-2a.c @@ -0,0 +1,242 @@ +// +// Task 2: Business Date +// +// C version. +// + +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> + +#define __USE_XOPEN +#include <time.h> + +#include "args.h" + + +#define STARTHOUR 9 +#define ENDHOUR 18 +// experimented with much shorter day: #define STARTHOUR 14 +// experimented with much shorter day: #define ENDHOUR 17 + +#define DAYLEN (ENDHOUR - STARTHOUR) + + +// +// bool ok = is_business_day_and_time( date ); +// Given a date object date, return 1 iff date is a business day +// and within business hours, else return 0. +// +bool is_business_day_and_time( struct tm date ) +{ + int dow = date.tm_wday; + if( debug ) + { + printf( "debug ibdt: dow=%d\n", dow ); + } + if( dow<1 || dow>5 ) return false; + + int h = date.tm_hour; + int m = date.tm_min; + if( debug ) + { + printf( "debug ibdt: h=%d, m=%d\n", h, m ); + } + if( h >= STARTHOUR && h < ENDHOUR ) return true; + if( h == ENDHOUR && m == 0 ) return true; + return false; +} + + +// +// double rem = remainder_of_business_day( h, m ); +// Given a time (hour h, minute m) that is within working hours, +// return the (real) number of hours remaining in that business day. +// +double remainder_of_business_day( int h, int m ) +{ + double t = h + ((double)m) / 60; + return ENDHOUR - t; +} + + +// +// next_business_day( &date ); +// Move date to the next business day. +// +void next_business_day( struct tm *date ) +{ + + int dow = date->tm_wday; + if( debug ) + { + printf( "debug nbd: dow=%d\n", dow ); + } + + do + { + // move to next physical day + date->tm_mday++; + date->tm_isdst = -1; + mktime( date ); + //dow = date->tm_wday; + dow++; + if( dow==7 ) dow = 0; + } while( dow < 1 || dow > 5 ); + if( debug ) + { + char buf[255]; + strftime( buf, sizeof(buf), "%a %d %b %Y %H:%M", date ); + printf( "debug nbd: nbd=%s\n", buf ); + } +} + + +// +// add_business_duration( &date, duration ); +// Add a +ve duration duration (real, business hours) to the given date, +// modifying the resultant date. This must skip from ENDHOUR:00 to +// STARTHOUR:00 on the next business day, where necessary. +// +void add_business_duration( struct tm *date, double duration ) +{ + int h = date->tm_hour; + int m = date->tm_min; + if( debug ) + { + printf( "debug abd: h=%d, m=%d\n", h, m ); + } + + double rem = remainder_of_business_day( h, m ); + if( debug ) + { + printf( "debug abd: remainder of busday: %g hours\n", rem ); + } + + if( duration <= rem ) + { + int id = duration; + int md = (int)((duration-(double)id)*60.0); + if( debug ) + { + printf( "debug abd: duration=%g, id=%d, md=%d\n", + duration, id, md ); + } + + h += id; + m += md; + if( m > 60 ) + { + m -= 60; + h++; + } + date->tm_hour = h; + date->tm_min = m; + } else + { + // duration goes onto another day; move to end of the day + duration -= rem; + + int id = duration; + int md = (int)((duration-(double)id)*60.0); + if( debug ) + { + printf( "debug abd: remaining duration=%g, id=%d, md=%d\n", + duration, id, md ); + } + + // now advance date to next business day + next_business_day( date ); + + // now advance business days while id>=daylen + while( id >= DAYLEN ) + { + next_business_day( date ); + id -= DAYLEN; + } + + int y = date->tm_year; + int mon = date->tm_mon; + int d = date->tm_mday; + if( debug ) + { + printf( "debug abd: next business day y=%d, m=%d, " + "d=%d, duration=%g, id=%d, md=%d\n", y, mon, d, + duration, id, md ); + } + + h = date->tm_hour = STARTHOUR + id; + m = date->tm_min = md; + if( debug ) + { + printf( "debug abd: time = %02d:%02d\n", h, m ); + } + } +} + + +int main( int argc, char **argv ) +{ + int argno = process_flag_n_args( "business-date", argc, argv, + 2, "datetime duration" ); + char *dt = argv[argno++]; + char *duration = argv[argno]; + + struct tm datetime; + memset( &datetime, 0, sizeof(struct tm) ); + datetime.tm_min = -1; + char *result = strptime( dt, "%Y-%m-%d %H:%M", &datetime ); + if( datetime.tm_min == -1 || (result != NULL && *result != '\0') ) + { + fprintf( stderr, "business-date: can't parse datetime %s\n", dt ); + exit(1); + } + if( ! is_business_day_and_time( datetime ) ) + { + fprintf( stderr, "business-date: date %s - is " + "not a business day/time\n", dt ); + exit(1); + } + + char buf[255]; + + #if 0 + strftime( buf, sizeof(buf), "%a %d %b %Y %H:%M", &datetime ); + printf( "validated date/time: %s\n", buf); + #endif + + double dur; + if( ! check_unsigned_real( duration, &dur ) ) + { + fprintf( stderr, "business-date: can't parse duration %s\n", + duration ); + exit(1); + } + #if 0 + printf( "duration: %g hours\n", dur ); + #endif + + #if 0 + int h = datetime.tm_hour; + int m = datetime.tm_min; + double rem = remainder_of_business_day( h, m ); + printf( "remainder of busday: %g hours\n", rem ); + #endif + + #if 0 + next_business_day( &datetime ); + strftime( buf, sizeof(buf), "%a %d %b %Y %H:%M", &datetime ); + printf( "next bus day date/time: %s\n", buf); + #endif + + if( dur > 0 ) + { + dur += 0.01; // fuzz factor to make rounding work better:-) + add_business_duration( &datetime, dur ); + } + strftime( buf, sizeof(buf), "%a %d %b %Y %H:%M", &datetime ); + printf( "final bus day date/time: %s\n", buf); + + return 0; +} diff --git a/challenge-178/duncan-c-white/README b/challenge-178/duncan-c-white/README index 500870a343..00a9b78b5a 100644 --- a/challenge-178/duncan-c-white/README +++ b/challenge-178/duncan-c-white/README @@ -1,46 +1,57 @@ -Task 1: Permuted Multiples +Task 1: Quater-imaginary Base -Write a script to find the smallest positive integer x such that x, 2x, -3x, 4x, 5x and 6x are permuted multiples of each other. +Write a script to convert a given number (base 10) to quater-imaginary +base number and vice-versa. For more informations, please checkout +the wiki page: https://en.wikipedia.org/wiki/Quater-imaginary_base -For example, the integers 125874 and 251748 are permutated multiples of -each other as - -251784 = 2 x 125874 - -and also both have the same digits but in different order. - -Output +For example, - 142857 +$number_base_10 = 4 +$number_quater_imaginary_base = 10300 -MY NOTES: ok, sounds pretty easy. Compare permutation either by forming -bags of digits and comparing them, or simply by sorting the digits -numerically (a signature) and comparing signatures. +MY NOTES: seriously? base -2i, and for task 1? what was Knuth smoking +in 1960? First, we have to define "number" more carefully. I'm going to +choose "positive integer", because that reduces the problem from base -2i +to base -4 with zeroes between every pair of digits, and that's already +much too horrible for a "task 1". 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: Reversible Numbers +Task 2: Business Date -Write a script to find out all Reversible Numbers below 100. +You are given $timestamp (date with time) and $duration in hours. -A number is said to be a reversible if sum of the number and its reverse -had only odd digits. +Write a script to find the time that occurs $duration business hours +after $timestamp. For the sake of this task, let us assume the working +hours is 9am to 6pm, Monday to Friday. Please ignore timezone too. For example, -36 is reversible number as 36 + 63 = 99 i.e. all digits are odd. -17 is not reversible as 17 + 71 = 88, none of the digits are odd. +Suppose the given timestamp is 2022-08-01 10:30 and the duration is 4 hours: +then the next business date would be 2022-08-01 14:30. -Output +Similar if the given timestamp is 2022-08-01 17:00 and the duration +is 3.5 hours, then the next business date would be 2022-08-02 11:30. -10, 12, 14, 16, 18, 21, 23, 25, 27, -30, 32, 34, 36, 41, 43, 45, 50, 52, -54, 61, 63, 70, 72, 81, 90 +MY NOTES: ok, at least this is more straightforward. We sort of "wrap +around" from date D, time 18:00 to date D+1 time 09:00 (when D is +Mon..Thur), and similarly wrap around from Friday 18:00 to the following +Monday 09:00.. -MY NOTES: Unusually, this seems even easier than task 1. +My first version (ch-2.pl) shows how to cheat using Date::Manip, which +already has a concept of business days which does of the work. -GUEST LANGUAGE: As a bonus, I also had a go at translating ch-2.pl -into C (look in the C directory for that). +My second version (ch-2a.pl) shows an alternative where we do most of the +work ourselves, needing only routines to: + - parse a calendar date and time, and + - move to the next calendar date, and + - determine which day of the week (Mon..Sun, 1..7) a date is + - break a date down into (year, month, day, hour, minutes) + +GUEST LANGUAGE: obviously ch-2.pl could only be translated into C +by translating all the built-in business day logic of Date::Manip +to C as well. But, having effectively done all that in the Perl +universe in ch-2a.pl, I then had a go at translating ch-2a.pl into C +(look in the C directory for that) diff --git a/challenge-178/duncan-c-white/perl/ch-1.pl b/challenge-178/duncan-c-white/perl/ch-1.pl new file mode 100755 index 0000000000..852cfdab45 --- /dev/null +++ b/challenge-178/duncan-c-white/perl/ch-1.pl @@ -0,0 +1,171 @@ +#!/usr/bin/perl +# +# Task 1: Quater-imaginary Base +# +# Write a script to convert a given number (base 10) to quater-imaginary +# base number and vice-versa. For more informations, please checkout +# the wiki page: https://en.wikipedia.org/wiki/Quater-imaginary_base +# +# For example, +# +# $number_base_10 = 4 +# $number_quater_imaginary_base = 10300 +# +# MY NOTES: seriously? base -2i, and for task 1? what was Knuth smoking +# in 1960? First, we have to define "number" more carefully. I'm going to +# choose "positive integer", because that reduces the problem from base -2i +# to base -4 with zeroes between every pair of digits, and that's already +# much too horrible for a "task 1". +# +# 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 Function::Parameters; +use Data::Dumper; + + +my $debug=0; +die "Usage: to-from-quater-imaginary-base [--debug] to|from|check N\n" + unless GetOptions( "debug"=>\$debug ) && @ARGV==2; + +my $dir = shift; # to/from/check.. +my $n = shift; + + +# +# my $b4 = convert_to_base_neg4( $x ); +# Convert +int $x to base -4, return the base-4 numeral. +# +fun convert_to_base_neg4( $x ) +{ + my $origx = $x; + my $b4 = ""; + while( abs($x)>0 ) + { + my $d = int($x/-4); + my $m = $x + 4*$d; + if( $m < 0 ) + { + $m += 4; + $d++; + } + say "debug: c_t_b-4($origx): x=$x, d=$d, m=$m" if $debug; + $b4 .= $m; + $x = $d; + } + $b4 = reverse($b4); + $b4 = '0' if $b4 eq ''; + say "debug: c_t_b-4($origx): result = $b4" if $debug; + return $b4; +} + + +# +# my $qistr = convert_to( $n ); +# Convert +int $n to q-i, return the q-i numeral. +# +fun convert_to( $n ) +{ + my $b4 = convert_to_base_neg4( $n ); + my $str = $b4; + $str =~ s/(\d)/${1}0/g; + chop $str; + return $str; +} + + +# +# my $n = convert_from( $qinum ); +# Given a q-i numeral $qinum (a string using only digits 0..3), +# convert it from q-i to a plain +int. +# +fun convert_from( $qinum ) +{ + my $n = 0; + my $len = length($qinum)-1; + + # convert $qinum into a base -4 string, checking that the + # imaginary columns in $qinum are all 0 as we go. + my $bstr = ""; + for( my $pos=$len; $pos>=0; $pos-- ) + { + my $d = substr($qinum,$pos,1); + if( $pos%2 == 1 ) + { + die "convert_from( $qinum ): digit $d at pos $pos ". + "should be zero\n" unless $d eq '0'; + } else + { + $bstr .= $d; + } + } + $bstr = reverse($bstr); + $bstr = '0' if $bstr eq ''; + say "debug: cf($qinum), bstr = $bstr" if $debug;< |
