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 /challenge-179 | |
| 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..
Diffstat (limited to 'challenge-179')
| -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 |
8 files changed, 674 insertions, 35 deletions
diff --git a/challenge-179/duncan-c-white/C/.cbuild b/challenge-179/duncan-c-white/C/.cbuild index aebcd2040a..624a95ebfb 100644 --- a/challenge-179/duncan-c-white/C/.cbuild +++ b/challenge-179/duncan-c-white/C/.cbuild @@ -1,3 +1,4 @@ -BUILD = ch-1 ch-2 +BUILD = ch-1 CFLAGS = -Wall -g +#LDFLAGS = -lm #CFLAGS = -g diff --git a/challenge-179/duncan-c-white/C/Makefile b/challenge-179/duncan-c-white/C/Makefile new file mode 100644 index 0000000000..3574b1eed4 --- /dev/null +++ b/challenge-179/duncan-c-white/C/Makefile @@ -0,0 +1,12 @@ +BUILD = ch-1 +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 diff --git a/challenge-179/duncan-c-white/C/README b/challenge-179/duncan-c-white/C/README new file mode 100644 index 0000000000..12ccf8a6e3 --- /dev/null +++ b/challenge-179/duncan-c-white/C/README @@ -0,0 +1,8 @@ +Thought I'd also have a go at translating ch-1.pl into C.. + +ch-1.c produces identical (non-debugging) output to my Perl originals. + +It uses the command-line argument processing module args.[ch]. + +It was 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-179/duncan-c-white/C/args.c b/challenge-179/duncan-c-white/C/args.c new file mode 100644 index 0000000000..d4a2d38b9a --- /dev/null +++ b/challenge-179/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-179/duncan-c-white/C/args.h b/challenge-179/duncan-c-white/C/args.h new file mode 100644 index 0000000000..8844a8f9c4 --- /dev/null +++ b/challenge-179/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-179/duncan-c-white/C/ch-1.c b/challenge-179/duncan-c-white/C/ch-1.c new file mode 100644 index 0000000000..8b51c26db2 --- /dev/null +++ b/challenge-179/duncan-c-white/C/ch-1.c @@ -0,0 +1,261 @@ +// +// Task 1: Ordinal Number Spelling +// +// C version. +// + +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> +#include <ctype.h> +#include <assert.h> + +#include "args.h" + + +// rules to deal with "formwords".. + +char *oneto19[] = { + "one", "two", "three", "four", "five", "six", "seven", "eight", + "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", + "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" + }; + +char *tens[] = { + "twenty", "thirty", "forty", "fifty", "sixty", "seventy", + "eighty", "ninety" + }; + + +// char words[1000]; +// inner_formwords( n, words ); +// Generate the English form of n, writing it into words. +// eg if n=17, set words to "seventeen". +void inner_formwords( int n, char *words ) +{ + if( n < 20 ) + { + strcpy( words, oneto19[n-1] ); + return; + } + + if( n < 100 ) + { + char *t = tens[n/10-2]; + if( debug ) + { + printf( "debug: n=%d, tens=%s\n", n, t ); + } + strcpy( words, t ); + if( n % 10 != 0 ) + { + strcat( words, "-" ); + strcat( words, oneto19[n%10-1] ); + } + return; + } + + if( n < 1000 ) + { + int mod = n%100; + n /= 100; + strcpy( words, oneto19[n-1] ); + strcat( words, "-hundred" ); + if( mod != 0 ) + { + strcat( words, "-and-" ); + inner_formwords( mod, words+strlen(words) ); + } + return; + } + + if( n < 1000000 ) + { + int mod = n%1000; + n /= 1000; + inner_formwords( n, words ); + strcat( words, "-thousand" ); + if( mod != 0 ) + { + strcat( words, "-and-" ); + inner_formwords(mod, words+strlen(words) ); + } + return; + } +} + + +// remove_extra_ands( words ); +// If the string words contains more than one "-and-", +// remove excess "and-"s leaving only the last. +// +void remove_extra_ands( char *words ) +{ + for(;;) + { + // locate the first -and-, if any + char *fst = strstr( words, "-and-" ); + if( fst == NULL ) return; + + // locate the second -and-, if any + char *snd = strstr( fst+1, "-and-" ); + if( snd == NULL ) return; + + if( debug ) + { + printf( "found two -and-s in %s\n", words ); + } + + // remove the first + char *d = fst+1; + for( char *s = fst+5; *s; *d++ = *s++ ) + { + /*EMPTY*/ + } + *d = '\0'; + + if( debug ) + { + printf( "removed the first leaving %s\n", words ); + } + + } +} + + +// +// char words[1000]; +// formwords( n, words ); +// Generate the English form of n, writing it into words, +// checking the range of n, and removing surplus "-and-"s. +// eg if n=17, set words to "seventeen". +// +void formwords( int n, char *words ) +{ + if( n < 1 ) + { + fprintf( stderr, "formwords: n (%d) must be > 0\n", n ); + exit(1); + } + if( n >= 1000000 ) + { + fprintf( stderr, "formwords: n (%d) must be < 1000000\n", n ); + exit(1); + } + + inner_formwords( n, words ); + + remove_extra_ands( words ); +} + + +// rules to do with "nth" logic + +// a useful type.. +typedef struct { char *from; char *to; } pair; + + +// special cases, eg "one" -> "first".. +pair special[] = { + { "one", "first" }, + { "two", "second" }, + { "three", "third" }, + { "five", "fifth" }, + { "eight", "eighth" }, + { "twelve", "twelfth" }, +}; + + +#define NSPECIALS (sizeof(special)/sizeof(special[0])) + + +// +// char *spec = lookup_special( word ); +// Lookup word to see if it's special; +// return NULL if it's not, or the equivalent +// of the special word if it is. +// +char *lookup_special( char *word ) +{ + for( int i=0; i < NSPECIALS; i++ ) + { + if( strcmp( special[i].from, word ) == 0 ) + { + return special[i].to; + } + } + return NULL; +} + + +// +// char words[1000]; +// nth( n, words ); +// Generate the "nth" English form of n in words, +// eg if n=17, set words to "seventeenth". Do it using formwords() +// and then mucking about with the ending.. +// +void nth( int n, char *words ) +{ + formwords( n, words ); + + char *dash = strchr( words, '-' ); + char prefix[1000]; + char lastbit[1000]; + + if( dash != NULL ) + { + *dash = '\0'; + strcpy( prefix, words ); + strcpy( lastbit, dash+1 ); + } else + { + strcpy( prefix, "" ); + strcpy( lastbit, words ); + } + + char *spec = lookup_special( lastbit ); + if( spec != NULL ) + { + strcpy( lastbit, spec ); + } + else + { + char *last = lastbit+strlen(lastbit)-1; + if( *last == 'y' ) + { + strcpy( last, "ie" ); + } + strcat( lastbit, "th" ); + } + + if( *prefix != '\0' ) + { + sprintf( words, "%s-%s", prefix, lastbit ); + } else + { + strcpy( words, lastbit ); + } +} + + +int main( int argc, char **argv ) +{ + int argno = process_flag_n_args( "nth", argc, argv, + 1, "N (0..999999)" ); + char *arg = argv[argno]; // N + + int n; + if( !check_unsigned_int(arg,&n) ) + { + fprintf( stderr, "nth: arg %s must be +int\n", arg ); + exit(1); + } + char words[1000]; + //formwords( n, words ); + nth( n, words ); + //printf( "n=%d, word=%s\n", n, words ); + printf( "%s\n", words ); + return 0; +} diff --git a/challenge-179/duncan-c-white/README b/challenge-179/duncan-c-white/README index 500870a343..635f772de2 100644 --- a/challenge-179/duncan-c-white/README +++ b/challenge-179/duncan-c-white/README @@ -1,46 +1,29 @@ -Task 1: Permuted Multiples +Task 1: Ordinal Number Spelling -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. +You are given a positive number, $n. +Write a script to spell the ordinal number. -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 +11 => eleventh +62 => sixty-second +99 => ninety-ninth -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: ok, sounds pretty easy for n>0; let's arbitrarily deal with +n < 1000000 (although millions, billions etc would be pretty easy to add). +Let's do this via formwords(n) which converts (eg) n=17 to "seventeen" and +then use that to generate the final "seventeeth" (nth, ordinal, form) by +mucking about with the ending (and using some special case rules for English, +eg mapping one->first) 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 - -Write a script to find out all Reversible Numbers below 100. +Task 2: Unicode Sparkline -A number is said to be a reversible if sum of the number and its reverse -had only odd digits. +You are given a list of positive numbers, @n. -For example, +Write a script to print sparkline in Unicode for the given list of numbers. -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. - -Output - -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: Unusually, this seems even easier than task 1. - -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 NOTES: What on earth is "sparkline"? Not a fan of Unicode either, forget it. diff --git a/challenge-179/duncan-c-white/perl/ch-1.pl b/challenge-179/duncan-c-white/perl/ch-1.pl new file mode 100755 index 0000000000..4a343ffb73 --- /dev/null +++ b/challenge-179/duncan-c-white/perl/ch-1.pl @@ -0,0 +1,156 @@ +#!/usr/bin/perl +# +# Task 1: Ordinal Number Spelling +# +# You are given a positive number, $n. +# Write a script to spell the ordinal number. +# +# For example, +# +# 11 => eleventh +# 62 => sixty-second +# 99 => ninety-ninth +# +# MY NOTES: ok, sounds pretty easy for n>0; let's arbitrarily deal with +# n < 1000000 (although millions, billions etc would be pretty easy to add). +# Let's do this via formwords(n) which converts (eg) n=17 to "seventeen" and +# then use that to generate the final "seventeeth" by mucking about with the +# ending (and using some special case rules for English, eg one->first) +# +# 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: nth [--debug] N\n" + unless GetOptions( "debug"=>\$debug ) && @ARGV==1; + + +# rules to deal with "formwords".. + +my @oneto19 = qw(one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen); +my @tens = qw(twenty thirty forty fifty sixty seventy eighty ninety); + + +# +# my $count = formwords( $n ); +# Generate and return the English form of $n, +# eg if n=17, return "seventeen". +# +fun formwords( $n ) +{ + die "formwords: n ($n) must be > 0\n" if $n<1; + + my $count = inner_formwords( $n ); + + # let's have no more than one "-and-".. + $count =~ s/and-// while $count =~ /-and-.*-and-/; + + return $count; +} + + +# +# my $count = inner_formwords( $n ); +# Generate and return the English form of $n, +# eg if n=17, return "seventeen". +# +fun inner_formwords( $n ) +{ + die "formwords: n ($n) must be > 0\n" if $n<1; + return $oneto19[$n-1] if $n<20; + if( $n < 100 ) + { + my $tens = $tens[int($n/10)-2]; + say "debug: n=$n, tens=$tens" if $debug; + if( $n % 10 == 0 ) + { + return $tens; + } + my $units = $oneto19[$n%10-1]; + return "$tens-$units"; + } + if( $n < 1000 ) + { + my $mod = $n%100; + $n = int($n/100); + my $hundreds = $oneto19[$n-1]; + return "$hundreds-hundred" if $mod==0; + my $fw = inner_formwords($mod); + return "$hundreds-hundred-and-$fw"; + } + if( $n < 1000000 ) + { + my $mod = $n%1000; + $n = int($n/1000); + my $thousands = inner_formwords($n); + my $result = "$thousands-thousand"; + return $result if $mod==0; + + $result .= "-and-". inner_formwords($mod); + return $result; + } + return "$n >= 1000000 to do"; +} + + +my %special = qw(one first two second three third five fifth + eight eighth twelve twelfth); + +# +# my $nth = nth( $n ); +# Generate and return the "nth" English form of $n, +# eg if n=17, return "seventeenth". Do it using formwords() +# and then mucking about with the ending.. +# +fun nth( $n ) +{ + my $fw = formwords( $n ); + + my( $prefix, $lastbit ); + if( $fw =~ /^(.+)-([^-]+)$/ ) + { + $prefix = $1; + $lastbit = $2; + } else + { + $prefix = ""; + $lastbit = $fw; + } + + if( defined $special{$lastbit} ) + { + $lastbit = $special{$lastbit}; + } + else + { + $lastbit =~ s/y$/ie/; + $lastbit .= "th"; + } + + if( $prefix ) + { + return "$prefix-$lastbit"; + } else + { + return $lastbit; + } +} + + + +my $n = shift; +die "nth: n ($n) must be > 0 and < 1,000,000\n" if $n<=0 || $n>1000000; + +#my $count = formwords( $n ); +#say $count; +my $nth = nth($n); +say $nth; |
