aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohammad S Anwar <Mohammad.Anwar@yahoo.com>2022-12-12 00:32:25 +0000
committerGitHub <noreply@github.com>2022-12-12 00:32:25 +0000
commit18e6031dc5adaf4bdf5e140acdea6186ee4ed6ae (patch)
treec8466c802e976cb751544bd576ffad663bbd267e
parentd0b001ade9ea153cd67dec18c0d8126a92fa078f (diff)
parent94204e1f9fc153367776e25c505a85c3da966bae (diff)
downloadperlweeklychallenge-club-18e6031dc5adaf4bdf5e140acdea6186ee4ed6ae.tar.gz
perlweeklychallenge-club-18e6031dc5adaf4bdf5e140acdea6186ee4ed6ae.tar.bz2
perlweeklychallenge-club-18e6031dc5adaf4bdf5e140acdea6186ee4ed6ae.zip
Merge pull request #7242 from dcw803/master
imported my (slightly late) solutions to challenge 194, both in Perl and C
-rw-r--r--challenge-194/duncan-c-white/C/.cbuild2
-rw-r--r--challenge-194/duncan-c-white/C/Makefile16
-rw-r--r--challenge-194/duncan-c-white/C/README7
-rw-r--r--challenge-194/duncan-c-white/C/args.c207
-rw-r--r--challenge-194/duncan-c-white/C/args.h11
-rw-r--r--challenge-194/duncan-c-white/C/ch-1.c140
-rw-r--r--challenge-194/duncan-c-white/C/ch-2.c73
-rw-r--r--challenge-194/duncan-c-white/README90
-rwxr-xr-xchallenge-194/duncan-c-white/perl/ch-1.pl99
-rwxr-xr-xchallenge-194/duncan-c-white/perl/ch-2.pl78
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);