aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohammad Sajid Anwar <Mohammad.Anwar@yahoo.com>2024-06-18 20:12:05 +0100
committerGitHub <noreply@github.com>2024-06-18 20:12:05 +0100
commitddbcbfcba49f227dc537c59c6a8f172f8a1e4390 (patch)
treec71878136f517dac0e22f1568b02a34721a1580f
parent2c8b134f83b8c30b9d30655942a6e5b81c2489f8 (diff)
parent1c6cd189ee4f8416961ec458aebe5449accc7aaf (diff)
downloadperlweeklychallenge-club-ddbcbfcba49f227dc537c59c6a8f172f8a1e4390.tar.gz
perlweeklychallenge-club-ddbcbfcba49f227dc537c59c6a8f172f8a1e4390.tar.bz2
perlweeklychallenge-club-ddbcbfcba49f227dc537c59c6a8f172f8a1e4390.zip
Merge pull request #10284 from Firedrake/rogerbw-challenge-274
RogerBW solutions for challenge no. 274
-rwxr-xr-xchallenge-274/roger-bell-west/crystal/ch-1.cr32
-rwxr-xr-xchallenge-274/roger-bell-west/crystal/ch-2.cr57
-rwxr-xr-xchallenge-274/roger-bell-west/javascript/ch-1.js40
-rwxr-xr-xchallenge-274/roger-bell-west/javascript/ch-2.js93
-rw-r--r--challenge-274/roger-bell-west/kotlin/ch-1.kt48
-rw-r--r--challenge-274/roger-bell-west/kotlin/ch-2.kt61
-rwxr-xr-xchallenge-274/roger-bell-west/lua/ch-1.lua86
-rwxr-xr-xchallenge-274/roger-bell-west/lua/ch-2.lua104
-rwxr-xr-xchallenge-274/roger-bell-west/perl/ch-1.pl28
-rwxr-xr-xchallenge-274/roger-bell-west/perl/ch-2.pl57
-rw-r--r--challenge-274/roger-bell-west/postscript/ch-1.ps158
-rw-r--r--challenge-274/roger-bell-west/postscript/ch-2.ps221
-rwxr-xr-xchallenge-274/roger-bell-west/python/ch-1.py33
-rwxr-xr-xchallenge-274/roger-bell-west/python/ch-2.py47
-rwxr-xr-xchallenge-274/roger-bell-west/raku/ch-1.p626
-rwxr-xr-xchallenge-274/roger-bell-west/raku/ch-2.p651
-rwxr-xr-xchallenge-274/roger-bell-west/ruby/ch-1.rb37
-rwxr-xr-xchallenge-274/roger-bell-west/ruby/ch-2.rb63
-rwxr-xr-xchallenge-274/roger-bell-west/rust/ch-1.rs47
-rwxr-xr-xchallenge-274/roger-bell-west/rust/ch-2.rs68
-rw-r--r--challenge-274/roger-bell-west/scala/ch-1.scala49
-rw-r--r--challenge-274/roger-bell-west/scala/ch-2.scala65
-rw-r--r--challenge-274/roger-bell-west/tests.json35
23 files changed, 1506 insertions, 0 deletions
diff --git a/challenge-274/roger-bell-west/crystal/ch-1.cr b/challenge-274/roger-bell-west/crystal/ch-1.cr
new file mode 100755
index 0000000000..ae0cc9b8e5
--- /dev/null
+++ b/challenge-274/roger-bell-west/crystal/ch-1.cr
@@ -0,0 +1,32 @@
+#! /usr/bin/crystal
+
+def goatlatin(a)
+ out = [] of String
+ a.split(" ").each_with_index do |word, ix|
+ c = word.split("")
+ if c[0] !~ /[aeiou]/i
+ co = c.shift;
+ c.push(co)
+ end
+ nw = c.join("")
+ nw += "ma"
+ 0.upto(ix) do
+ nw += "a"
+ end
+ out.push(nw)
+ end
+ out.join(" ")
+end
+
+require "spec"
+describe "goatlatin" do
+ it "test_ex1" do
+ goatlatin("I love Perl").should eq "Imaa ovelmaaa erlPmaaaa"
+ end
+ it "test_ex2" do
+ goatlatin("Perl and Raku are friends").should eq "erlPmaa andmaaa akuRmaaaa aremaaaaa riendsfmaaaaaa"
+ end
+ it "test_ex3" do
+ goatlatin("The Weekly Challenge").should eq "heTmaa eeklyWmaaa hallengeCmaaaa"
+ end
+end
diff --git a/challenge-274/roger-bell-west/crystal/ch-2.cr b/challenge-274/roger-bell-west/crystal/ch-2.cr
new file mode 100755
index 0000000000..36f4fa8789
--- /dev/null
+++ b/challenge-274/roger-bell-west/crystal/ch-2.cr
@@ -0,0 +1,57 @@
+#! /usr/bin/crystal
+
+def busroute(a)
+ route = [] of Hash(Int32, Int32)
+ a.each do |rt|
+ ri = Hash(Int32, Int32).new
+ interval, offset, duration = rt
+ start = offset
+ while true
+ if start > 60 + offset
+ break
+ end
+ ri[start] = start + duration
+ start += interval
+ end
+ route.push(ri)
+ end
+ out = [] of Int32
+ 0.upto(59) do |t|
+ best = Set(Int32).new
+ at = -1
+ nxt = Set(Int32).new
+ ndt = -1
+ route.each_with_index do |r, i|
+ nb = r.keys.select { |n| n >= t }.min
+ nt = r[nb]
+ if at == -1 || nt < at
+ best.clear
+ at = nt
+ end
+ if nt <= at
+ best.add(i)
+ end
+ if ndt == -1 || nb < ndt
+ nxt.clear
+ ndt = nb
+ end
+ if nb <= ndt
+ nxt.add(i)
+ end
+ end
+ if (best & nxt) .size == 0
+ out.push(t)
+ end
+ end
+ out
+end
+
+require "spec"
+describe "busroute" do
+ it "test_ex1" do
+ busroute([[12, 11, 41], [15, 5, 35]]).should eq [36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47]
+ end
+ it "test_ex2" do
+ busroute([[12, 3, 41], [15, 9, 35], [30, 5, 25]]).should eq [0, 1, 2, 3, 25, 26, 27, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 55, 56, 57, 58, 59]
+ end
+end
diff --git a/challenge-274/roger-bell-west/javascript/ch-1.js b/challenge-274/roger-bell-west/javascript/ch-1.js
new file mode 100755
index 0000000000..b300b4d51f
--- /dev/null
+++ b/challenge-274/roger-bell-west/javascript/ch-1.js
@@ -0,0 +1,40 @@
+#! /usr/bin/node
+
+"use strict"
+
+function goatlatin(a) {
+ let out = [];
+ a.split(" ").forEach((word, ix) => {
+ let c = word.split("");
+ if (!c[0].match(/[aeiou]/i)) {
+ let co = c.shift();
+ c.push(co);
+ }
+ let nw = c.join("");
+ nw += "ma";
+ for (let i = 0; i <= ix; i++) {
+ nw += "a";
+ }
+ out.push(nw)
+ });
+ return out.join(" ");
+}
+
+if (goatlatin('I love Perl') == 'Imaa ovelmaaa erlPmaaaa') {
+ process.stdout.write("Pass");
+} else {
+ process.stdout.write("FAIL");
+}
+process.stdout.write(" ");
+if (goatlatin('Perl and Raku are friends') == 'erlPmaa andmaaa akuRmaaaa aremaaaaa riendsfmaaaaaa') {
+ process.stdout.write("Pass");
+} else {
+ process.stdout.write("FAIL");
+}
+process.stdout.write(" ");
+if (goatlatin('The Weekly Challenge') == 'heTmaa eeklyWmaaa hallengeCmaaaa') {
+ process.stdout.write("Pass");
+} else {
+ process.stdout.write("FAIL");
+}
+process.stdout.write("\n");
diff --git a/challenge-274/roger-bell-west/javascript/ch-2.js b/challenge-274/roger-bell-west/javascript/ch-2.js
new file mode 100755
index 0000000000..a067c154bb
--- /dev/null
+++ b/challenge-274/roger-bell-west/javascript/ch-2.js
@@ -0,0 +1,93 @@
+#! /usr/bin/node
+
+"use strict"
+
+// by Frank Tan
+// https://stackoverflow.com/questions/38400594/javascript-deep-comparison
+function deepEqual(a,b)
+{
+ if( (typeof a == 'object' && a != null) &&
+ (typeof b == 'object' && b != null) )
+ {
+ var count = [0,0];
+ for( var key in a) count[0]++;
+ for( var key in b) count[1]++;
+ if( count[0]-count[1] != 0) {return false;}
+ for( var key in a)
+ {
+ if(!(key in b) || !deepEqual(a[key],b[key])) {return false;}
+ }
+ for( var key in b)
+ {
+ if(!(key in a) || !deepEqual(b[key],a[key])) {return false;}
+ }
+ return true;
+ }
+ else
+ {
+ return a === b;
+ }
+}
+
+function busroute(a) {
+ let route = [];
+ for (let rt of a) {
+ let ri = new Map;
+ const interval = rt[0];
+ const offset = rt[1];
+ const duration = rt[2];
+ let start = offset;
+ while (true) {
+ if (start > 60 + offset) {
+ break;
+ }
+ ri.set(start, start + duration);
+ start += interval;
+ }
+ route.push(ri);
+ }
+ let out = [];
+ for (let t = 0; t < 60; t++) {
+ let best = new Set;
+ let at = -1;
+ let nxt = new Set;
+ let ndt = -1;
+ route.forEach((r, i) => {
+ const nb = Math.min(...([...r.keys()].filter(n => n >= t)));
+ const nt = r.get(nb);
+ if (at == -1 || nt < at) {
+ best = new Set;
+ at = nt;
+ }
+ if (nt <= at) {
+ best.add(i);
+ }
+ if (ndt == -1 || nb < ndt) {
+ nxt = new Set;
+ ndt = nb;
+ }
+ if (nb <= ndt) {
+ nxt.add(i);
+ }
+ });
+ const intersect = new Set([...best].filter(i => nxt.has(i)));
+ if (intersect.size == 0) {
+ out.push(t);
+ }
+ }
+ return out;
+}
+
+
+if (deepEqual(busroute([[12, 11, 41], [15, 5, 35]]), [36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47])) {
+ process.stdout.write("Pass");
+} else {
+ process.stdout.write("FAIL");
+}
+process.stdout.write(" ");
+if (deepEqual(busroute([[12, 3, 41], [15, 9, 35], [30, 5, 25]]), [0, 1, 2, 3, 25, 26, 27, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 55, 56, 57, 58, 59])) {
+ process.stdout.write("Pass");
+} else {
+ process.stdout.write("FAIL");
+}
+process.stdout.write("\n");
diff --git a/challenge-274/roger-bell-west/kotlin/ch-1.kt b/challenge-274/roger-bell-west/kotlin/ch-1.kt
new file mode 100644
index 0000000000..5e2e3bbb4c
--- /dev/null
+++ b/challenge-274/roger-bell-west/kotlin/ch-1.kt
@@ -0,0 +1,48 @@
+fun is_vowel(c: Char): Boolean {
+ return when (c.lowercaseChar()) {
+ 'a', 'e', 'i', 'o', 'u' -> true
+ else -> false
+ }
+}
+
+fun goatlatin(a: String): String {
+ var out = ArrayList<String>()
+ a.split(" ").forEachIndexed {i, word ->
+ var c = word.toList()
+ var nw = StringBuilder(word);
+ if (!is_vowel(c[0])) {
+ var co = ArrayList(c.drop(1))
+ co.add(c[0])
+ nw = StringBuilder(co.joinToString(""))
+ }
+ nw.append("ma")
+ for (ix in 0..i) {
+ nw.append("a")
+ }
+ out.add(nw.toString())
+ }
+ return out.joinToString(" ")
+}
+
+fun main() {
+
+ if (goatlatin("I love Perl") == "Imaa ovelmaaa erlPmaaaa") {
+ print("Pass")
+ } else {
+ print("Fail")
+ }
+ print(" ")
+ if (goatlatin("Perl and Raku are friends") == "erlPmaa andmaaa akuRmaaaa aremaaaaa riendsfmaaaaaa") {
+ print("Pass")
+ } else {
+ print("Fail")
+ }
+ print(" ")
+ if (goatlatin("The Weekly Challenge") == "heTmaa eeklyWmaaa hallengeCmaaaa") {
+ print("Pass")
+ } else {
+ print("Fail")
+ }
+ println("")
+
+}
diff --git a/challenge-274/roger-bell-west/kotlin/ch-2.kt b/challenge-274/roger-bell-west/kotlin/ch-2.kt
new file mode 100644
index 0000000000..a09d3869a4
--- /dev/null
+++ b/challenge-274/roger-bell-west/kotlin/ch-2.kt
@@ -0,0 +1,61 @@
+fun busroute(a: List<List<Int>>): List<Int> {
+ var route = ArrayList<Map<Int, Int>>()
+ for (rt in a) {
+ var ri = mutableMapOf<Int, Int>()
+ val interval = rt[0]
+ val offset = rt[1]
+ val duration = rt[2]
+ var start = offset
+ while (start <= 60 + offset) {
+ ri.put(start, start + duration)
+ start += interval
+ }
+ route.add(ri)
+ }
+ var out = ArrayList<Int>()
+ for (t in 0 .. 59) {
+ var best = mutableSetOf<Int>()
+ var at = -1
+ var nxt = mutableSetOf<Int>()
+ var ndt = -1
+ route.forEachIndexed {i, r ->
+ val nb = r.keys.filter{it >= t}.minOrNull()!!
+ val nt = r.getValue(nb)
+ if (at == -1 || nt < at) {
+ best = mutableSetOf<Int>()
+ at = nt
+ }
+ if (nt <= at) {
+ best.add(i)
+ }
+ if (ndt == -1 || nb < ndt) {
+ nxt = mutableSetOf<Int>()
+ ndt = nb
+ }
+ if (nb <= ndt) {
+ nxt.add(i)
+ }
+ }
+ if (best.intersect(nxt).isEmpty()) {
+ out.add(t)
+ }
+ }
+ return out.toList()
+}
+
+fun main() {
+
+ if (busroute(listOf(listOf(12, 11, 41), listOf(15, 5, 35))) == listOf(36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47)) {
+ print("Pass")
+ } else {
+ print("Fail")
+ }
+ print(" ")
+ if (busroute(listOf(listOf(12, 3, 41), listOf(15, 9, 35), listOf(30, 5, 25))) == listOf(0, 1, 2, 3, 25, 26, 27, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 55, 56, 57, 58, 59)) {
+ print("Pass")
+ } else {
+ print("Fail")
+ }
+ println("")
+
+}
diff --git a/challenge-274/roger-bell-west/lua/ch-1.lua b/challenge-274/roger-bell-west/lua/ch-1.lua
new file mode 100755
index 0000000000..1127f03cb4
--- /dev/null
+++ b/challenge-274/roger-bell-west/lua/ch-1.lua
@@ -0,0 +1,86 @@
+#! /usr/bin/lua
+
+-- bart at https://stackoverflow.com/questions/1426954/split-string-in-lua
+function splits(inputstr, sep)
+ sep=sep or '%s'
+ local t={}
+ for field,s in string.gmatch(inputstr, "([^"..sep.."]*)("..sep.."?)") do
+ table.insert(t,field)
+ if s=="" then
+ return t
+ end
+ end
+end
+
+function split(t)
+ local cl = {}
+ string.gsub(t,
+ "(.)",
+ function(c)
+ table.insert(cl, c)
+ end
+ )
+ return cl
+end
+
+function join(t)
+ local out=""
+ for i, v in ipairs(t) do
+ out = out .. v
+ end
+ return out
+end
+
+function joins(t,pad)
+ local out=""
+ local later = false
+ for k,v in pairs(t) do
+ if later then
+ out = out .. pad
+ end
+ out = out .. v
+ later = true
+ end
+ return out
+end
+
+function goatlatin(a)
+ local out = {}
+ for ix, word in ipairs(splits(a, " ")) do
+ local nw = word
+ local c = split(word)
+ if string.match(c[1], "[^aeiouAEIOU]") then
+ table.insert(c, c[1])
+ table.remove(c, 1)
+ nw = join(c)
+ end
+ nw = nw .. "ma"
+ for i = 1, ix do
+ nw = nw .. "a"
+ end
+ table.insert(out, nw)
+ end
+ return joins(out, " ")
+end
+
+if goatlatin("I love Perl") == "Imaa ovelmaaa erlPmaaaa" then
+ io.write("Pass")
+else
+ io.write("FAIL")
+end
+io.write(" ")
+
+if goatlatin("Perl and Raku are friends") == "erlPmaa andmaaa akuRmaaaa aremaaaaa riendsfmaaaaaa" then
+ io.write("Pass")
+else
+ io.write("FAIL")
+end
+io.write(" ")
+
+if goatlatin("The Weekly Challenge") == "heTmaa eeklyWmaaa hallengeCmaaaa" then
+ io.write("Pass")
+else
+ io.write("FAIL")
+end
+print("")
+
diff --git a/challenge-274/roger-bell-west/lua/ch-2.lua b/challenge-274/roger-bell-west/lua/ch-2.lua
new file mode 100755
index 0000000000..2f50581f13
--- /dev/null
+++ b/challenge-274/roger-bell-west/lua/ch-2.lua
@@ -0,0 +1,104 @@
+#! /usr/bin/lua
+
+-- by Michael Anderson at
+-- https://stackoverflow.com/questions/8722620/comparing-two-index-tables-by-index-value-in-lua
+-- modified by Roger
+function recursive_compare(t1,t2)
+ -- Use usual comparison first.
+ if t1==t2 then return true end
+ -- We only support non-default behavior for tables
+ if (type(t1)~="table") then return false end
+ -- They better have the same metatables
+ local mt1 = getmetatable(t1)
+ local mt2 = getmetatable(t2)
+ if( not recursive_compare(mt1,mt2) ) then return false end
+ -- Build list of all keys
+ local kk = {}
+ for k1, _ in pairs(t1) do
+ kk[k1] = true
+ end
+ for k2, _ in pairs(t2) do
+ kk[k2] = true
+ end
+ -- Check each key that exists in at least one table
+ for _, k in ipairs(kk) do
+ if (not recursive_compare(t1[k], t2[k])) then
+ return false
+ end
+ end
+ return true
+end
+
+function busroute(a)
+ local routes = {}
+ for _, rt in ipairs(a) do
+ local ri = {}
+ local interval = rt[1]
+ local offset = rt[2]
+ local duration = rt[3]
+ local start = offset
+ while start <= 60 + offset do
+ ri[start] = start + duration
+ start = start + interval
+ end
+ table.insert(routes, rt)
+ end
+ local out = {}
+ for t = 0, 59 do
+ local best = {}
+ local at = -1
+ local nxt = {}
+ local ndt = -1
+ for i, r in ipairs(routes) do
+ local nb = 999
+ local nt = 0
+ for n, l in ipairs(r) do
+ if n >= t then
+ if l < nb then
+ nb = n
+ nt = l
+ end
+ end
+ end
+ if at == -1 or nt < at then
+ best = {}
+ at = nt
+ end
+ if nt <= at then
+ best[i] = true
+ end
+ if ndt == -1 or nb < ndt then
+ nxt = {}
+ ndt = nb
+ end
+ if nb <= ndt then
+ nxt[i] = true
+ end
+ end
+ local intersect = {}
+ for k, v in pairs(best) do
+ if nxt[k] ~= nil then
+ table.insert(intersect, k)
+ end
+ end
+ if #intersect == 0 then
+ table.insert(out, t)
+ end
+ end
+ return out
+end
+
+if recursive_compare(busroute({{12, 11, 41}, {15, 5, 35}}), {36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}) then
+ io.write("Pass")
+else
+ io.write("FAIL")
+end
+io.write(" ")
+
+if recursive_compare(busroute({{12, 3, 41}, {15, 9, 35}, {30, 5, 25}}), {0, 1, 2, 3, 25, 26, 27, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 55, 56, 57, 58, 59}) then
+ io.write("Pass")
+else
+ io.write("FAIL")
+end
+print("")
+
diff --git a/challenge-274/roger-bell-west/perl/ch-1.pl b/challenge-274/roger-bell-west/perl/ch-1.pl
new file mode 100755
index 0000000000..6cb6190b8c
--- /dev/null
+++ b/challenge-274/roger-bell-west/perl/ch-1.pl
@@ -0,0 +1,28 @@
+#! /usr/bin/perl
+
+use strict;
+use warnings;
+use experimental 'signatures';
+
+use Test::More tests => 3;
+
+is(goatlatin('I love Perl'), 'Imaa ovelmaaa erlPmaaaa', 'example 1');
+is(goatlatin('Perl and Raku are friends'), 'erlPmaa andmaaa akuRmaaaa aremaaaaa riendsfmaaaaaa', 'example 2');
+is(goatlatin('The Weekly Challenge'), 'heTmaa eeklyWmaaa hallengeCmaaaa', 'example 3');
+
+sub goatlatin($a) {
+ my @out;
+ my @w = split ' ', $a;
+ while (my ($ix, $word) = each @w) {
+ my @c = split '',$word;
+ my $nw = $word;
+ if ($c[0] !~ /[aeiou]/i) {
+ push @c,shift @c;
+ $nw = join('', @c);
+ }
+ $nw .= 'ma';
+ $nw .= 'a' x ($ix + 1);
+ push @out, $nw;
+ }
+ return join(' ', @out);
+}
diff --git a/challenge-274/roger-bell-west/perl/ch-2.pl b/challenge-274/roger-bell-west/perl/ch-2.pl
new file mode 100755
index 0000000000..5a3ee1c7ae
--- /dev/null
+++ b/challenge-274/roger-bell-west/perl/ch-2.pl
@@ -0,0 +1,57 @@
+#! /usr/bin/perl
+
+use strict;
+use warnings;
+use experimental 'signatures';
+
+use Test::More tests => 2;
+
+is_deeply(busroute([[12, 11, 41], [15, 5, 35]]), [36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47], 'example 1');
+is_deeply(busroute([[12, 3, 41], [15, 9, 35], [30, 5, 25]]), [0, 1, 2, 3, 25, 26, 27, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 55, 56, 57, 58, 59], 'example 2');
+
+use List::Util qw(min);
+
+sub busroute($a) {
+ my @routes;
+ foreach my $rt (@{$a}) {
+ my %ri;
+ my ($interval, $offset, $duration) = @{$rt};
+ my $start = $offset;
+ while ($start <= 60 + $offset) {
+ $ri{$start} = $start + $duration;
+ $start += $interval;
+ }
+ push @routes, \%ri;
+ }
+ my @out;
+ foreach my $t (0 .. 59) {
+ my %best;
+ my $at = -1;
+ my %nxt;
+ my $ndt = -1;
+ values @routes;
+ while (my ($i, $r) = each @routes) {
+ my $nb = min grep {$_ >= $t} keys(%{$r});
+ my $nt = $r->{$nb};
+ if ($at == -1 || $nt < $at) {
+ %best = ();
+ $at = $nt;
+ }
+ if ($nt <= $at) {
+ $best{$i} = 1;
+ }
+ if ($ndt == -1 || $nb < $ndt) {
+ %nxt = ();
+ $ndt = $nb;
+ }
+ if ($nb <= $ndt) {
+ $nxt{$i} = 1;
+ }
+ }
+ my @intersect = grep {exists $nxt{$_}} keys %best;
+ if (scalar @intersect == 0) {
+ push @out, $t;
+ }
+ }
+ return \@out;
+}
diff --git a/challenge-274/roger-bell-west/postscript/ch-1.ps b/challenge-274/roger-bell-west/postscript/ch-1.ps
new file mode 100644
index 0000000000..09be170853
--- /dev/null
+++ b/challenge-274/roger-bell-west/postscript/ch-1.ps
@@ -0,0 +1,158 @@
+%!PS
+
+% begin included library code
+% see https://codeberg.org/Firedrake/postscript-libraries/
+/strconcat % (a) (b) -> (ab)
+{
+ [
+ 3 -1 roll
+ s2a aload length
+ 2 add -1 roll
+ s2a aload pop
+ ] a2s
+} bind def
+
+/a2s {
+ 2 dict begin
+ /i exch def
+ i length dup string /o exch def
+ 1 sub 0 exch 1 exch {
+ dup i 3 -1 roll get o 3 1 roll put
+ } for
+ o
+ end
+} bind def
+
+
+/test.end {
+ ( ) print
+ test.count 0 gt {
+ (Passed ) print
+ test.pass (...) cvs print
+ (/) print
+ test.count (...) cvs print
+ ( \() print
+ test.pass 100 mul test.count idiv (...) cvs print
+ (%\)) print
+ (\r\n) print
+ } if
+} bind def
+
+/toset { % array -> dict of (value, true)
+ << exch
+ {
+ true
+ } forall
+ >>
+} bind def
+
+/test.start {
+ print (:) print
+ /test.pass 0 def
+ /test.count 0 def
+} bind def
+
+/test {
+ /test.count test.count 1 add def
+ {
+ /test.pass test.pass 1 add def
+ } {
+ ( ) print
+ test.count (....) cvs print
+ (-fail) print
+ } ifelse
+} bind def
+
+/enumerate.array {
+ 1 dict begin
+ /a exch def
+ [
+ 0 1 a length 1 sub {
+ [ exch dup a exch get ]
+ } for
+ ]
+ end
+} bind def
+
+/strsplit % (ajbjc) (j) -> [ (a) (b) (c) ]
+{
+ 1 dict begin
+ /sep exch def
+ [ exch
+ {
+ dup length 0 eq {
+ pop
+ exit
+ } {
+ sep search {
+ exch pop
+ dup length 0 eq {
+ pop
+ } {
+ exch
+ } ifelse
+ } {
+ ()
+ } ifelse
+ } ifelse
+ } loop
+ ]
+ end
+} bind def
+
+/s2a {
+ [ exch { } forall ]
+} bind def
+
+/strjoin % [(a) (b) (c)] (j) -> (ajbjc)
+{
+ 3 dict begin
+ /j exch def
+ dup 0 get /out exch def
+ /first true def
+ {
+ first {
+ pop
+ /first false def
+ } {
+ out j strconcat
+ exch strconcat
+ /out exch def
+ } ifelse
+ } forall
+ out
+ end
+} bind def
+
+
+% end included library code
+
+/goatlatin {
+ 0 dict begin
+ /vowels (aeiouAEIOU) s2a toset def
+ [ exch
+ ( ) strsplit enumerate.array {
+ aload pop
+ /c exch s2a def
+ /i exch def
+ [
+ c aload pop
+ vowels c 0 get known not {
+ c length -1 roll
+ } if
+ 109
+ 97
+ i 1 add {
+ 97
+ } repeat
+ ] a2s
+ } forall
+ ] ( ) strjoin
+ end
+} bind def
+
+(goatlatin) test.start
+(I love Perl) goatlatin (Imaa ovelmaaa erlPmaaaa) eq test
+(Perl and Raku are friends) goatlatin (erlPmaa andmaaa akuRmaaaa aremaaaaa riendsfmaaaaaa) eq test
+(The Weekly Challenge) goatlatin (heTmaa eeklyWmaaa hallengeCmaaaa) eq test
+test.end
diff --git a/challenge-274/roger-bell-west/postscript/ch-2.ps b/challenge-274/roger-bell-west/postscript/ch-2.ps
new file mode 100644
index 0000000000..f34399caf4
--- /dev/null
+++ b/challenge-274/roger-bell-west/postscript/ch-2.ps
@@ -0,0 +1,221 @@
+%!PS
+
+% begin included library code
+% see https://codeberg.org/Firedrake/postscript-libraries/
+/test.start {
+ print (:) print
+ /test.pass 0 def
+ /test.count 0 def
+} bind def
+
+/set.intersection {
+ 4 dict begin
+ /s 0 dict def
+ /b exch def
+ /a exch def
+ a keys {
+ /k exch def
+ b k known {
+ s k true put
+ } if
+ } forall
+ s
+ end
+} bind def
+
+/test.end {
+ ( ) print
+ test.count 0 gt {
+ (Passed ) print
+ test.pass (...) cvs print
+ (/) print
+ test.count (...) cvs print
+ ( \() print
+ test.pass 100 mul test.count idiv (...) cvs print
+ (%\)) print
+ (\r\n) print
+ } if
+} bind def
+
+/keys { % dict -> array of dict keys
+ [ exch
+ {
+ pop
+ } forall
+ ]
+} bind def
+
+/deepeq {
+ 2 dict begin
+ /a exch def
+ /b exch def
+ a type b type eq {
+ a type /dicttype eq {
+ a length b length eq {
+ <<
+ a {
+ pop
+ true
+ } forall
+ b {
+ pop
+ true
+ } forall
+ >>
+ true exch
+ {
+ pop
+ dup a exch known {
+ dup b exch known {
+ dup a exch get exch b exch get deepeq not {
+ pop false
+ } if
+ } {
+ false
+ } ifelse
+ } {
+ false
+ } ifelse
+ } forall
+ } {
+ false
+ } ifelse
+ } {
+ a type dup /arraytype eq exch /stringtype eq or {
+ a length b length eq {
+ true
+ 0 1 a length 1 sub {
+ dup a exch get exch b exch get deepeq not {
+ pop false
+ exit
+ } if
+ } for
+ } {
+ false
+ } ifelse
+ } {
+ a b eq
+ } ifelse
+ } ifelse
+ } {
+ false
+ } ifelse
+ end
+} bind def
+
+/reduce { % array proc -> value
+ 2 dict begin
+ /p exch def
+ /a exch def
+ a 0 get
+ 1 1 a length 1 sub {
+ a exch get
+ p
+ } for
+ end
+} bind def
+
+/listmin {
+ { min } reduce
+} bind def
+
+/test {
+ /test.count test.count 1 add def
+ {
+ /test.pass test.pass 1 add def
+ } {
+ ( ) print
+ test.count (....) cvs print
+ (-fail) print
+ } ifelse
+} bind def
+
+/enumerate.array {
+ 1 dict begin
+ /a exch def
+ [
+ 0 1 a length 1 sub {
+ [ exch dup a exch get ]
+ } for
+ ]
+ end
+} bind def
+
+/filter { % array proc(bool) -> array
+ 1 dict begin
+ /p exch def
+ [ exch
+ {
+ dup p not
+ {
+ pop</