diff options
| author | dcw <d.white@imperial.ac.uk> | 2019-09-29 23:44:54 +0100 |
|---|---|---|
| committer | dcw <d.white@imperial.ac.uk> | 2019-09-29 23:44:54 +0100 |
| commit | 5430708b11757850cb80b415f65bc3aed811e9d4 (patch) | |
| tree | ca492698af5dc64036d7e42f498fc428fee4d816 /challenge-027 | |
| parent | b85b95be86c1e2a250858f5c5022030470c09d02 (diff) | |
| download | perlweeklychallenge-club-5430708b11757850cb80b415f65bc3aed811e9d4.tar.gz perlweeklychallenge-club-5430708b11757850cb80b415f65bc3aed811e9d4.tar.bz2 perlweeklychallenge-club-5430708b11757850cb80b415f65bc3aed811e9d4.zip | |
imported my challenge-027 solutions..
Diffstat (limited to 'challenge-027')
| -rw-r--r-- | challenge-027/duncan-c-white/README | 54 | ||||
| -rwxr-xr-x | challenge-027/duncan-c-white/perl5/ch-1.pl | 92 | ||||
| -rwxr-xr-x | challenge-027/duncan-c-white/perl5/ch-2.pl | 180 |
3 files changed, 299 insertions, 27 deletions
diff --git a/challenge-027/duncan-c-white/README b/challenge-027/duncan-c-white/README index 4cd2bbfe01..69197e921e 100644 --- a/challenge-027/duncan-c-white/README +++ b/challenge-027/duncan-c-white/README @@ -1,36 +1,36 @@ -Challenge 1: "Create a script that prints nth order forward difference -series. You should be a able to pass the list of numbers and order number -as command line parameters. Let me show you with an example: +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: -Suppose we have list (X) of numbers: 5, 9, 2, 8, 1, 6 and we would like -to create 1st order forward difference series (Y). So using the formula -Y(i) = X(i+1) - X(i), we get the following numbers: (9-5), (2-9), (8-2), -(1-8), (6-1), ie 4, -7, 6, -7, 5. -If you noticed, it has one less number than the original series. -Similarly you can generate the 2nd order forward difference series like: -(-7-4), (6+7), (-7-6), (5+7) => -11, 13, -13, 12. +The two ends of Line 1 are represented as co-ordinates (a,b) and (c,d). -My notes: Clearly defined, very easy - let's have a go.. +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: "Create a script that prints Prime Decomposition of a -given number. The prime decomposition of a number is defined as a list -of prime numbers which when all multiplied together, are equal to that -number. For example, the Prime decomposition of 228 is 2,2,3,19 as 228 = -2 * 2 * 3 * 19." +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.. -My notes: So, prime factors then. Very easy again. In fact, haven't I -already solved this in one of the other prime-based questions? +Challenge 2: "Write a script that allows you to capture/display historical +data. It could be an object or a scalar. For example -Challenge 3: "Write a script to use Random Poems API: -https://www.poemist.com/api/v1/randompoems -This is the easiset API, I have come across so far. You don't need API -key for this. They have only route to work with (GET). The API task is -optional but we would love to see your solution." + my $x = 10; $x = 20; $x -= 5; -My notes: ok, even I can't argue that obtaining an API key for an API -I will literally never use again is too much hassle - when I don't need -an API key, and the whole program appears to be an LWP::Simple get.. +After the above operations, it should list $x historical value in order." -update: well, apart from the Unicode in the response, complicating life. +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. diff --git a/challenge-027/duncan-c-white/perl5/ch-1.pl b/challenge-027/duncan-c-white/perl5/ch-1.pl new file mode 100755 index 0000000000..fbd23aaff8 --- /dev/null +++ b/challenge-027/duncan-c-white/perl5/ch-1.pl @@ -0,0 +1,92 @@ +#!/usr/bin/perl +# +# 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: +# +# The two ends of Line 1 are represented as co-ordinates (a,b) and (c,d). +# +# 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." +# +# My notes: Clearly defined, very easy - let's have a go.. and then +# let's run gnuplot to display the results.. +# + +use v5.10; # to get "say" +use strict; +use warnings; +use Function::Parameters; + +die "Usage: ch-1.pl line1:a b c d line2:p q r s\n" unless @ARGV == 8; + +my ( $a, $b, $c, $d, @rest ) = @ARGV; +my ( $p, $q, $r, $s ) = @rest; + +# general form of an infinite line is y = mx + c, and m = (p1y-p2y)/(p1x-p2x) +# (unless p1x==p2x) for any two points p1(x,y) and p2(x,y) on the line, and +# then c = p1y - m*p1x (or p2y - m*p2x) +# +# once we have calculated m1 and c1 for line (a,b)-(c,d), and m2 and c2 +# for line (p,q)->(r,s), we need to find the intersection point and check it's +# within the line segments. + +say "a=$a, b=$b, c=$c, d=$d, p=$p, q=$q, r=$r, s=$s"; + +die "line 1: ($a,$b)->($c,$d) is vertical\n" if $b==$d; +my $m1 = ($d-$b)/($c-$a); +my $c1 = $b - $m1 * $a; + +die "line 2: ($p,$q)->($r,$s) is vertical\n" if $p==$r; +my $m2 = ($s-$q)/($r-$p); +my $c2 = $q - $m2 * $p; + +say "line 1 : y = $m1 x + $c1"; +say "line 2 : y = $m2 x + $c2"; + +# intersection of line 1 and line 2: set line1.y == line2.y: +# (m1-m2) x + (c1-c2) == 0 +# (m1-m2) x = c2-c1 +# ix = c2-c1/(m1-m2) +# subst in line 1: +# iy = m1 * ix + c1 + +die "No intersection between $m1 x + $c1 and $m2 x + $c2\n" if $m1==$m2; + +my $ix = ($c2-$c1)/($m1-$m2); +my $iy = $m1 * $ix + $c1; +say "intersection at ($ix,$iy)"; + +print "show results in gnuplot? "; +my $in = <STDIN>; + +prepare_gnuplot() if $in =~ /^y/i; + + +# +# prepare_gnuplot(); +# Prepare the gnuplot files, the data file will contain +# the two lines, and the command file will continue +# instuctions to plot both lines and the intersection point +# +fun prepare_gnuplot() +{ + # prepare the data file.. + open( my $outfh, '>', '1.dat' ) || die; + say $outfh "$a $b $p $q\n$c $d $r $s"; + close( $outfh ); + + # prepare the gnuplot command file.. + open( $outfh, '>', '1.cmd' ) || die; + say $outfh "set grid"; + say $outfh "ix = $ix"; + say $outfh "iy = $iy"; + say $outfh "plot '1.dat' using 1:2 with lines title 'line 1', '1.dat' using 3:4 with lines title 'line 2', '+' using (ix):(iy) title 'intersection'"; + say $outfh "pause mouse key"; + close( $outfh ); + + # run gnuplot + system( "gnuplot 1.cmd" ); +} diff --git a/challenge-027/duncan-c-white/perl5/ch-2.pl b/challenge-027/duncan-c-white/perl5/ch-2.pl new file mode 100755 index 0000000000..aed4e00bd3 --- /dev/null +++ b/challenge-027/duncan-c-white/perl5/ch-2.pl @@ -0,0 +1,180 @@ +#!/usr/bin/perl +# +# 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 '%='), and track the historic value of each +# variable over time. +# +# So let's try to do that, using __DATA__ (at the end of this file) for the +# default sequence, or the contents of a named input file if given. +# +# Let's also graph the time-series results via Gnuplot as I seem to be having +# a Gnuplot kick this week:-) +# + +use v5.10; # for "say" +use strict; +use warnings; +use Function::Parameters; +use Data::Dumper; + + +# +# my $val = combine( $op, $oldval, $newval ); +# Combine an optional old value $oldval (or undefined) +# and a new value $newval, under operation $op ('=', +# +fun combine( $op, $oldval, $newval ) +{ + return $newval if $op eq "="; + return $oldval + $newval if $op eq "+="; + return $oldval - $newval if $op eq "-="; + return $oldval * $newval if $op eq "*="; + return $oldval / $newval if $op eq "/="; + return $oldval % $newval if $op eq "%="; +} + + +# +# my( $varset, $input ) = process( $infh ); +# Process an input file (handle $infh), every line of which +# should be of the form VARNAME OP VALUE (where OP='=', '+=', +# '-=', '*=', '/=' or '%='), and build and return a set of all +# variables named in that input file, and an array @$input of +# all [VARNAME,OP,VALUE] decoded triples. +# +fun process( $infh ) +{ + my %vars; + my @input; + while( <$infh> ) + { + chomp; + my( $var, $op, $value ) = split( /\s+/, $_ ); + push @input, [$var,$op,$value]; + $vars{$var}++; + } + return ( \%vars, \@input ); +} + +die "Usage: ch-2.pl\nor ch-2.pl filename\n" if @ARGV>1; +my $varset; +my $input; +if( @ARGV == 0 ) +{ + ( $varset, $input ) = process( \*DATA ); +} +else +{ + open( my $infh, '<', $ARGV[0] ) || die; + ( $varset, $input ) = process( $infh ); + close( $infh ); +} + + +my $time = 0; # current time +my %currv = map { $_ => 0 } keys %$varset; # current values of variables +$time++; + +my %track; # track all historical values of all variables +foreach my $var (keys %$varset) +{ + $track{$var} = [ 0 ]; +} + + +# +# update( $triple ); +# Take a single triple $triple of the form [ VARNAME, OP, VALUE ] +# (where OP='=', '+=', '-=', '*=', '/=' or '%='), +# and update %currv and %track.. +# +fun update( $triple ) +{ + my( $var, $op, $value ) = @$triple; + $currv{$var} = combine( $op, $currv{$var}, $value ); + foreach my $var (keys %$varset) + { + push @{$track{$var}}, $currv{$var}; + } + $time++; +} + + +foreach my $triple (@$input) +{ + update( $triple ); +} + +say "Final values:"; +foreach my $var (sort keys %currv) +{ + say "$var: $currv{$var}"; +} + +say "Historical values:"; +foreach my $var (sort keys %track) +{ + say "$var: ", join(',', @{$track{$var}} ); +} + +print "show results in gnuplot? "; +my $in = <STDIN>; +prepare_gnuplot() if $in =~ /^y/i; + + +# +# prepare_gnuplot(); +# Prepare the gnuplot files, the data file will contain +# track[var][time] ordered first by time, then by vars, +# and the command file will continue instuctions to plot +# each column as a separate named variable. +# +fun prepare_gnuplot() +{ + # prepare the data file.. + open( my $outfh, '>', '2.dat' ) || die; + foreach my $t (0..$time-1) + { + my @line = ( $t ); + foreach my $var (sort keys %track) + { + push @line, $track{$var}[$t]; + } + say $outfh join(' ', @line); + } + close( $outfh ); + + # prepare the gnuplot command file.. + open( $outfh, '>', '2.cmd' ) || die; + say $outfh "set grid"; + my $pos = 1; + my @pl = map { + $pos++; + "'2.dat' using 1:$pos with lines title '$_'"; + } sort keys %track; + say $outfh "plot ", join(', ', @pl); + say $outfh "pause mouse key"; + close( $outfh ); + + # run gnuplot + system( "gnuplot 2.cmd" ); +} + +__DATA__ +x = 10 +y = 20 +x = 20 +y += 100 +x -= 5 +y *= 2 +x *= 3 |
