aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordcw <d.white@imperial.ac.uk>2022-11-13 23:56:01 +0000
committerdcw <d.white@imperial.ac.uk>2022-11-13 23:56:01 +0000
commita9ec3e9e8d6db4bfca04560d436d945da57f5eff (patch)
tree9a4af37f6582e008cdc19e137c104d3ed5ecdf7f
parent78a97ea8621c3fc04c65bc6f5104b247f5601095 (diff)
downloadperlweeklychallenge-club-a9ec3e9e8d6db4bfca04560d436d945da57f5eff.tar.gz
perlweeklychallenge-club-a9ec3e9e8d6db4bfca04560d436d945da57f5eff.tar.bz2
perlweeklychallenge-club-a9ec3e9e8d6db4bfca04560d436d945da57f5eff.zip
imported my solutions to this week's tasks, two reasonably easy tasks (submitted right at last minute, got stuck in C translation of task 2)
-rw-r--r--challenge-190/duncan-c-white/C/Makefile16
-rw-r--r--challenge-190/duncan-c-white/C/README8
-rw-r--r--challenge-190/duncan-c-white/C/args.c207
-rw-r--r--challenge-190/duncan-c-white/C/args.h11
-rw-r--r--challenge-190/duncan-c-white/C/ch-1.c65
-rw-r--r--challenge-190/duncan-c-white/C/ch-2.c133
-rw-r--r--challenge-190/duncan-c-white/README109
-rwxr-xr-xchallenge-190/duncan-c-white/perl/ch-1.pl68
-rwxr-xr-xchallenge-190/duncan-c-white/perl/ch-2.pl113
9 files changed, 664 insertions, 66 deletions
diff --git a/challenge-190/duncan-c-white/C/Makefile b/challenge-190/duncan-c-white/C/Makefile
new file mode 100644
index 0000000000..8d85c7d16d
--- /dev/null
+++ b/challenge-190/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-190/duncan-c-white/C/README b/challenge-190/duncan-c-white/C/README
new file mode 100644
index 0000000000..93788320dc
--- /dev/null
+++ b/challenge-190/duncan-c-white/C/README
@@ -0,0 +1,8 @@
+Thought I'd also have a go at translating ch-1.pl and ch-2.pl into C..
+
+Both produce near-identical (non-debugging) output to my Perl originals.
+
+They use 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-190/duncan-c-white/C/args.c b/challenge-190/duncan-c-white/C/args.c
new file mode 100644
index 0000000000..d4a2d38b9a
--- /dev/null
+++ b/challenge-190/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-190/duncan-c-white/C/args.h b/challenge-190/duncan-c-white/C/args.h
new file mode 100644
index 0000000000..8844a8f9c4
--- /dev/null
+++ b/challenge-190/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-190/duncan-c-white/C/ch-1.c b/challenge-190/duncan-c-white/C/ch-1.c
new file mode 100644
index 0000000000..76471220fa
--- /dev/null
+++ b/challenge-190/duncan-c-white/C/ch-1.c
@@ -0,0 +1,65 @@
+//
+// Task 1: Capital Detection
+//
+// C version.
+//
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "args.h"
+
+
+//
+// bool ok = capdetect( str );
+// Return true iff str is a good "use of capitals" string as described
+// above, or return false otherwise.
+//
+bool capdetect( char *str )
+{
+ if( isupper(*str) )
+ {
+ bool alllower = true;
+ bool allupper = true;
+ for( char *p=str+1; *p; p++ )
+ {
+ if( ! islower(*p) ) alllower = false;
+ if( ! isupper(*p) ) allupper = false;
+ }
+ if( alllower || allupper ) return true;
+ }
+ if( islower(*str) )
+ {
+ bool alllower = true;
+ for( char *p=str+1; *p; p++ )
+ {
+ if( ! islower(*p) ) alllower = false;
+ }
+ if( alllower ) return true;
+ }
+ return 0;
+}
+
+
+int main( int argc, char **argv )
+{
+ int argno = process_flag_n_args( "capital-detect", argc, argv,
+ 1, "string" );
+
+ char *str = argv[argno++];
+
+ if( debug )
+ {
+ printf( "debug: str=%s\n", str );
+ }
+
+ bool ok = capdetect( str );
+
+ printf( "%c\n", ok?'1':'0' );
+
+ return 0;
+}
diff --git a/challenge-190/duncan-c-white/C/ch-2.c b/challenge-190/duncan-c-white/C/ch-2.c
new file mode 100644
index 0000000000..daca37a01d
--- /dev/null
+++ b/challenge-190/duncan-c-white/C/ch-2.c
@@ -0,0 +1,133 @@
+//
+// Task 2: Decoded List
+//
+// C version.
+//
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "args.h"
+
+
+typedef char bigstr[1024];
+
+
+char enc[27]; // element 0 not used
+
+
+//
+// decode_all( str, prefix, results[], &nr );
+// Decode str, taking 1 or 2 digits off the front (as long
+// as the number that results is between 1..26), producing
+// all the possible decodings (adding prefix to each decoding
+// that we produce)
+//
+void decode_all( char *str, char *prefix, bigstr *results, int *nr )
+{
+ if( *str == '\0' )
+ {
+ int i = (*nr);
+ strcpy( results[i], prefix );
+ if( debug )
+ {
+ printf( "found solution %d = %s\n", i, prefix );
+ }
+ (*nr)++;
+ return;
+ }
+
+ // try taking off the first char..
+ char first = *str;
+ char *rem = str+1;
+ if( debug )
+ {
+ printf( "debug: first=%c, rem=%s\n", first, rem );
+ }
+ if( strcmp(rem,"0") != 0 && first != '0')
+ {
+ bigstr p2;
+ strcpy( p2, prefix );
+ char *p = p2+strlen(p2);
+ *p++ = enc[first-'0'];
+ *p++ = '\0';
+ if( debug )
+ {
+ printf( "debug: recurse with rem=%s, first=%c, prefix=%s\n",
+ rem, first, p2 );
+ }
+ decode_all( rem, p2, results, nr );
+ }
+
+ if( strlen(str) > 1 )
+ {
+ // try taking off the first two chars..
+ int first = (*str-'0')*10 + (str[1]-'0');
+ char *rem = str+2;
+ if( debug )
+ {
+ printf( "debug: first=%d, rem=%s\n", first, rem );
+ }
+
+ if( strcmp(rem,"0") != 0 && first <= 26 )
+ {
+ bigstr p2;
+ strcpy( p2, prefix );
+ char *p = p2+strlen(p2);
+ *p++ = enc[first];
+ *p++ = '\0';
+ if( debug )
+ {
+ printf( "debug: recurse with rem=%s, first=%d, prefix=%s\n",
+ rem, first, p2 );
+ }
+ decode_all( rem, p2, results, nr );
+ }
+ }
+}
+
+
+int main( int argc, char **argv )
+{
+ int argno = process_flag_n_args( "decoded-list", argc, argv,
+ 1, "encoded string" );
+
+ char *str = argv[argno++];
+
+ if( debug )
+ {
+ printf( "debug: str=%s\n", str );
+ }
+
+ for( char ch='A'; ch<='Z'; ch++ )
+ {
+ enc[ch-'@'] = ch;
+ if( debug )
+ {
+ printf( "debug: enc[%d] = %c\n", ch-'@', ch );
+ }
+ }
+
+
+ bigstr results[1024];
+ int nr = 0;
+ decode_all( str, "", results, &nr );
+
+ bool first = true;
+ for( int i=0; i<nr; i++ )
+ {
+ if( ! first )
+ {
+ fputs( ", ", stdout );
+ }
+ printf( "%s", results[i] );
+ first = false;
+ }
+ putchar( '\n' );
+
+ return 0;
+}
diff --git a/challenge-190/duncan-c-white/README b/challenge-190/duncan-c-white/README
index 6ac1265327..9edc65e930 100644
--- a/challenge-190/duncan-c-white/README
+++ b/challenge-190/duncan-c-white/README
@@ -1,96 +1,73 @@
-Task 1: Greater Character
+Task 1: Capital Detection
-You are given an array of characters (a..z) and a target character.
+You are given a string with alphabetic characters only: A..Z and a..z.
-Write a script to find out the smallest character in the given array
-lexicographically greater than the target character.
+Write a script to find out if the usage of Capital is appropriate if it
+satisfies any of the following rules:
-Example 1
+1) Only first letter is capital and all others are small.
+2) Every letter is small.
+3) Every letter is capital.
- Input: @array = qw/e m u g/, $target = 'b'
- Output: e
+Example 1
+ Input: $s = 'Perl'
+ Output: 1
Example 2
-
- Input: @array = qw/d c e f/, $target = 'a'
- Output: c
+ Input: $s = 'TPF'
+ Output: 1
Example 3
-
- Input: @array = qw/j a r/, $target = 'o'
- Output: r
+ Input: $s = 'PyThon'
+ Output: 0
Example 4
+ Input: $s = 'raku'
+ Output: 1
- Input: @array = qw/d c a f/, $target = 'a'
- Output: c
-
-Example 5
-
- Input: @array = qw/t g a l/, $target = 'v'
- Output: v
-
-MY NOTES: pretty easy, although example 5 seems to imply that the spec
-should say, "... or the target if no character in the array is bigger
-than the target". So that's the basis on which I'm proceeding:
-
-Note that "an array of characters" is awfully like "a string + split",
-so let's do that.
-
-Can do it as a one-liner:
-perl -MList::Util=minstr -E '( $target, $str ) = @ARGV; $x = minstr( grep { $_ gt $target } split( //, $str ) ) // ($target); say $x' a dcef
+MY NOTES: very easy.
GUEST LANGUAGE: As a bonus, I also had a go at translating ch-1.pl
-into C and Pascal (look in the relevant direcories for
-those translations)
+into C (look in the C directory for the translation)
-Task 2: Array Degree
+Task 2: Decoded List
-You are given an array of 2 or more non-negative integers.
+You are given an encoded string $s consisting of a sequence of numeric
+characters: 0..9.
-Write a script to find out the smallest slice, i.e. contiguous subarray
-of the original array, having the degree of the given array.
+Write a script to find all valid different decodings in sorted order.
-The degree of an array is the maximum frequency of an element in the array.
+Encoding is simply done by mapping A,B,C,D,# to 1,2,3,4,# etc.
Example 1
+ Input: $s = 11
+ Output: AA, K
- Input: @array = (1, 3, 3, 2)
- Output: (3, 3)
-
- The degree of the given array is 2.
- The possible subarrays having the degree 2 are as below:
- (3, 3)
- (1, 3, 3)
- (3, 3, 2)
- (1, 3, 3, 2)
-
- And the smallest of all is (3, 3).
+ 11 can be decoded as (1 1) or (11) i.e. AA or K
Example 2
+ Input: $s = 1115
+ Output: AAAE, AAO, AKE, KAE, KO
- Input: @array = (1, 2, 1, 3)
- Output: (1, 2, 1)
+ Possible decoded data are:
+ (1 1 1 5) => (AAAE)
+ (1 1 15) => (AAO)
+ (1 11 5) => (AKE)
+ (11 1 5) => (KAE)
+ (11 15) => (KO)
Example 3
+ Input: $s = 127
+ Output: ABG, LG
- Input: @array = (1, 3, 2, 1, 2)
- Output: (2, 1, 2)
-
-Example 4
-
- Input: @array = (1, 1, 2, 3, 2)
- Output: (1, 1)
-
-Example 5
-
- Input: @array = (2, 1, 2, 1, 1)
- Output: (1, 2, 1, 1)
+ Possible decoded data are:
+ (1 2 7) => (ABG)
+ (12 7) => (LG)
-MY NOTES: Ok, sounds pretty easy. Finding the degree of an array range
-involves building a frequency hash, the degree is max( values %freq ).
-Finding the smallest subarray is easier enough, although tedious.
+MY NOTES: Hmm.. may be simple "take 1 or 2 chars off the front" (if that
+front part is in 1..26 range), plus recursive processing of what's left, with a prefix
+added to each sub-solution..
GUEST LANGUAGE: As a bonus, I also had a go at translating ch-2.pl
-into C and Pascal (look in the relevant direcories for those translations)
+into C (look in the C directory for the translation)
diff --git a/challenge-190/duncan-c-white/perl/ch-1.pl b/challenge-190/duncan-c-white/perl/ch-1.pl
new file mode 100755
index 0000000000..c29ebacd1d
--- /dev/null
+++ b/challenge-190/duncan-c-white/perl/ch-1.pl
@@ -0,0 +1,68 @@
+#!/usr/bin/perl
+#
+# Task 1: Capital Detection
+#
+# You are given a string with alphabetic characters only: A..Z and a..z.
+#
+# Write a script to find out if the usage of Capital is appropriate if it
+# satisfies any of the following rules:
+#
+# 1) Only first letter is capital and all others are small.
+# 2) Every letter is small.
+# 3) Every letter is capital.
+#
+# Example 1
+# Input: $s = 'Perl'
+# Output: 1
+#
+# Example 2
+# Input: $s = 'TPF'
+# Output: 1
+#
+# Example 3
+# Input: $s = 'PyThon'
+# Output: 0
+#
+# Example 4
+# Input: $s = 'raku'
+# Output: 1
+#
+# MY NOTES: very easy.
+#
+# 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: capital-detect [--debug] string\n"
+ unless GetOptions( "debug"=>\$debug ) && @ARGV==1;
+
+my $str = shift;
+
+=pod
+
+=head2 my $ok = capdetect( $str );
+
+Return 1 iff $str is a good "use of capitals" string as described
+above, or return 0 otherwise.
+
+=cut
+sub capdetect
+{
+ my( $str ) = @_;
+ return 1 if $str =~ /^[A-Z][a-z]*$/;
+ return 1 if $str =~ /^[a-z]+$/;
+ return 1 if $str =~ /^[A-Z]+$/;
+ return 0;
+}
+
+
+my $ok = capdetect( $str );
+
+say $ok;
diff --git a/challenge-190/duncan-c-white/perl/ch-2.pl b/challenge-190/duncan-c-white/perl/ch-2.pl
new file mode 100755
index 0000000000..cd830f7657
--- /dev/null
+++ b/challenge-190/duncan-c-white/perl/ch-2.pl
@@ -0,0 +1,113 @@
+#!/usr/bin/perl
+#
+# Task 2: Decoded List
+#
+# You are given an encoded string $s consisting of a sequence of numeric
+# characters: 0..9.
+#
+# Write a script to find all valid different decodings in sorted order.
+#
+# Encoding is simply done by mapping A,B,C,D,# to 1,2,3,4,# etc.
+#
+# Example 1
+# Input: $s = 11
+# Output: AA, K
+#
+# 11 can be decoded as (1 1) or (11) i.e. AA or K
+#
+# Example 2
+# Input: $s = 1115
+# Output: AAAE, AAO, AKE, KAE, KO
+#
+# Possible decoded data are:
+# (1 1 1 5) => (AAAE)
+# (1 1 15) => (AAO)
+# (1 11 5) => (AKE)
+# (11 1 5) => (KAE)
+# (11 15) => (KO)
+#
+# Example 3
+# Input: $s = 127
+# Output: ABG, LG
+#
+# Possible decoded data are:
+# (1 2 7) => (ABG)
+# (12 7) => (LG)
+#
+# MY NOTES: Hmm.. may be simple "take 1 or 2 chars off the front" (if that
+# front part is in 1..26 range), plus recursive processing of what's left,
+# with a prefix added to each sub-solution..
+#
+# 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: decoded-list [--debug] encodedstr\n"
+ unless GetOptions( "debug"=>\$debug ) && @ARGV==1;
+
+my $str = shift;
+
+die "decoded-list: bad string $str (must be entirely numeric)\n"
+ unless $str =~ /^\d+$/;
+
+my %enc = map { ord($_)-ord('@') => $_ } 'A'..'Z';
+#die Dumper \%enc;
+
+my @poss = decode_all( $str, '' );
+
+
+=pod
+
+=head2 my @poss = decode_all( $str, $prefix );
+
+Decode $str, taking 1 or 2 digits off the front (as long
+as the number that results is between 1..26), producing
+all the possible decodings (adding $prefix to each decoding
+that we produce)
+
+=cut
+fun decode_all( $str, $prefix )
+{
+ return ( $prefix ) if $str eq '';
+
+ my @result;
+
+ # try taking off the first char..
+ my $first = substr($str,0,1);
+ my $rem = substr($str,1);
+ say "debug: first=$first, rem=$rem" if $debug;
+ if( $rem ne '0' && $first ne '0' )
+ {
+ my $p2 = $prefix . $enc{$first};
+ say "debug: recurse with first=$first, prefix=$p2" if $debug;
+ @result = decode_all( $rem, $p2 );
+ }
+
+ if( length($str) > 1 )
+ {
+ # try taking off the first two chars..
+ $first = substr($str,0,2);
+ $rem = substr($str,2);
+ say "debug: first2=$first, rem=$rem" if $debug;
+ if( $rem ne '0' && $first <= 26 )
+ {
+ my $p2 = $prefix . $enc{$first};
+ say "debug: recurse with first=$first, prefix=$p2" if $debug;
+ my @p = decode_all( $rem, $p2 );
+ push @result, @p;
+ }
+ }
+ return @result;
+}
+
+
+say join( ', ', @poss );