diff options
| author | Mohammad S Anwar <Mohammad.Anwar@yahoo.com> | 2022-05-22 21:39:14 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-05-22 21:39:14 +0100 |
| commit | 726d703455e52374ff4d703bc4f3f704786f45eb (patch) | |
| tree | c4ca565a49a54990a1e2a1121f84a8245d4b7bfe | |
| parent | ef704186cc608715275b0620cb62c781333c5a03 (diff) | |
| parent | 44eff7f683e537a808e8824328ec263b39e76404 (diff) | |
| download | perlweeklychallenge-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.pl | 65 | ||||
| -rw-r--r-- | challenge-165/wanderdoc/perl/ch-2.pl | 83 | ||||
| -rw-r--r-- | challenge-165/wanderdoc/perl/input.txt | 59 | ||||
| -rw-r--r-- | challenge-165/wanderdoc/perl/my_svg.pm | 135 |
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 |
