aboutsummaryrefslogtreecommitdiff
path: root/challenge-029
diff options
context:
space:
mode:
authordcw <d.white@imperial.ac.uk>2019-10-13 23:30:01 +0100
committerdcw <d.white@imperial.ac.uk>2019-10-13 23:30:01 +0100
commit8d6b78cae9bccfbb16bf79c58544f3b65716cbe3 (patch)
tree5f57743b31ecd4e3ebbd631d29f9c906407541d3 /challenge-029
parenta62eda85606f9705d85659a8f596b135099f7a8c (diff)
downloadperlweeklychallenge-club-8d6b78cae9bccfbb16bf79c58544f3b65716cbe3.tar.gz
perlweeklychallenge-club-8d6b78cae9bccfbb16bf79c58544f3b65716cbe3.tar.bz2
perlweeklychallenge-club-8d6b78cae9bccfbb16bf79c58544f3b65716cbe3.zip
imported my solutions..
Diffstat (limited to 'challenge-029')
-rw-r--r--challenge-029/duncan-c-white/README34
-rwxr-xr-xchallenge-029/duncan-c-white/perl5/ch-1.pl153
-rwxr-xr-xchallenge-029/duncan-c-white/perl5/ch-2.pl62
3 files changed, 234 insertions, 15 deletions
diff --git a/challenge-029/duncan-c-white/README b/challenge-029/duncan-c-white/README
index 75c9f80743..b00307c5eb 100644
--- a/challenge-029/duncan-c-white/README
+++ b/challenge-029/duncan-c-white/README
@@ -1,19 +1,23 @@
-Challenge 1: "Write a script to check the file content without explicitly
-reading the content. It should accept file name with path as command
-line argument and print 'The file content is binary.' or else 'The file
-content is ascii.' accordingly."
+Challenge 1: "Write a script to demonstrate brace expansion. For example,
+script would take command line argument Perl {Daily,Weekly,Monthly,Yearly}
+Challenge and should expand it and print like below:
-My notes: That's bafflingly unclear! Without "explicitly" reading
-the content, does that imply "implicitly" reading it is ok, or that
-we're really not supposed to read the content at all. In the former
-case, I guess we can run "file" and parse the outout. In the latter
-case, unless there's some magic metadata somewhere else, that only
-leaves file extensions. In that case, we just need a hash of file
-extension -> binary/ascii choices. Dull.
+ Perl Daily Challenge
+ Perl Weekly Challenge
+ Perl Monthly Challenge
+ Perl Yearly Challenge
+My notes: Nested braces may be slightly tricky, first I tried a recursive
+function to find and expand the innermost {}, but that produced the
+right output in a weird order, with duplicates.
+Instead, try a state machine to track the locations of the outer level
+elements {,}. Extract $before, $after and an array of alternatives @alt,
+then recombine them, until there are no { left.
-Challenge 2: "Write a script to display Digital Clock. Feel free to be
-as creative as you can when displaying digits. We expect bare minimum
-something like '14:10:11'"
-My notes: Sounds like a job for Tk:-)
+Challenge 2: "Write a script to demonstrate calling a C function. It
+could be any user defined or standard C function."
+
+My notes: Hmm, either XS or Inline::C. I've never used either:-)
+Wrote simple sqrt routine (algorithm: squaring the rectangle) in C,
+wrote the same in Perl, then used Benchmark to benchmark both versions.
diff --git a/challenge-029/duncan-c-white/perl5/ch-1.pl b/challenge-029/duncan-c-white/perl5/ch-1.pl
new file mode 100755
index 0000000000..8d3e89243a
--- /dev/null
+++ b/challenge-029/duncan-c-white/perl5/ch-1.pl
@@ -0,0 +1,153 @@
+#!/usr/bin/perl
+#
+# Challenge 1: "Write a script to demonstrate brace expansion. For example,
+# script would take command line argument Perl {Daily,Weekly,Monthly,Yearly}
+# Challenge and should expand it and print like below:
+#
+# Perl Daily Challenge
+# Perl Weekly Challenge
+# Perl Monthly Challenge
+# Perl Yearly Challenge
+#
+# My notes: Nested braces may be slightly tricky, first I tried a recursive
+# function to find and expand the innermost {}, but that produced the
+# right output in a weird order, with duplicates.
+# Instead, try a state machine to track the locations of the outer level
+# elements {,}. Extract $before, $after and an array of alternatives @alt,
+# then recombine them, until there are no { left.
+#
+
+use v5.10; # to get "say"
+use strict;
+use warnings;
+use Function::Parameters;
+use Data::Dumper;
+
+die "Usage: ch-1.pl STRING+\n" unless @ARGV == 1;
+my $string = shift;
+
+my @strings = expand_braces( $string );
+#my @pos = find_outermost_posns( $string );
+#say Dumper \@pos;
+say for @strings;
+
+
+#
+# my @strings = expand_braces( $string );
+# Expand brace pairs in $string, giving an array of strings.
+#
+fun expand_braces( $string )
+{
+ my @pos = find_outermost_posns( $string );
+ #say Dumper \@pos;
+ return ( $string ) if @pos==0;
+ my( $before, $after, @alt ) = extract_pieces( $string, @pos );
+ #die "debug: before=$before, after=$after, alt=@alt\n";
+ my @result;
+ foreach my $alt (@alt)
+ {
+ my $s = $before.$alt.$after;
+ push @result, expand_braces( $s );
+ }
+ return @result;
+}
+
+
+#
+# my( $before, $after, @alt ) = extract_pieces( $string, @pos );
+# Extract the before part of $string, and the after
+# part, and the array of altneratives.
+#
+fun extract_pieces( $string, @pos )
+{
+ my( $p, $c ) = @{shift @pos};
+ die "extrace_pieces: first pos $p, char $c not {\n" unless $c eq '{';
+ my $before = substr($string,0,$p);
+ #print "debug: before=$before, p=$p, c=$c\n";
+ my $start = $p;
+ my @alt;
+ my $after;
+ foreach my $pc (@pos)
+ {
+ my( $p, $c ) = @$pc;
+ if( $c eq ',' || $c eq '}' )
+ {
+ my $frag = substr($string,$start+1,$p-$start-1);
+ push @alt, $frag;
+ $start = $p;
+ if( $c eq '}' )
+ {
+ $after = substr($string,$p+1);
+ #print "debug: before=$before, after=$after, alt=@alt\n";
+ return ( $before, $after, @alt );
+ }
+ }
+ }
+ die "extrace_pieces: no } found{\n";
+}
+
+
+#
+# my @pos = find_outermost_posns( $string );
+# Locate the char positions in $string of:
+# any '{', ',', '}' characters (not nested).
+# Return the array of char positions, or an
+# empty array if the string doesn't contain
+# a '{'.
+#
+# How? a state machine to track the locations of the outer level {,}:
+#
+# s0: NOTE POS and enter s1 when '{'
+# s1: N=1; enter s2 when '{'
+# NOTE POS when ','
+# NOTE pos and enter s0 when '}'
+# s2: N++ when '{'
+# N--; enter s1 if N==0 when '}'
+#
+fun find_outermost_posns( $string )
+{
+ my @result;
+ my $state = 0;
+ my $state2n = 0;
+ for( my $pos = 0; $pos < length($string); $pos++ )
+ {
+ my $ch = substr($string,$pos,1);
+ #print "debug: pos=$pos, ch=$ch, state=$state, state2n=$state2n\n";
+ if( $state == 0 ) # not in {
+ {
+ if( $ch eq '{' )
+ {
+ push @result, [ $pos, $ch ];
+ $state = 1;
+ }
+ } elsif( $state == 1 ) # inside exactly one {
+ {
+ if( $ch eq ',' )
+ {
+ push @result, [ $pos, $ch ];
+ } elsif( $ch eq '{' )
+ {
+ $state2n = 1;
+ $state = 2;
+ } elsif( $ch eq '}' )
+ {
+ push @result, [ $pos, $ch ];
+ $state = 0;
+ }
+ } elsif( $state == 2 ) # inside >1 {
+ {
+ if( $ch eq '{' )
+ {
+ $state2n++;
+ } elsif( $ch eq '}' )
+ {
+ $state2n--;
+ if( $state2n == 0 )
+ {
+ $state = 1;
+ }
+ }
+ }
+ }
+ return @result;
+}
diff --git a/challenge-029/duncan-c-white/perl5/ch-2.pl b/challenge-029/duncan-c-white/perl5/ch-2.pl
new file mode 100755
index 0000000000..2a5d21b0c5
--- /dev/null
+++ b/challenge-029/duncan-c-white/perl5/ch-2.pl
@@ -0,0 +1,62 @@
+#!/usr/bin/perl
+#
+# Challenge 2: "Write a script to demonstrate calling a C function. It
+# could be any user defined or standard C function."
+#
+# My notes: Hmm, either XS or Inline::C. I've never used either:-)
+# Wrote simple sqrt routine (algorithm: squaring the rectangle) in C,
+# wrote the same in Perl, then used Benchmark to benchmark both versions.
+#
+
+use v5.10; # for "say"
+use strict;
+use warnings;
+#use Data::Dumper;
+use Function::Parameters;
+use Benchmark qw(:all);
+
+use Inline 'C';
+
+
+fun perl_sqrt( $x )
+{
+ my $EPSILON = 0.00001;
+ my $w=1.0;
+ for(;;)
+ {
+ my $h=$x/$w;
+ last if abs($h-$w)<$EPSILON;
+ $w = ($w+$h)/2;
+ }
+ return $w;
+}
+
+
+#greet('thingy');
+#greet(42);
+#greet(4.6);
+my $sc = c_sqrt( 145 );
+my $sp = perl_sqrt( 145 );
+print "sqrt(145)=$sc by C, =$sp by perl\n";
+
+timethese( 10000000,
+ {
+ "C" => sub { c_sqrt(145); },
+ "perl" => sub { perl_sqrt(145); }
+ } );
+__END__
+__C__
+void greet(SV* sv_name) {
+ printf("Hello %s!\n", SvPV(sv_name, PL_na));
+}
+double c_sqrt( double x ) {
+ #define EPSILON 0.00001
+ double w=1.0;
+ for(;;)
+ {
+ double h=x/w;
+ if( fabs(h-w)<EPSILON ) break;
+ w = (w+h)/2;
+ }
+ return w;
+}