aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohammad S Anwar <Mohammad.Anwar@yahoo.com>2022-05-22 21:39:14 +0100
committerGitHub <noreply@github.com>2022-05-22 21:39:14 +0100
commit726d703455e52374ff4d703bc4f3f704786f45eb (patch)
treec4ca565a49a54990a1e2a1121f84a8245d4b7bfe
parentef704186cc608715275b0620cb62c781333c5a03 (diff)
parent44eff7f683e537a808e8824328ec263b39e76404 (diff)
downloadperlweeklychallenge-club-726d703455e52374ff4d703bc4f3f704786f45eb.tar.gz
perlweeklychallenge-club-726d703455e52374ff4d703bc4f3f704786f45eb.tar.bz2
perlweeklychallenge-club-726d703455e52374ff4d703bc4f3f704786f45eb.zip
Merge pull request #6136 from wanderdoc/master
Solutions to challenge-165.
-rw-r--r--challenge-165/wanderdoc/perl/ch-1.pl65
-rw-r--r--challenge-165/wanderdoc/perl/ch-2.pl83
-rw-r--r--challenge-165/wanderdoc/perl/input.txt59
-rw-r--r--challenge-165/wanderdoc/perl/my_svg.pm135
4 files changed, 342 insertions, 0 deletions
diff --git a/challenge-165/wanderdoc/perl/ch-1.pl b/challenge-165/wanderdoc/perl/ch-1.pl
new file mode 100644
index 0000000000..fcebac9aa3
--- /dev/null
+++ b/challenge-165/wanderdoc/perl/ch-1.pl
@@ -0,0 +1,65 @@
+#!perl
+use strict;
+use warnings FATAL => qw(all);
+
+=prompt
+Your task is to accept a series of points and lines in the following format, one per line, in arbitrary order:
+Point: x,y
+Line: x1,y1,x2,y2
+Then, generate an SVG file plotting all points, and all lines. If done correctly, you can view the output .svg file in your browser.
+=cut
+
+
+
+
+
+
+
+
+use FindBin qw($Bin);
+use lib $Bin;
+use my_svg;
+
+my (@points, @lines);
+
+my $input_file = 'input.txt';
+
+{
+ open my $in, "<", "$Bin/$input_file" or die "$!";
+
+ while ( my $line = <$in> )
+ {
+ chomp $line;
+ $line =~ tr/ //ds;
+ next unless length($line);
+
+ my @arr = split(/,/, $line);
+ my %h;
+
+
+
+ if ( 2 == @arr )
+ {
+ @h{qw(x y)} = @arr;
+ push @points, \%h ;
+ }
+ elsif ( 4 == @arr )
+ {
+ @h{qw(x1 y1 x2 y2)} = @arr;
+
+ push @lines, \%h;
+ }
+
+ if ( 2 != @arr and 4 != @arr )
+ {
+ warn "Confusing line: <<$line>> ... ignoring ... $/";
+ }
+ }
+
+}
+
+my $output_svg = create_svg(\@points, \@lines);
+
+open my $out, ">", "$Bin/output_task1.svg" or die "$!";
+
+print {$out} $output_svg; \ No newline at end of file
diff --git a/challenge-165/wanderdoc/perl/ch-2.pl b/challenge-165/wanderdoc/perl/ch-2.pl
new file mode 100644
index 0000000000..727033de33
--- /dev/null
+++ b/challenge-165/wanderdoc/perl/ch-2.pl
@@ -0,0 +1,83 @@
+#!perl
+use strict;
+use warnings FATAL => qw(all);
+
+=prompt
+Calculate the line of best fit for the following 48 points:
+...
+Using your rudimentary graphing engine from Task #1, graph all points, as well as the line of best fit.
+=cut
+
+
+
+
+
+use List::Util qw(reduce);
+use FindBin qw($Bin);
+
+use lib $Bin;
+use my_svg;
+
+
+my $input = <<'POINTS';
+333,129 39,189 140,156 292,134 393,52 160,166 362,122 13,193
+341,104 320,113 109,177 203,152 343,100 225,110 23,186 282,102
+284,98 205,133 297,114 292,126 339,112 327,79 253,136 61,169
+128,176 346,72 316,103 124,162 65,181 159,137 212,116 337,86
+215,136 153,137 390,104 100,180 76,188 77,181 69,195 92,186
+275,96 250,147 34,174 213,134 186,129 189,154 361,82 363,89
+POINTS
+
+
+my @pts = map { my %h; @h{qw(x y)} = split(/,/, $_); \%h; }
+ split(/\s+/, $input);
+my ( $slope, $intercept ) = calculate_best_fit(@pts);
+my ($x_1, $x_2) = (sort{$a <=> $b} map $_->{x} , @pts)[0, -1];
+my @lines;
+push @lines, create_line($x_1, $x_2, $slope, $intercept);
+
+
+
+my $output_svg = create_svg(\@pts, \@lines, $slope, $intercept);
+open my $out, ">", "$Bin/output_task2.svg" or die "$!";
+print {$out} $output_svg;
+
+
+sub calculate_best_fit
+{
+ my @points = @_;
+
+ my $N = scalar @points;
+
+ # Step 1: For each (x,y) point calculate x^2 and xy:
+ my @x_sq = map $_->{x} * $_->{x}, @points;
+
+ my @xy = map $_->{x} * $_->{y}, @points;
+
+ # Step 2: Sum all x, y, x^2 and xy:
+
+ my $sum_x = reduce { $a + $b->{x} } 0, @points;
+ my $sum_y = reduce { $a + $b->{y} } 0, @points;
+ my $sum_x_sq = reduce {$a + $b } @x_sq;
+ my $sum_xy = reduce {$a + $b} @xy;
+
+ # Step 3: Calculate slope m:
+ my $m = ($N * $sum_xy - $sum_x * $sum_y) /
+ ($N * $sum_x_sq - ($sum_x * $sum_x));
+
+ # Step 4: Calculate Intercept b:
+ my $intrcpt = ($sum_y - $m * $sum_x) / $N;
+
+ return ($m, $intrcpt);
+
+}
+
+
+
+sub create_line
+{
+ my ( $x1, $x2, $slp, $itr ) = @_;
+ my $y1 = int( $slp * $x1 + $itr );
+ my $y2 = int( $slp * $x2 + $itr );
+ return {x1 => $x1, y1 => $y1, x2 => $x2, y2 => $y2};
+} \ No newline at end of file
diff --git a/challenge-165/wanderdoc/perl/input.txt b/challenge-165/wanderdoc/perl/input.txt
new file mode 100644
index 0000000000..7b8f430207
--- /dev/null
+++ b/challenge-165/wanderdoc/perl/input.txt
@@ -0,0 +1,59 @@
+25, 50
+120, 70, 90, 200
+15, 25
+99, 77
+73, 11
+3, 14, 15, 92
+15, 225
+100, 100
+100, 200
+200, 500
+
+333,129
+39,189
+140,156
+292,134
+393,52
+160,166
+362,122
+13,193
+341,104
+320,113
+109,177
+203,152
+343,100
+225,110
+23,186
+282,102
+284,98
+205,133
+297,114
+292,126
+339,112
+327,79
+253,136
+61,169
+128,176
+346,72
+316,103
+124,162
+65,181
+159,137
+212,116
+337,86
+215,136
+153,137
+390,104
+100,180
+76,188
+77,181
+69,195
+92,186
+275,96
+ 250,147
+34,174
+213,134
+186,129
+189,154
+361,82
+ 363,89 \ No newline at end of file
diff --git a/challenge-165/wanderdoc/perl/my_svg.pm b/challenge-165/wanderdoc/perl/my_svg.pm
new file mode 100644
index 0000000000..f911e58b48
--- /dev/null
+++ b/challenge-165/wanderdoc/perl/my_svg.pm
@@ -0,0 +1,135 @@
+#!perl
+use strict;
+use warnings FATAL => qw(all);
+
+use XML::Writer;
+
+
+my $MIN_X = my $MIN_Y = 1e6;
+my $MAX_X = my $MAX_Y = 0;
+
+
+
+
+
+
+
+
+
+sub create_svg
+{
+ my @these_points = @{$_[0]};
+ my @these_lines = @{$_[1]};
+ _calculate_sizes(@_[0,1]);
+
+
+
+ my $color_point = '#0000CD';
+ my $color_line = '#CD0000';
+ my $color_background = '#E5E5E5';
+ my $font = 'bold 20px sans-serif';
+ my $size_point = 3;
+ my $size_line = 3;
+
+ my ($buffer_x, $buffer_y) = (0, 0);
+
+ my $slope = $_[2];
+ my $intercept = $_[3];
+
+
+ if ( $MIN_X < 0 ) { $buffer_x = abs($MIN_X); }
+ if ( $MIN_Y < 0 ) { $buffer_y = abs($MIN_Y); }
+ my $buffer_aesthetic = 10;
+ my $width = $MAX_X + $buffer_x + $buffer_aesthetic; # print $width, $/;
+ my $height = $MAX_Y + $buffer_y + $buffer_aesthetic; # print $height, $/;
+
+ my $writer = XML::Writer->new( OUTPUT => 'self');
+ $writer->xmlDecl("UTF-8");
+
+
+ $writer->doctype('svg',
+ "-//W3C//DTD SVG 1.0//EN",
+ "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd");
+
+ $writer->startTag('svg', height => $height, width => $width,
+ xmlns => 'http://www.w3.org/2000/svg',
+ 'xmlns:svg' => 'http://www.w3.org/2000/svg',
+ 'xmlns:xlink' => 'http://www.w3.org/1999/xlink');
+
+
+
+ $writer->emptyTag('rect', width => "100%",, height => "100%",
+ fill => ${color_background});
+
+ if ( scalar @these_points )
+ {
+ $writer->startTag('g', 'fill' => $color_point, 'id' => "points");
+
+ for my $point ( @these_points )
+ {
+ $writer->emptyTag('circle', cx => $point->{x} + $buffer_x,
+ cy => _converse_y($point->{y} + $buffer_y, $height), r => $size_point);
+ }
+
+ $writer->endTag('g');
+ }
+
+ if ( scalar @these_lines )
+ {
+ $writer->startTag('g', id => "lines", 'stroke' => $color_line, 'stroke-width' => $size_line);
+ for my $line ( @these_lines )
+ {
+ $writer->emptyTag('line', x1 => $line->{x1} + $buffer_x, x2 => $line->{x2} + $buffer_x,
+ y1 => _converse_y($line->{y1} + $buffer_y, $height),
+ y2 => _converse_y($line->{y2} + $buffer_y, $height));
+
+ }
+ $writer->endTag('g');
+ }
+
+ if ( $slope and $intercept )
+ {
+ $_ = sprintf("%.5f", $_) for ($slope, $intercept); # $slope = sprintf("%.5f", $slope);
+ my $regression = "y = $slope * x + $intercept";
+
+ $writer->startTag('text', x => $buffer_aesthetic, y => _converse_y($buffer_aesthetic, $height),
+ fill => $color_line, style=> "font: ${font};");
+ $writer->characters($regression);
+ $writer->endTag('text');
+ }
+
+ $writer->endTag('svg');
+ $writer->end();
+
+
+ return $writer->to_string;
+}
+
+
+sub _calculate_sizes
+{
+ my @these_points = @{$_[0]};
+ my @these_lines = @{$_[1]};
+
+ _change_min_max($_->{x}, $_->{y}) for @these_points;
+ _change_min_max($_->{x1}, $_->{y1}) for @these_lines;
+ _change_min_max($_->{x2}, $_->{y2}) for @these_lines;
+}
+
+sub _change_min_max
+{
+
+ my ( $x, $y ) = @_;
+ if ( $x < $MIN_X ) { $MIN_X = $x; }
+ if ( $x > $MAX_X ) { $MAX_X = $x; }
+ if ( $y < $MIN_Y ) { $MIN_Y = $y; }
+ if ( $y > $MAX_Y ) { $MAX_Y = $y; }
+}
+
+sub _converse_y
+{
+ my ($this_y, $height) = @_;
+ return $height - $this_y;
+}
+
+1; \ No newline at end of file