diff options
| -rw-r--r-- | challenge-194/duncan-c-white/C/.cbuild | 2 | ||||
| -rw-r--r-- | challenge-194/duncan-c-white/C/Makefile | 16 | ||||
| -rw-r--r-- | challenge-194/duncan-c-white/C/README | 7 | ||||
| -rw-r--r-- | challenge-194/duncan-c-white/C/args.c | 207 | ||||
| -rw-r--r-- | challenge-194/duncan-c-white/C/args.h | 11 | ||||
| -rw-r--r-- | challenge-194/duncan-c-white/C/ch-1.c | 140 | ||||
| -rw-r--r-- | challenge-194/duncan-c-white/C/ch-2.c | 73 | ||||
| -rw-r--r-- | challenge-194/duncan-c-white/README | 90 | ||||
| -rwxr-xr-x | challenge-194/duncan-c-white/perl/ch-1.pl | 99 | ||||
| -rwxr-xr-x | challenge-194/duncan-c-white/perl/ch-2.pl | 78 |
10 files changed, 675 insertions, 48 deletions
diff --git a/challenge-194/duncan-c-white/C/.cbuild b/challenge-194/duncan-c-white/C/.cbuild index 624a95ebfb..a14ec76520 100644 --- a/challenge-194/duncan-c-white/C/.cbuild +++ b/challenge-194/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-194/duncan-c-white/C/Makefile b/challenge-194/duncan-c-white/C/Makefile new file mode 100644 index 0000000000..8d85c7d16d --- /dev/null +++ b/challenge-194/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-194/duncan-c-white/C/README b/challenge-194/duncan-c-white/C/README new file mode 100644 index 0000000000..a5adc6cda7 --- /dev/null +++ b/challenge-194/duncan-c-white/C/README @@ -0,0 +1,7 @@ +Thought I'd also have a go at translating ch-1.pl and ch-2.pl into C.. + +Both C versions produce near-identical (non-debugging and even debugging) +output to the Perl originals. + +They use one of my regular support modules: +- a command-line argument processing module args.[ch] diff --git a/challenge-194/duncan-c-white/C/args.c b/challenge-194/duncan-c-white/C/args.c new file mode 100644 index 0000000000..d4a2d38b9a --- /dev/null +++ b/challenge-194/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-194/duncan-c-white/C/args.h b/challenge-194/duncan-c-white/C/args.h new file mode 100644 index 0000000000..8844a8f9c4 --- /dev/null +++ b/challenge-194/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-194/duncan-c-white/C/ch-1.c b/challenge-194/duncan-c-white/C/ch-1.c new file mode 100644 index 0000000000..ed2aa36f06 --- /dev/null +++ b/challenge-194/duncan-c-white/C/ch-1.c @@ -0,0 +1,140 @@ +// +// Task 1: Digital Clock +// +// C version. +// + +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> +#include <ctype.h> +#include <assert.h> + +#include "args.h" + + +int countch(char *str, char ch) +{ + int n=0; + for( ; *str; str++ ) + { + if( *str==ch ) n++; + } + return n; +} + + +// char *errmesg = validate_date( date, &h1, &h2, &m1, &m2 ); +// Validate date <date>, if the date is valid, fill in h1, h2, +// m1 and m2 and return NULL, otherwise return an error message. +char *validate_date( char *date, char *h1, char *h2, char *m1, char *m2 ) +{ + static char err[100]; + if( strlen(date) != 5 ) + { + sprintf( err, "hh:mm %s should be length 5\n", date ); + return err; + } + + int nq = countch(date,'?'); + if( nq != 1 ) + { + sprintf( err, "need 1 '?' in hh:mm str %s, not %d\n", date, nq ); + return err; + } + + if( date[2] != ':' ) + { + sprintf( err, "':' expected in hh:mm str %s\n", date ); + return err; + } + + *h1 = date[0]; + *h2 = date[1]; + *m1 = date[3]; + *m2 = date[4]; + if( *h1!='0' && *h1!='1' && *h1!='2' && *h1!='?' ) + { + sprintf( err, "h1 (%c) should be 0..2 or ?\n", *h1 ); + return err; + } + + if( ! isdigit(*h2) && *h2!='?' ) + { + sprintf( err, "h2 (%c) should be 0..9 or ?\n", *h2 ); + return err; + } + + if( (*m1<'0' || *m1>'5') && *m1!='?' ) + { + sprintf( err, "m1 (%c) should be 0..5 or ?\n", *m1 ); + return err; + } + + if( ! isdigit(*m2) && *m2!='?' ) + { + sprintf( err, "m2 (%c) should be 0..9 or ?\n", *m2 ); + return err; + } + + if( *h1 == '2' && *h2 > '3' && *h2 != '?' ) + { + sprintf( err, "hour %c%c must be 2[0..3]\n", *h1, *h2 ); + return err; + } + + return NULL; +} + + +// +// int n = find_question( h1, h2, m1, m2 ); +// Given h1 (the first hour digit 0,1,2 or ?), +// h2 (the second hour digit, 0-9 or ?), +// m1 (the first minute digit 0-5 or ?) and +// m2 (the second minute digit 0-9 or ?), +// locate the question mark and find and return the maximum value +// that cell could be. Abort if there's no '?' anywhere. +// +int find_question( char h1, char h2, char m1, char m2 ) +{ + if( h1 == '?' ) + { + return ( h2 > '3' ) ? 1 : 2; + } + if( h2 == '?' ) + { + return ( h1 == '2' ) ? 3 : 9; + } + if( m1 == '?' ) return 5; + if( m2 == '?' ) return 9; + fprintf( stderr, "no question mark found in %c%c:%c%c\n", + h1, h2, m1, m2 ); + exit(1); +} + + +int main( int argc, char **argv ) +{ + int argno = process_flag_n_args( "digital-clock", argc, argv, 1, "" ); + char *arg = argv[argno]; + + if( debug ) + { + printf( "debug: arg=%s\n", arg ); + } + + char h1, h2, m1, m2; + char *mesg = validate_date( arg, &h1, &h2, &m1, &m2 ); + if( mesg != NULL ) + { + fprintf( stderr, "digital-clock: %s\n", mesg ); + exit(1); + } + + int result = find_question( h1, h2, m1, m2 ); + printf( "%d\n", result ); + + return 0; +} diff --git a/challenge-194/duncan-c-white/C/ch-2.c b/challenge-194/duncan-c-white/C/ch-2.c new file mode 100644 index 0000000000..251d2ba5fe --- /dev/null +++ b/challenge-194/duncan-c-white/C/ch-2.c @@ -0,0 +1,73 @@ +// +// Task 2: Frequency Equalizer +// +// C version. +// + +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> +#include <ctype.h> +#include <assert.h> + +#include "args.h" + + +static int compn(const void *p1, const void *p2) +{ + // The actual arguments to this function are "pointers to ints" + return (*(int *) p1) - (*(int *) p2); +} + + +int main( int argc, char **argv ) +{ + int argno = process_flag_n_args( "odd-strings", argc, argv, + 1, "string" ); + + if( debug ) + { + printf( "debug: argno=%d, argc=%d\n", argno, argc ); + } + + char *str = argv[argno]; + + if( debug ) + { + printf( "debug: str=%s\n", str ); + } + + // build a freq mapping + int freq[256]; + for( int i=0; i<256; i++ ) + { + freq[i] = 0; + } + for( char *s=str; *s; s++ ) + { + freq[(int)*s]++; + } + + // sort the frequencies + qsort( freq, 256, sizeof(int), &compn ); + + if( debug ) + { + printf( "after sorting: " ); + for( int i=0; i<256; i++ ) + { + if( freq[i] != 0 ) printf( "%d: %d,", i, freq[i] ); + } + putchar('\n'); + } + + // skip over any zeros + int firstnq=0; + for( ; firstnq<256 && freq[firstnq]==0; firstnq++ ) /*EMPTY BODY*/; + + int result = (freq[255] == 1 + freq[254] && freq[firstnq] == freq[254]) ? 1 : 0; + printf( "%d\n", result ); + + return 0; +} diff --git a/challenge-194/duncan-c-white/README b/challenge-194/duncan-c-white/README index e24b328169..f9faa0e5de 100644 --- a/challenge-194/duncan-c-white/README +++ b/challenge-194/duncan-c-white/README @@ -1,75 +1,71 @@ -Task 1: Binary String +Task 1: Digital Clock -You are given an integer, $n > 0. -Write a script to find all possible binary numbers of size $n bits. +You are given time in the format hh:mm with one missing digit. + +Write a script to find the highest digit between 0-9 that makes it valid time. Example 1 -Input: $n = 2 -Output: 00, 11, 01, 10 +Input: $time = '?5:00' +Output: 1 + +Since 05:00 and 15:00 are valid time and no other digits can fit in the +missing place. Example 2 -Input: $n = 3 -Output: 000, 001, 010, 100, 111, 110, 101, 011 +Input: $time = '?3:00' +Output: 2 -MY NOTES: very easy +Example 3 -GUEST LANGUAGE: As a bonus, I also had a go at translating ch-1.pl -into C (look in the C directory for the translation) +Input: $time = '1?:00' +Output: 9 +Example 4 -Task 2: Odd String +Input: $time = '2?:00' +Output: 3 -You are given a list of strings of same length, @s. +Example 5 -Write a script to find the odd string in the given list. Use positional -value of alphabet starting with 0, i.e. a = 0, b = 1, ... z = 25. +Input: $time = '12:?5' +Output: 5 -Find the difference array for each string as shown in the example. Then -pick the odd one out. +Example 6 -Example 1: +Input: $time = '12:5?' +Output: 9 + +MY NOTES: very easy -Input: @s = ("adc", "wzy", "abc") -Output: "abc" +GUEST LANGUAGE: As a bonus, I also had a go at translating ch-1.pl +into C (look in the C directory for the translation) -Difference array for "adc" => [ d - a, c - d ] - => [ 3 - 0, 2 - 3 ] - => [ 3, -1 ] -Difference array for "wzy" => [ z - w, y - z ] - => [ 25 - 22, 24 - 25 ] - => [ 3, -1 ] +Task 2: Frequency Equalizer -Difference array for "abc" => [ b - a, c - b ] - => [ 1 - 0, 2 - 1 ] - => [ 1, 1 ] +You are given a string made of alphabetic characters only, a-z. -The difference array for "abc" is the odd one. +Write a script to determine whether removing only one character can make +the frequency of the remaining characters the same. -Example 2: +Example 1: -Input: @s = ("aaa", "bob", "ccc", "ddd") -Output: "bob" +Input: $s = 'abbc' +Output: 1 since removing one alphabet 'b' will give us 'abc' where each alphabet frequency is the same. -Difference array for "aaa" => [ a - a, a - a ] - => [ 0 - 0, 0 - 0 ] - => [ 0, 0 ] +Example 2: -Difference array for "bob" => [ o - b, b - o ] - => [ 14 - 1, 1 - 14 ] - => [ 13, -13 ] +Input: $s = 'xyzyyxz' +Output: 1 since removing 'y' will give us 'xzyyxz'. -Difference array for "ccc" => [ c - c, c - c ] - => [ 2 - 2, 2 - 2 ] - => [ 0, 0 ] +Example 3: -Difference array for "ddd" => [ d - d, d - d ] - => [ 3 - 3, 3 - 3 ] - => [ 0, 0 ] +Input: $s = 'xzxz' +Output: 0 since removing any one alphabet would not give us string with same frequency alphabet. -The difference array for "bob" is the odd one. +MY NOTES: sounds pretty easy. -MY NOTES: Hmm.. not always a single odd one out. What are we supposed -to do if there is no odd one out? +GUEST LANGUAGE: As a bonus, I also had a go at translating ch-2.pl +into C (look in the C directory for the translation) diff --git a/challenge-194/duncan-c-white/perl/ch-1.pl b/challenge-194/duncan-c-white/perl/ch-1.pl new file mode 100755 index 0000000000..c17510af2d --- /dev/null +++ b/challenge-194/duncan-c-white/perl/ch-1.pl @@ -0,0 +1,99 @@ +#!/usr/bin/perl +# +# Task 1: Digital Clock +# +# You are given time in the format hh:mm with one missing digit. +# +# Write a script to find the highest digit between 0-9 that makes it valid time. +# +# Example 1 +# +# Input: $time = '?5:00' +# Output: 1 +# +# Since 05:00 and 15:00 are valid time and no other digits can fit in the +# missing place. +# +# Example 2 +# +# Input: $time = '?3:00' +# Output: 2 +# +# Example 3 +# +# Input: $time = '1?:00' +# Output: 9 +# +# Example 4 +# +# Input: $time = '2?:00' +# Output: 3 +# +# Example 5 +# +# Input: $time = '12:?5' +# Output: 5 +# +# Example 6 +# +# Input: $time = '12:5?' +# Output: 9 +# +# MY NOTES: very easy, most of it is error checking.. +# +# GUEST LANGUAGE: As a bonus, I also had a go at translating ch-1.pl +# into C (look in the C directory for the translation) +# + +use strict; +use warnings; +use feature 'say'; +use Getopt::Long; +use Data::Dumper; + +my $debug=0; +die "Usage: digital-clock [--debug] hh:mm\n" + unless GetOptions( "debug"=>\$debug ) && @ARGV==1; + +my $time = shift; + +die "digital-clock: time str $time should be length 5\n" + unless length($time)==5; + +die "digital-clock: bad time str $time\n" + unless $time =~ /^([(012?])([0-9?]):([0-5?])([0-9?])$/; + +my( $h1, $h2, $m1, $m2 ) = ( $1, $2, $3, $4 ); + +my $tmp = $time; +my $nq = $tmp =~ tr/?//d; +die "digital-clock: need a single '?' in time str $time, not $nq\n" + unless $nq==1; + +die "digital-clock: bad time str $time\n" + if $h1 eq '2' && $h2 gt '3' && $h2 ne '?'; + +=pod + +=head2 my $result = find_question( $h1, $h2, $m1, $m2 ); + +Given h1 (the first hour digit 0,1,2 or ?), +h2 (the second hour digit, 0-9 or ?), +m1 (the first minute digit 0-5 or ?) and +m2 (the second minute digit 0-9 or ?), +locate the question mark and find and return the maximum value +that cell could be. Abort if there's no '?' anywhere. + +=cut +sub find_question +{ + my( $h1, $h2, $m1, $m2 ) = @_; + return ( $h2 gt '3' ) ? 1 : 2 if $h1 eq '?'; + return ( $h1 eq '2' ) ? 3 : 9 if $h2 eq '?'; + return 5 if $m1 eq '?'; + return 9 if $m2 eq '?'; + die "no question mark found in $h1$h2:$m1$m2\n"; +} + +my $result = find_question( $h1, $h2, $m1, $m2 ); +say $result; diff --git a/challenge-194/duncan-c-white/perl/ch-2.pl b/challenge-194/duncan-c-white/perl/ch-2.pl new file mode 100755 index 0000000000..5cbf9366aa --- /dev/null +++ b/challenge-194/duncan-c-white/perl/ch-2.pl @@ -0,0 +1,78 @@ +#!/usr/bin/perl +# +# Task 2: Frequency Equalizer +# +# You are given a string made of alphabetic characters only, a-z. +# +# Write a script to determine whether removing only one character can make +# the frequency of the remaining characters the same. +# +# Example 1: +# +# Input: $s = 'abbc' +# Output: 1 since removing one alphabet 'b' will give us 'abc' where each alphabet frequency is the same. +# +# Example 2: +# +# Input: $s = 'xyzyyxz' +# Output: 1 since removing 'y' will give us 'xzyyxz'. +# +# Example 3: +# +# Input: $s = 'xzxz' +# Output: 0 since removing any one alphabet would not give us string with same frequency alphabet. +# +# MY NOTES: sounds pretty easy. +# +# GUEST LANGUAGE: As a bonus, I also had a go at translating ch-2.pl +# into C (look in the C directory for the translation) +# + +use strict; +use warnings; +use feature 'say'; +use Getopt::Long; +use Function::Parameters; +use Data::Dumper; + + +my $debug=0; +die "Usage: freq-eq [--debug] string\n" + unless GetOptions( "debug"=>\$debug ) && @ARGV==1; + +my $str = shift; + +my @let = split( //, $str ); + +# build the frequency hash +my %freq; +foreach my $l (@let) +{ + $freq{$l}++; +} + +# sort the frequency hash +my @sortf = map { $freq{$_} } sort { $freq{$a} <=> $freq{$b} } keys %freq; + +say "sorted freqs are: ", join(',', @sortf ) if $debug; + +=pod + +=head2 my $ok = can_eq( @sortedfreqs ); + +Given a sorted array of letter frequencies, +remove 1 iff the biggest frequency is 1+the 2nd biggest freq +and the smallest freq is the same as the 2nd biggest freq; +return 0 otherwise. + +=cut +fun can_eq( @sf ) +{ + my $lastf = $#sf; + return 1 if $sf[$lastf] == 1 + $sf[$lastf-1] && + $sf[0] == $sf[$lastf-1]; + return 0; +} + + +say can_eq(@sortf); |
