aboutsummaryrefslogtreecommitdiff
path: root/challenge-165
diff options
context:
space:
mode:
authorarnesom <arne@bbop.org>2022-05-22 22:21:58 +0200
committerarnesom <arne@bbop.org>2022-05-22 22:21:58 +0200
commita6eb1d94efeaae67661fe89dcbcdeb01b2d200ba (patch)
treea8bd1523e6231120d1aff7a1d1d2691063dc6895 /challenge-165
parentd9bb08876458314b070fa4679fa1ffc7a68b82a6 (diff)
downloadperlweeklychallenge-club-a6eb1d94efeaae67661fe89dcbcdeb01b2d200ba.tar.gz
perlweeklychallenge-club-a6eb1d94efeaae67661fe89dcbcdeb01b2d200ba.tar.bz2
perlweeklychallenge-club-a6eb1d94efeaae67661fe89dcbcdeb01b2d200ba.zip
Arne Sommer
Diffstat (limited to 'challenge-165')
-rw-r--r--challenge-165/arne-sommer/blog.txt1
-rw-r--r--challenge-165/arne-sommer/misc/czech_rep.txt3
-rw-r--r--challenge-165/arne-sommer/misc/example-lsm.txt5
-rw-r--r--challenge-165/arne-sommer/misc/example-lsm2.txt1
-rw-r--r--challenge-165/arne-sommer/misc/example1.txt3
-rw-r--r--challenge-165/arne-sommer/misc/example2.txt6
-rw-r--r--challenge-165/arne-sommer/misc/japan.txt2
-rw-r--r--challenge-165/arne-sommer/misc/norway.txt3
-rw-r--r--challenge-165/arne-sommer/misc/ukraine.txt2
-rw-r--r--challenge-165/arne-sommer/misc/union_jack.txt10
-rw-r--r--challenge-165/arne-sommer/misc/usa-ascii.txt12
-rw-r--r--challenge-165/arne-sommer/misc/usa.txt12
-rwxr-xr-xchallenge-165/arne-sommer/raku/ch-1.raku95
-rwxr-xr-xchallenge-165/arne-sommer/raku/ch-2.raku95
-rwxr-xr-xchallenge-165/arne-sommer/raku/mksvg-turbo165
-rwxr-xr-xchallenge-165/arne-sommer/raku/mksvg163
-rwxr-xr-xchallenge-165/arne-sommer/raku/mksvg263
-rwxr-xr-xchallenge-165/arne-sommer/raku/mksvg395
18 files changed, 636 insertions, 0 deletions
diff --git a/challenge-165/arne-sommer/blog.txt b/challenge-165/arne-sommer/blog.txt
new file mode 100644
index 0000000000..a6a759d6b2
--- /dev/null
+++ b/challenge-165/arne-sommer/blog.txt
@@ -0,0 +1 @@
+https://raku-musings.com/doubly-scalable.html
diff --git a/challenge-165/arne-sommer/misc/czech_rep.txt b/challenge-165/arne-sommer/misc/czech_rep.txt
new file mode 100644
index 0000000000..d525845135
--- /dev/null
+++ b/challenge-165/arne-sommer/misc/czech_rep.txt
@@ -0,0 +1,3 @@
+:fc:#FFFFFF r,0,0,6,2
+:fc:#d7141a r,0,2,6,2
+:fc:#11457e p,0,0,3,2,0,4
diff --git a/challenge-165/arne-sommer/misc/example-lsm.txt b/challenge-165/arne-sommer/misc/example-lsm.txt
new file mode 100644
index 0000000000..fd1494f1af
--- /dev/null
+++ b/challenge-165/arne-sommer/misc/example-lsm.txt
@@ -0,0 +1,5 @@
+2,4
+3,5
+5,7
+7,10
+9,15
diff --git a/challenge-165/arne-sommer/misc/example-lsm2.txt b/challenge-165/arne-sommer/misc/example-lsm2.txt
new file mode 100644
index 0000000000..04ea5cd9b4
--- /dev/null
+++ b/challenge-165/arne-sommer/misc/example-lsm2.txt
@@ -0,0 +1 @@
+2,4 3,5 :r:3 5,7 7,10 :r:5 :f:#ff0000 9,15
diff --git a/challenge-165/arne-sommer/misc/example1.txt b/challenge-165/arne-sommer/misc/example1.txt
new file mode 100644
index 0000000000..42acc2b70b
--- /dev/null
+++ b/challenge-165/arne-sommer/misc/example1.txt
@@ -0,0 +1,3 @@
+53,10
+53,10,23,30
+23,30
diff --git a/challenge-165/arne-sommer/misc/example2.txt b/challenge-165/arne-sommer/misc/example2.txt
new file mode 100644
index 0000000000..9e5ecc346a
--- /dev/null
+++ b/challenge-165/arne-sommer/misc/example2.txt
@@ -0,0 +1,6 @@
+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
diff --git a/challenge-165/arne-sommer/misc/japan.txt b/challenge-165/arne-sommer/misc/japan.txt
new file mode 100644
index 0000000000..6fd1009bfc
--- /dev/null
+++ b/challenge-165/arne-sommer/misc/japan.txt
@@ -0,0 +1,2 @@
+:fc:#FFFFFF r,0,0,30,20
+:cr:6 :cc:#bc002d 15,10
diff --git a/challenge-165/arne-sommer/misc/norway.txt b/challenge-165/arne-sommer/misc/norway.txt
new file mode 100644
index 0000000000..e216138e36
--- /dev/null
+++ b/challenge-165/arne-sommer/misc/norway.txt
@@ -0,0 +1,3 @@
+:fc:#BA0C2F r,0,0,22,16
+:fc:#ffffff r,6,0,4,16 r,0,6,22,4
+:fc:#00205B r,7,0,2,16 r,0,7,22,2
diff --git a/challenge-165/arne-sommer/misc/ukraine.txt b/challenge-165/arne-sommer/misc/ukraine.txt
new file mode 100644
index 0000000000..9f0d32273c
--- /dev/null
+++ b/challenge-165/arne-sommer/misc/ukraine.txt
@@ -0,0 +1,2 @@
+:fc:#0057b7 r,0,0,3,1
+:fc:#ffd700 r,0,1,3,1
diff --git a/challenge-165/arne-sommer/misc/union_jack.txt b/challenge-165/arne-sommer/misc/union_jack.txt
new file mode 100644
index 0000000000..b235d29621
--- /dev/null
+++ b/challenge-165/arne-sommer/misc/union_jack.txt
@@ -0,0 +1,10 @@
+:w:60 :h:30
+
+:fc:#012169 r,0,0,60,30
+
+:lw:6 :lc:#ffffff 0,0,60,30 0,30,60,0
+:lw:2 :lc:#C8102E -1.5,0,30,16 32.5,16,61.5,30
+ -1,31,29.5,16 30.5,14,61,-1
+
+:fc:#ffffff r,0,10,60,10 r,25,0,10,30
+:fc:#C8102E r,0,12,60,6 r,27,0,6,30
diff --git a/challenge-165/arne-sommer/misc/usa-ascii.txt b/challenge-165/arne-sommer/misc/usa-ascii.txt
new file mode 100644
index 0000000000..da091642f3
--- /dev/null
+++ b/challenge-165/arne-sommer/misc/usa-ascii.txt
@@ -0,0 +1,12 @@
+:fc:#B31942 r,0,0,250,10 r,0,20,250,10 r,0,40,250,10 r,0,60,250,10 r,0,80,250,10 r,0,100,250,10 r,0,120,250,10
+:fc:#FFFFFF r,0,10,250,10 r,0,30,250,10 r,0,50,250,10 r,0,70,250,10 r,0,90,250,10 r,0,110,250,10
+:fc:#0A3161 r,0,0,100,70
+:tc:#FFFFFF :th:15 :ls:5pt
+t,3,18,******
+t,11,27,*****
+t,3,36,******
+t,11,46,*****
+t,3,55,******
+t,11,64,*****
+t,3,73,******
+
diff --git a/challenge-165/arne-sommer/misc/usa.txt b/challenge-165/arne-sommer/misc/usa.txt
new file mode 100644
index 0000000000..88a07e5bfd
--- /dev/null
+++ b/challenge-165/arne-sommer/misc/usa.txt
@@ -0,0 +1,12 @@
+:fc:#B31942 r,0,0,250,10 r,0,20,250,10 r,0,40,250,10 r,0,60,250,10 r,0,80,250,10 r,0,100,250,10 r,0,120,250,10
+:fc:#FFFFFF r,0,10,250,10 r,0,30,250,10 r,0,50,250,10 r,0,70,250,10 r,0,90,250,10 r,0,110,250,10
+:fc:#0A3161 r,0,0,100,70
+:tc:#FFFFFF :th:9 :ls:4pt
+t,3,12,★★★★★★
+t,11,21,★★★★★
+t,3,30,★★★★★★
+t,11,39,★★★★★
+t,3,48,★★★★★★
+t,11,57,★★★★★
+t,3,66,★★★★★★
+
diff --git a/challenge-165/arne-sommer/raku/ch-1.raku b/challenge-165/arne-sommer/raku/ch-1.raku
new file mode 100755
index 0000000000..e37805ae44
--- /dev/null
+++ b/challenge-165/arne-sommer/raku/ch-1.raku
@@ -0,0 +1,95 @@
+#! /usr/bin/env raku
+
+unit sub MAIN ($file where $file.IO.f && $file.IO.r, :l(:$lsm));
+
+my @lines;
+my @points;
+my $height = 0;
+my $width = 0;
+
+for $file.IO.lines.words -> $element
+{
+ my (@elems) = $element.split(",");
+
+ if (@elems.elems == 4)
+ {
+ @lines.push: @elems;
+
+ $height = max($height, @elems[1], @elems[3].Numeric);
+ $width = max($width, @elems[0], @elems[2].Numeric);
+ }
+ elsif (@elems.elems == 2)
+ {
+ @points.push: @elems;
+
+ $height = max($height, @elems[1].Numeric);
+ $width = max($width, @elems[0].Numeric);
+ }
+ else
+ {
+ die "Wrong number of values; use 2 or 4 only";
+ }
+}
+
+if $lsm
+{
+ die "'Line of Best Fit' cannot be used with a dataset with lines" if @lines.elems;
+
+ my $x = 0;
+ my $y = 0;
+ my $xx = 0;
+ my $xy = 0;
+
+ my $N = @points.elems;
+
+ my $min-x = Inf;
+ my $max-x = 0;
+
+ for @points -> @point
+ {
+ my ($X, $Y) = @point;
+
+ $min-x = min($min-x, $X.Numeric);
+ $max-x = max($max-x, $X.Numeric);
+
+ $x += $X;
+ $y += $Y;
+ $xx += $X ** 2;
+ $xy += $X * $Y;
+ }
+
+ my $m = ($N * $xy - $x * $y) / ($N * $xx - $x ** 2);
+ my $b = ($y - $m * $x) / $N;
+
+ @lines.push(($min-x, ($m * $min-x) + $b, $max-x, ($m * $max-x) + $b));
+}
+
+say '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg height="' ~ $height +3 ~ '" width="' ~ $width +3 ~'" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">';
+
+if @points
+{
+ say '<g fill="#f73" id="points">';
+
+ for @points -> @point
+ {
+ say ' <circle cx="' ~ @point[0] ~ '" cy="' ~ @point[1] ~ '" r="3" />';
+ }
+
+ say '</g>';
+}
+
+if @lines
+{
+ say '<g id="lines" stroke="#369" stroke-width="4">';
+
+ for @lines -> @line
+ {
+ say ' <line x1="' ~ @line[0] ~ '" x2="' ~ @line[2] ~ '" y1="' ~ @line[1] ~ '" y2="' ~ @line[3] ~ '" />'
+ }
+
+ say '</g>';
+}
+
+say '</svg>';
diff --git a/challenge-165/arne-sommer/raku/ch-2.raku b/challenge-165/arne-sommer/raku/ch-2.raku
new file mode 100755
index 0000000000..e37805ae44
--- /dev/null
+++ b/challenge-165/arne-sommer/raku/ch-2.raku
@@ -0,0 +1,95 @@
+#! /usr/bin/env raku
+
+unit sub MAIN ($file where $file.IO.f && $file.IO.r, :l(:$lsm));
+
+my @lines;
+my @points;
+my $height = 0;
+my $width = 0;
+
+for $file.IO.lines.words -> $element
+{
+ my (@elems) = $element.split(",");
+
+ if (@elems.elems == 4)
+ {
+ @lines.push: @elems;
+
+ $height = max($height, @elems[1], @elems[3].Numeric);
+ $width = max($width, @elems[0], @elems[2].Numeric);
+ }
+ elsif (@elems.elems == 2)
+ {
+ @points.push: @elems;
+
+ $height = max($height, @elems[1].Numeric);
+ $width = max($width, @elems[0].Numeric);
+ }
+ else
+ {
+ die "Wrong number of values; use 2 or 4 only";
+ }
+}
+
+if $lsm
+{
+ die "'Line of Best Fit' cannot be used with a dataset with lines" if @lines.elems;
+
+ my $x = 0;
+ my $y = 0;
+ my $xx = 0;
+ my $xy = 0;
+
+ my $N = @points.elems;
+
+ my $min-x = Inf;
+ my $max-x = 0;
+
+ for @points -> @point
+ {
+ my ($X, $Y) = @point;
+
+ $min-x = min($min-x, $X.Numeric);
+ $max-x = max($max-x, $X.Numeric);
+
+ $x += $X;
+ $y += $Y;
+ $xx += $X ** 2;
+ $xy += $X * $Y;
+ }
+
+ my $m = ($N * $xy - $x * $y) / ($N * $xx - $x ** 2);
+ my $b = ($y - $m * $x) / $N;
+
+ @lines.push(($min-x, ($m * $min-x) + $b, $max-x, ($m * $max-x) + $b));
+}
+
+say '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg height="' ~ $height +3 ~ '" width="' ~ $width +3 ~'" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">';
+
+if @points
+{
+ say '<g fill="#f73" id="points">';
+
+ for @points -> @point
+ {
+ say ' <circle cx="' ~ @point[0] ~ '" cy="' ~ @point[1] ~ '" r="3" />';
+ }
+
+ say '</g>';
+}
+
+if @lines
+{
+ say '<g id="lines" stroke="#369" stroke-width="4">';
+
+ for @lines -> @line
+ {
+ say ' <line x1="' ~ @line[0] ~ '" x2="' ~ @line[2] ~ '" y1="' ~ @line[1] ~ '" y2="' ~ @line[3] ~ '" />'
+ }
+
+ say '</g>';
+}
+
+say '</svg>';
diff --git a/challenge-165/arne-sommer/raku/mksvg-turbo b/challenge-165/arne-sommer/raku/mksvg-turbo
new file mode 100755
index 0000000000..88a0db172a
--- /dev/null
+++ b/challenge-165/arne-sommer/raku/mksvg-turbo
@@ -0,0 +1,165 @@
+#! /usr/bin/env raku
+
+unit sub MAIN ($file where $file.IO.f && $file.IO.r, :l(:$lsm));
+
+my $height = 0;
+my $width = 0;
+my $padding = 0;
+my $line-width = 4;
+my $line-colour = "#336699";
+my $circle-radius = 3;
+my $circle-colour = "#FF7733";
+my $fill-colour = "#000000";
+my $text-height = 8;
+my $text-font = "sans-serif";
+my $text-colour = "#ffffff";
+my $letter-spacing = 'normal';
+my $fixed-height = False;
+my $fixed-width = False;
+my @svg;
+my @points;
+
+for $file.IO.lines.words -> $element
+{
+ my (@elems) = $element.split(",");
+
+ if (@elems.elems == 1)
+ {
+ if @elems[0] ~~ /^\:h\:(\d+)$/
+ {
+ $height = $0.Numeric; $fixed-height = True;
+ }
+ elsif @elems[0] ~~ /^\:w\:(\d+)$/
+ {
+ $width = $0.Numeric; $fixed-width = True;
+ }
+ elsif @elems[0] ~~ /^\:p\:(\d+)$/
+ {
+ $padding = $0.Numeric;
+ }
+ elsif @elems[0] ~~ /^\:cr\:(\d+)$/
+ {
+ $circle-radius = $0.Numeric;
+ }
+ elsif @elems[0] ~~ /^\:lw\:(\d+)$/
+ {
+ $line-width = $0.Numeric;
+ }
+ elsif @elems[0] ~~ /^\:lc\:(\#......)$/
+ {
+ $line-colour = $0.Str;
+ }
+ elsif @elems[0] ~~ /^\:fc\:(\#......)$/
+ {
+ $fill-colour = $0.Str;
+ }
+ elsif @elems[0] ~~ /^\:cc\:(\#......)$/
+ {
+ $circle-colour = $0.Str;
+ }
+ elsif @elems[0] ~~ /^\:tc\:(\#......)$/
+ {
+ $text-colour = $0.Str;
+ }
+ elsif @elems[0] ~~ /^\:tf\:(.+)$/
+ {
+ $text-font = $0.Str;
+ }
+ elsif @elems[0] ~~ /^\:th\:(\d+)$/
+ {
+ $text-height = $0.Numeric;
+ }
+ elsif @elems[0] ~~ /^\:ls\:(.+)$/
+ {
+ $letter-spacing = $0.Str;
+ }
+ else {
+ die "Illegal: @elems[0]";
+ }
+ }
+
+ elsif (@elems.elems == 2)
+ {
+ @svg.push: '<circle cx="' ~ @elems[0] ~ '" cy="' ~ @elems[1] ~ '" r="' ~ $circle-radius ~ '" fill="' ~ $circle-colour ~ '"/>';
+
+ @points.push: @elems if $lsm;
+
+ $height = max($height, @elems[1].Numeric) unless $fixed-height;
+ $width = max($width, @elems[0].Numeric) unless $fixed-width;
+ }
+ elsif (@elems[0] eq "p")
+ {
+ my $svg = '<polygon points="';
+
+ my @points = @elems[1 .. Inf];
+ while (@points.elems >= 2)
+ {
+ $svg ~= @points.shift ~ "," ~ @points.shift ~ " ";
+ }
+ $svg ~= '" style="fill: ' ~ $fill-colour ~ ';"/>';
+ @svg.push: $svg;
+ }
+ elsif (@elems.elems == 4 && @elems[0] eq "t")
+ {
+ @svg.push: '<text x="' ~ @elems[1] ~ '" y="' ~ @elems[2] ~ '" style="font-family: ' ~ $text-font ~ '; font-size: '
+ ~ $text-height ~ 'pt; stroke: none; fill:' ~ $text-colour ~ '; letter-spacing: ' ~ $letter-spacing ~ ';">' ~ @elems[3] ~ '</text>';
+ }
+ elsif (@elems.elems == 4)
+ {
+ @svg.push: '<line x1="' ~ @elems[0] ~ '" x2="' ~ @elems[2] ~ '" y1="' ~ @elems[1] ~ '" y2="' ~ @elems[3] ~ '" stroke-width="' ~ $line-width ~ '" stroke="' ~ $line-colour ~ '"/>';
+
+ $height = max($height, @elems[1], @elems[3].Numeric) unless $fixed-height;
+ $width = max($width, @elems[0], @elems[2].Numeric) unless $fixed-width;
+ }
+ elsif (@elems.elems == 5 && @elems[0] eq "r")
+ {
+ @svg.push: '<rect x="' ~ @elems[1] ~ '" y="' ~ @elems[2] ~ '" width="' ~ @elems[3] ~ '" height="' ~ @elems[4] ~ '" fill="' ~ $fill-colour ~ '"/>';
+
+ $height = max($height, @elems[2] + @elems[4]) unless $fixed-height;
+ $width = max($width, @elems[1] + @elems[3]) unless $fixed-width;
+ }
+
+
+ else
+ {
+ die "Wrong number of values; use 2 or 4 only";
+ }
+}
+
+if $lsm
+{
+ my $x = 0;
+ my $y = 0;
+ my $xx = 0;
+ my $xy = 0;
+
+ my $N = @points.elems;
+
+ my $min-x = Inf;
+ my $max-x = 0;
+
+ for @points -> @point
+ {
+ my ($X, $Y) = @point;
+
+ $min-x = min($min-x, $X.Numeric);
+ $max-x = max($max-x, $X.Numeric);
+
+ $x += $X;
+ $y += $Y;
+ $xx += $X ** 2;
+ $xy += $X * $Y;
+ }
+
+ my $m = ($N * $xy - $x * $y) / ($N * $xx - $x ** 2);
+ my $b = ($y - $m * $x) / $N;
+
+ @svg.push: ' <line x1="' ~ $min-x ~ '" y1="' ~ ($m * $min-x) + $b ~ '" x2="' ~ $max-x ~ '" y2="' ~ ($m * $max-x) + $b ~ '" stroke-width="' ~ $line-width ~ '" stroke="' ~ $line-colour ~ '"/>';
+}
+
+say '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg height="' ~ $height + $padding ~ '" width="' ~ $width + $padding ~'" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">';
+
+say @svg.join("\n");
+say '</svg>';
diff --git a/challenge-165/arne-sommer/raku/mksvg1 b/challenge-165/arne-sommer/raku/mksvg1
new file mode 100755
index 0000000000..8ec47d096c
--- /dev/null
+++ b/challenge-165/arne-sommer/raku/mksvg1
@@ -0,0 +1,63 @@
+#! /usr/bin/env raku
+
+unit sub MAIN ($file where $file.IO.f && $file.IO.r);
+
+my @lines;
+my @points;
+my $height = 0;
+my $width = 0;
+
+for $file.IO.lines -> $row
+{
+ my (@elems) = $row.split(",");
+
+ if (@elems.elems == 4)
+ {
+ @lines.push: @elems;
+
+ $height = max($height, @elems[1], @elems[3].Numeric);
+ $width = max($width, @elems[0], @elems[2].Numeric);
+ }
+ elsif (@elems.elems == 2)
+ {
+ @points.push: @elems;
+
+ $height = max($height, @elems[1].Numeric);
+ $width = max($width, @elems[0].Numeric);
+ }
+ else
+ {
+ die "Wrong number of values; use 2 or 4 only";
+ }
+}
+
+say '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<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">';
+
+if @lines
+{
+ say '<g id="lines" stroke="#369" stroke-width="4">';
+
+ for @lines -> @line
+ {
+ say ' <line x1="' ~ @line[0] ~ '" x2="' ~ @line[2] ~ '" y1="' ~ @line[1] ~ '" y2="' ~ @line[3] ~ '" />'
+ }
+
+ say '</g>';
+}
+
+if @points
+{
+ say '<g fill="#f73" id="points">';
+
+ for @points -> @point
+ {
+ say ' <circle cx="' ~ @point[0] ~ '" cy="' ~ @point[1] ~ '" r="3" />';
+ }
+
+ say '</g>';
+}
+
+say '</svg>';
+
diff --git a/challenge-165/arne-sommer/raku/mksvg2 b/challenge-165/arne-sommer/raku/mksvg2
new file mode 100755
index 0000000000..1800f5b90b
--- /dev/null
+++ b/challenge-165/arne-sommer/raku/mksvg2
@@ -0,0 +1,63 @@
+#! /usr/bin/env raku
+
+unit sub MAIN ($file where $file.IO.f && $file.IO.r);
+
+my @lines;
+my @points;
+my $height = 0;
+my $width = 0;
+
+for $file.IO.lines -> $element
+{
+ my (@elems) = $element.split(",");
+
+ if (@elems.elems == 4)
+ {
+ @lines.push: @elems;
+
+ $height = max($height, @elems[1], @elems[3].Numeric);
+ $width = max($width, @elems[0], @elems[2].Numeric);
+ }
+ elsif (@elems.elems == 2)
+ {
+ @points.push: @elems;
+
+ $height = max($height, @elems[1].Numeric);
+ $width = max($width, @elems[0].Numeric);
+ }
+ else
+ {
+ die "Wrong number of values; use 2 or 4 only";
+ }
+}
+
+say '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg height="' ~ $height +3 ~ '" width="' ~ $width +3 ~'" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">';
+
+if @lines
+{
+ say '<g id="lines" stroke="#369" stroke-width="4">';
+
+ for @lines -> @line
+ {
+ say ' <line x1="' ~ @line[0] ~ '" x2="' ~ @line[2] ~ '" y1="' ~ @line[1] ~ '" y2="' ~ @line[3] ~ '" />'
+ }
+
+ say '</g>';
+}
+
+if @points
+{
+ say '<g fill="#f73" id="points">';
+
+ for @points -> @point
+ {
+ say ' <circle cx="' ~ @point[0] ~ '" cy="' ~ @point[1] ~ '" r="3" />';
+ }
+
+ say '</g>';
+}
+
+say '</svg>';
+
diff --git a/challenge-165/arne-sommer/raku/mksvg3 b/challenge-165/arne-sommer/raku/mksvg3
new file mode 100755
index 0000000000..e37805ae44
--- /dev/null
+++ b/challenge-165/arne-sommer/raku/mksvg3
@@ -0,0 +1,95 @@
+#! /usr/bin/env raku
+
+unit sub MAIN ($file where $file.IO.f && $file.IO.r, :l(:$lsm));
+
+my @lines;
+my @points;
+my $height = 0;
+my $width = 0;
+
+for $file.IO.lines.words -> $element
+{
+ my (@elems) = $element.split(",");
+
+ if (@elems.elems == 4)
+ {
+ @lines.push: @elems;
+
+ $height = max($height, @elems[1], @elems[3].Numeric);
+ $width = max($width, @elems[0], @elems[2].Numeric);
+ }
+ elsif (@elems.elems == 2)
+ {
+ @points.push: @elems;
+
+ $height = max($height, @elems[1].Numeric);
+ $width = max($width, @elems[0].Numeric);
+ }
+ else
+ {
+ die "Wrong number of values; use 2 or 4 only";
+ }
+}
+
+if $lsm
+{
+ die "'Line of Best Fit' cannot be used with a dataset with lines" if @lines.elems;
+
+ my $x = 0;
+ my $y = 0;
+ my $xx = 0;
+ my $xy = 0;
+
+ my $N = @points.elems;
+
+ my $min-x = Inf;
+ my $max-x = 0;
+
+ for @points -> @point
+ {
+ my ($X, $Y) = @point;
+
+ $min-x = min($min-x, $X.Numeric);
+ $max-x = max($max-x, $X.Numeric);
+
+ $x += $X;
+ $y += $Y;
+ $xx += $X ** 2;
+ $xy += $X * $Y;
+ }
+
+ my $m = ($N * $xy - $x * $y) / ($N * $xx - $x ** 2);
+ my $b = ($y - $m * $x) / $N;
+
+ @lines.push(($min-x, ($m * $min-x) + $b, $max-x, ($m * $max-x) + $b));
+}
+
+say '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg height="' ~ $height +3 ~ '" width="' ~ $width +3 ~'" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">';
+
+if @points
+{
+ say '<g fill="#f73" id="points">';
+
+ for @points -> @point
+ {
+ say ' <circle cx="' ~ @point[0] ~ '" cy="' ~ @point[1] ~ '" r="3" />';
+ }
+
+ say '</g>';
+}
+
+if @lines
+{
+ say '<g id="lines" stroke="#369" stroke-width="4">';
+
+ for @lines -> @line
+ {
+ say ' <line x1="' ~ @line[0] ~ '" x2="' ~ @line[2] ~ '" y1="' ~ @line[1] ~ '" y2="' ~ @line[3] ~ '" />'
+ }
+
+ say '</g>';
+}
+
+say '</svg>';