From c4f59e7b721a8e4ffc2db93db7dc6292d7a6336d Mon Sep 17 00:00:00 2001 From: dcw Date: Sun, 6 Oct 2019 23:55:05 +0100 Subject: incorporated my solutions.. ch-1.pl is ridiculous, but ch-2.pl is a rather cool 7-segment led based digital clock (that resizes properly too) --- challenge-028/duncan-c-white/README | 47 ++---- challenge-028/duncan-c-white/perl5/ch-1.pl | 48 ++++++ challenge-028/duncan-c-white/perl5/ch-2.pl | 228 +++++++++++++++++++++++++++++ 3 files changed, 291 insertions(+), 32 deletions(-) create mode 100755 challenge-028/duncan-c-white/perl5/ch-1.pl create mode 100755 challenge-028/duncan-c-white/perl5/ch-2.pl diff --git a/challenge-028/duncan-c-white/README b/challenge-028/duncan-c-white/README index 69197e921e..75c9f80743 100644 --- a/challenge-028/duncan-c-white/README +++ b/challenge-028/duncan-c-white/README @@ -1,36 +1,19 @@ -Challenge 1: "Write a script to find the intersection of two straight -lines. The co-ordinates of the two lines should be provided as command -line parameter. For example: +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." -The two ends of Line 1 are represented as co-ordinates (a,b) and (c,d). +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. -The two ends of Line 2 are represented as co-ordinates (p,q) and (r,s). -The script should print the co-ordinates of point of intersection of -the above two lines." +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: Clearly defined, very easy if I can remember the formulae - let's -have a go.. after doing it, I decided to run Gnuplot to display the results -as it's an intensely graphical concept.. - - -Challenge 2: "Write a script that allows you to capture/display historical -data. It could be an object or a scalar. For example - - my $x = 10; $x = 20; $x -= 5; - -After the above operations, it should list $x historical value in order." - -My notes: The idea is easy, but we're not told the API to implement. I'm -certainly not going to introspect into Perl to find out whenever a scalar -variable is assigned to! I have chosen to implement this for numeric -variables, using an input sequence of VARNAME OP VALUE triples (where OP='=', -'+=', '-=', '*=', '/=' or '%='), where each input triple N occurs at time N, -and we track the historic value of each variable over time. - -I did that, using __DATA__ (at the end of this file) for the default sequence, -or the contents of a named input file if given. - -I also graphed the time-series results via Gnuplot as I seem to be having -a Gnuplot kick this week:-) It's not really the ideal output format, but -it's relatively cute. +My notes: Sounds like a job for Tk:-) diff --git a/challenge-028/duncan-c-white/perl5/ch-1.pl b/challenge-028/duncan-c-white/perl5/ch-1.pl new file mode 100755 index 0000000000..cb4f7444b2 --- /dev/null +++ b/challenge-028/duncan-c-white/perl5/ch-1.pl @@ -0,0 +1,48 @@ +#!/usr/bin/perl +# +# 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." +# +# 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 both ways. I'll do the latter." +# +# + +use v5.10; # to get "say" +use strict; +use warnings; +use Function::Parameters; + +die "Usage: ch-1.pl FILENAME+\n" if @ARGV == 0; + +foreach my $filename (@ARGV) +{ + my $binary = ClassifyBinaryOrText( $filename ); + say "file $filename is ", $binary?"binary":"text"; +} + +my %knownbinary = map { $_ => 1 } +qw(tar gz bz2 tbz tbz2 tgz tar.gz tar.bz2 tar.bz Z tar.Z + zip jpg gif png cpio out a o); + + +# +# my $binary = ClassifyBinaryOrText( $filename ); +# Classify filename into binary or text without reading +# the content =s (why???). So based on the extension then. +# Returns 1 for binary, 0 for text. +# +fun ClassifyBinaryOrText( $filename ) +{ + my $ext = $filename; + $ext =~ s|^[^.]+/\.|| or return 0; + return 1 if $knownbinary{$ext}; + return 0; +} diff --git a/challenge-028/duncan-c-white/perl5/ch-2.pl b/challenge-028/duncan-c-white/perl5/ch-2.pl new file mode 100755 index 0000000000..04fd92f06a --- /dev/null +++ b/challenge-028/duncan-c-white/perl5/ch-2.pl @@ -0,0 +1,228 @@ +#!/usr/bin/perl +# +# 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:-) in this version, after earlier +# building a simple coloured-label clock, I now build a 7-segment LED based +# clock, which handles window resizing properly. There's something slightly +# strange about the "font" of the LED segments, with the verticals being +# surprisingly thin, actually that's a bug I've run out of time to track +# down, but it's quite appealing somehow:-) +# + +use v5.10; # for "say" +use strict; +use warnings; +use Tk; +use Function::Parameters; +use Data::Dumper; + +my $width = 1000; +my $height = 400; +my $mw; +my $eg = 50; # edge gap (above, below, to left, and right) +my $g = 30; # internal gap (between things) +my $dotw = 20; # dot width +my $linew = 12; # width of segment lines +my $digitw; # 7-segment led digit width, recalculated when we resize +my $hiy; # high coord of led digits, recalculated when we resize +my $midy; # middle coord of led digits, recalculated when we resize +my $loy; # low coord of led digits, recalculated when we resize + +die "Usage: ch-2.pl\n" if @ARGV>0; +$mw = MainWindow->new(); +$mw->minsize( 200, 50 ); +my $canvas = $mw->Canvas( + -width => $width, -height => $height, + -background => 'black', + )->pack(-expand => 1, -fill => 'both'); +layout( $width, $height ); +$mw->after( 1000, \&setupbindings ); + +# +# setupbindings(); +# Set up the bindings, not sure why but unless I +# delay this, the configure event triggers itself +# with gradually smaller WxH and the clock shrinks +# to it's minimum size... gross hack time:-) +# +sub setupbindings +{ + $mw->bind('' => \&exit); + $mw->bind( "" => \&handleresize ); +} + + +# +# handleresize( $widget ); +# Handle a configure (resize or something else) event on $widget. +# Figure out the new width and height, update globals width and height +# and change the font size for the label to fit. +# +fun handleresize( $widget ) +{ + my $e = $widget->XEvent; + if( $width != $e->w || $height != $e->h ) + { + $width = $e->w; + $height = $e->h; + #say "w=$width, h=$height"; + + # change layout using $width + layout( $width, $height ); + } +} + + +# +# layout( $width, $height ); +# Ok, the dimensions of the mainwindow (and canvas) have changed, +# now work out how the layout of the LEDs changes in response. +# +fun layout( $width, $height ) +{ + $digitw = ( $width - 2 * $eg - 7 * $g - 2 * $dotw ) / 6; + $hiy = $eg; + $midy = $height/2; + $loy = $height - $eg; + + # blank canvas + $canvas->delete('all'); + + # now draw everything grey + drawdigit( 0, 0 ); + drawdigit( 1, 0 ); + drawcolon( 0 ); + drawdigit( 2, 0 ); + drawdigit( 3, 0 ); + drawdigit( 4, 0); + drawdigit( 5, 0 ); + drawcolon( 1 ); +} + + +# +# drawdigit( $digitno, $bitset ); +# Draw a 7-led LED, all grey except those elements in the $bitset which +# are on (which are shown in red), digitno is 0 for leftmost (h1).. 5 for +# rightmost (s2) +# +fun drawdigit( $digitno, $bitset ) +{ + my $lx = $eg + ($digitno*($digitw+$g)); + $lx += $g + $dotw if $digitno>1; + $lx += $g + $dotw if $digitno>3; + + my $rx = $lx+$digitw-1; + + my $oncol = 'red'; + my $offcol = 'black'; + + # line 0: across the top + my $col = ($bitset&1) ? $oncol : $offcol; + $canvas->createRectangle( $lx+$linew, $hiy, $rx-$linew, $hiy+$linew, + -fill=>$col, -outline=>$col ); + + # line 1: left hand side, upper + $col = ($bitset&2) ? $oncol : $offcol; + $canvas->createRectangle( $lx+$linew, $hiy, $lx+$linew, $midy+$linew, + -fill=>$col, -outline=>$col ); + + # line 2: right hand side, upper + $col = ($bitset&4) ? $oncol : $offcol; + $canvas->createRectangle( $rx-$linew, $hiy, $rx-$linew, $midy+$linew, + -fill=>$col, -outline=>$col ); + + # line 3: across the middle + $col = ($bitset&8) ? $oncol : $offcol; + $canvas->createRectangle( $lx+$linew, $midy, $rx-$linew, $midy+$linew, + -fill=>$col, -outline=>$col ); + + # line 4: left hand side, lower + $col = ($bitset&16) ? $oncol : $offcol; + $canvas->createRectangle( $lx+$linew, $midy, $lx+$linew, $loy+$linew, + -fill=>$col, -outline=>$col ); + + # line 5: right hand side, lower + $col = ($bitset&32) ? $oncol : $offcol; + $canvas->createRectangle( $rx-$linew, $midy, $rx-$linew, $loy+$linew, + -fill=>$col, -outline=>$col ); + + # line 6: across the bottom + $col = ($bitset&64) ? $oncol : $offcol; + $canvas->createRectangle( $lx+$linew, $loy, $rx-$linew, $loy+$linew, + -fill=>$col, -outline=>$col ); +} + + +# +# drawcolon( $lr ); +# Draw one colon (either the one between hours/mins if lr==0, +# or the one between mins/seconds if lr==1 +# +fun drawcolon( $lr ) +{ + my $lx = $eg + 2 * $digitw + 2 * $g + $dotw/2; + $lx += 2 * $digitw + 3 * $g + $dotw if $lr==1; + + $canvas->createOval( $lx-$dotw/2, $midy-3*$dotw, + $lx+$dotw/2, $midy-2*$dotw, + -fill=>'red', -outline=>'red' ); + $canvas->createOval( $lx-$dotw/2, $midy+2*$dotw, + $lx+$dotw/2, $midy+3*$dotw, + -fill=>'red', -outline=>'red' ); +} + + +# the 7-led sets representing each digit +my @set = +( + 0b1110111, + 0b0100100, + 0b1011101, + 0b1101101, + 0b0101110, + 0b1101011, + 0b1111011, + 0b0100101, + 0b1111111, + 0b0101111, +); + + +# +# showleds( $h1, $h2, $m1, $m2, $s1, $s2 ); +# Show the LEDs for each digit +# +fun showleds( $h1, $h2, $m1, $m2, $s1, $s2 ) +{ + drawdigit( 0, $set[$h1] ); + drawdigit( 1, $set[$h2] ); + drawdigit( 2, $set[$m1] ); + drawdigit( 3, $set[$m2] ); + drawdigit( 4, $set[$s1] ); + drawdigit( 5, $set[$s2] ); +} + + +# +# tick(); +# Update the counter every 1000 milliseconds (second) +sub tick +{ + my( $sec, $min, $hour ) = localtime(time()); + my $h1 = int( $hour / 10 ); + my $h2 = $hour % 10; + my $m1 = int( $min / 10 ); + my $m2 = $min % 10; + my $s1 = int( $sec / 10 ); + my $s2 = $sec % 10; + showleds( $h1, $h2, $m1, $m2, $s1, $s2 ); + $mw->after(1000, \&tick); +} + +tick(); + +MainLoop; -- cgit