aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohammad S Anwar <Mohammad.Anwar@yahoo.com>2023-04-27 16:46:19 +0100
committerGitHub <noreply@github.com>2023-04-27 16:46:19 +0100
commitec4823ef5c8b87e9d98c55ca4e88f76484cf5cee (patch)
tree931729d1f88c4112b0293c00e772b198b515246e
parentcddf844d842a7e3906743c0649d59f2c68e44918 (diff)
parent12fa389d6e1dc5ab45926f20d9bc3eff560dbd52 (diff)
downloadperlweeklychallenge-club-ec4823ef5c8b87e9d98c55ca4e88f76484cf5cee.tar.gz
perlweeklychallenge-club-ec4823ef5c8b87e9d98c55ca4e88f76484cf5cee.tar.bz2
perlweeklychallenge-club-ec4823ef5c8b87e9d98c55ca4e88f76484cf5cee.zip
Merge pull request #7973 from Firedrake/rogerbw-challenge-214
RogerBW solutions for challenge no. 214
-rwxr-xr-xchallenge-214/roger-bell-west/javascript/ch-1.js88
-rwxr-xr-xchallenge-214/roger-bell-west/javascript/ch-2.js70
-rw-r--r--challenge-214/roger-bell-west/kotlin/ch-1.kt58
-rw-r--r--challenge-214/roger-bell-west/kotlin/ch-2.kt73
-rwxr-xr-xchallenge-214/roger-bell-west/lua/ch-1.lua102
-rwxr-xr-xchallenge-214/roger-bell-west/lua/ch-2.lua86
-rwxr-xr-xchallenge-214/roger-bell-west/perl/ch-1.pl36
-rwxr-xr-xchallenge-214/roger-bell-west/perl/ch-2.pl57
-rw-r--r--challenge-214/roger-bell-west/postscript/ch-1.ps256
-rw-r--r--challenge-214/roger-bell-west/postscript/ch-2.ps178
-rwxr-xr-xchallenge-214/roger-bell-west/python/ch-1.py44
-rwxr-xr-xchallenge-214/roger-bell-west/python/ch-2.py53
-rwxr-xr-xchallenge-214/roger-bell-west/raku/ch-1.p634
-rwxr-xr-xchallenge-214/roger-bell-west/raku/ch-2.p652
-rwxr-xr-xchallenge-214/roger-bell-west/ruby/ch-1.rb51
-rwxr-xr-xchallenge-214/roger-bell-west/ruby/ch-2.rb63
-rwxr-xr-xchallenge-214/roger-bell-west/rust/ch-1.rs54
-rwxr-xr-xchallenge-214/roger-bell-west/rust/ch-2.rs65
-rw-r--r--challenge-214/roger-bell-west/tests.yaml87
19 files changed, 1507 insertions, 0 deletions
diff --git a/challenge-214/roger-bell-west/javascript/ch-1.js b/challenge-214/roger-bell-west/javascript/ch-1.js
new file mode 100755
index 0000000000..01464b4ec2
--- /dev/null
+++ b/challenge-214/roger-bell-west/javascript/ch-1.js
@@ -0,0 +1,88 @@
+#! /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 rankscore(a) {
+ let av = new Map;
+ for (let s of a) {
+ if (av.has(s)) {
+ av.set(s, av.get(s) + 1);
+ } else {
+ av.set(s, 1);
+ }
+ }
+ let kk = Array.from(av.keys());
+ kk.sort(function(a,b) {
+ return b-a;
+ });
+ let rank = 1;
+ let tab = new Map;
+ for (let k of kk) {
+ const siz = av.get(k);
+ let r = "";
+ if (rank <= 3) {
+ r = ["G", "S", "B"][rank - 1];
+ } else {
+ r = rank.toString();
+ }
+ if (siz > 1) {
+ r += "=";
+ }
+ tab.set(k, r);
+ rank += siz;
+ }
+ return a.map(i => tab.get(i));
+}
+
+
+if (deepEqual(rankscore([1, 2, 4, 3, 5]), ['5', '4', 'S', 'B', 'G'])) {
+ process.stdout.write("Pass");
+} else {
+ process.stdout.write("FAIL");
+}
+process.stdout.write(" ");
+if (deepEqual(rankscore([8, 5, 6, 7, 4]), ['G', '4', 'B', 'S', '5'])) {
+ process.stdout.write("Pass");
+} else {
+ process.stdout.write("FAIL");
+}
+process.stdout.write(" ");
+if (deepEqual(rankscore([3, 5, 4, 2]), ['B', 'G', 'S', '4'])) {
+ process.stdout.write("Pass");
+} else {
+ process.stdout.write("FAIL");
+}
+process.stdout.write(" ");
+if (deepEqual(rankscore([2, 5, 2, 1, 7, 5, 1]), ['4=', 'S=', '4=', '6=', 'G', 'S=', '6='])) {
+ process.stdout.write("Pass");
+} else {
+ process.stdout.write("FAIL");
+}
+process.stdout.write("\n");
diff --git a/challenge-214/roger-bell-west/javascript/ch-2.js b/challenge-214/roger-bell-west/javascript/ch-2.js
new file mode 100755
index 0000000000..aabc5e43dc
--- /dev/null
+++ b/challenge-214/roger-bell-west/javascript/ch-2.js
@@ -0,0 +1,70 @@
+#! /usr/bin/node
+
+"use strict"
+
+function collectpoints(a) {
+ let m = [];
+ let st = 0;
+ while (st < a.length) {
+ const k = a[st];
+ let e = st;
+ while (e < a.length && a[e] == k) {
+ e += 1;
+ }
+ m.push([k, e - st]);
+ st = e;
+ }
+ let rv = 0;
+ let stack = [[m, 0]];
+ while (stack.length > 0) {
+ const s = stack.pop();
+ if (s[0].length == 0) {
+ rv = Math.max(rv, s[1]);
+ } else {
+ for (let i = 0; i < s[0].length; i++) {
+ let ss = JSON.parse(JSON.stringify(s));
+ ss[1] += ss[0][i][1] * ss[0][i][1];
+ ss[0].splice(i, 1);
+ let j = i;
+ while (true) {
+ if (j > 0 &&
+ j < ss[0].length &&
+ ss[0][j][0] == ss[0][j - 1][0]) {
+ ss[0][j][1] += ss[0][j - 1][1];
+ ss[0].splice(j - 1, 1);
+ j -= 1;
+ } else {
+ break;
+ }
+ }
+ stack.push(ss);
+ }
+ }
+ }
+ return rv;
+}
+
+if (collectpoints([2, 4, 3, 3, 3, 4, 5, 4, 2]) == 23) {
+ process.stdout.write("Pass");
+} else {
+ process.stdout.write("FAIL");
+}
+process.stdout.write(" ");
+if (collectpoints([1, 2, 2, 2, 2, 1]) == 20) {
+ process.stdout.write("Pass");
+} else {
+ process.stdout.write("FAIL");
+}
+process.stdout.write(" ");
+if (collectpoints([1]) == 1) {
+ process.stdout.write("Pass");
+} else {
+ process.stdout.write("FAIL");
+}
+process.stdout.write(" ");
+if (collectpoints([2, 2, 2, 1, 1, 2, 2, 2]) == 40) {
+ process.stdout.write("Pass");
+} else {
+ process.stdout.write("FAIL");
+}
+process.stdout.write("\n");
diff --git a/challenge-214/roger-bell-west/kotlin/ch-1.kt b/challenge-214/roger-bell-west/kotlin/ch-1.kt
new file mode 100644
index 0000000000..657c05c684
--- /dev/null
+++ b/challenge-214/roger-bell-west/kotlin/ch-1.kt
@@ -0,0 +1,58 @@
+fun rankscore(a: List<Int>): List<String> {
+ var av = mutableMapOf<Int, Int>()
+ for (s in a) {
+ if (av.contains(s)) {
+ av.put(s, av.get(s)!! + 1)
+ } else {
+ av.put(s, 1)
+ }
+ }
+ var kk = ArrayList(av.keys)
+ kk.sortWith(compareByDescending { it })
+ var rank = 1
+ var tab = mutableMapOf<Int, String>()
+ for (k in kk) {
+ val siz = av.get(k)!!
+ var r: String
+ if (rank <= 3) {
+ r = listOf("G", "S", "B")[rank - 1]
+ } else {
+ r = rank.toString()
+ }
+ if (siz > 1) {
+ r += "="
+ }
+ tab.put(k, r)
+ rank += siz
+ }
+ return a.map {tab.get(it)!!}.toList()
+}
+
+fun main() {
+
+ if (rankscore(listOf(1, 2, 4, 3, 5)) == listOf("5", "4", "S", "B", "G")) {
+ print("Pass")
+ } else {
+ print("Fail")
+ }
+ print(" ")
+ if (rankscore(listOf(8, 5, 6, 7, 4)) == listOf("G", "4", "B", "S", "5")) {
+ print("Pass")
+ } else {
+ print("Fail")
+ }
+ print(" ")
+ if (rankscore(listOf(3, 5, 4, 2)) == listOf("B", "G", "S", "4")) {
+ print("Pass")
+ } else {
+ print("Fail")
+ }
+ print(" ")
+ if (rankscore(listOf(2, 5, 2, 1, 7, 5, 1)) == listOf("4=", "S=", "4=", "6=", "G", "S=", "6=")) {
+ print("Pass")
+ } else {
+ print("Fail")
+ }
+ println("")
+
+}
diff --git a/challenge-214/roger-bell-west/kotlin/ch-2.kt b/challenge-214/roger-bell-west/kotlin/ch-2.kt
new file mode 100644
index 0000000000..b5941135f5
--- /dev/null
+++ b/challenge-214/roger-bell-west/kotlin/ch-2.kt
@@ -0,0 +1,73 @@
+import kotlin.math.max
+
+fun collectpoints(a: List<Int>): Int {
+ var m = ArrayList<Pair<Int, Int>>()
+ var st = 0
+ while (st < a.size) {
+ val k = a[st]
+ var e = st
+ while (e < a.size && a[e] == k) {
+ e += 1
+ }
+ m.add(Pair(k, e - st))
+ st = e
+ }
+ var rv = 0
+ var stack = ArrayList<Pair<ArrayList<Pair<Int, Int>>, Int>>()
+ stack.add(Pair(m, 0))
+ while (stack.size > 0) {
+ val s = stack.removeLast()
+ if (s.first.size == 0) {
+ rv = max(rv, s.second)
+ } else {
+ for (i in 0 .. s.first.size - 1) {
+ var ss = Pair(ArrayList(s.first), s.second)
+ ss = Pair(ss.first, ss.second + ss.first[i].second * ss.first[i].second)
+ ss.first.removeAt(i)
+ var j = i
+ while (true) {
+ if (j >0 &&
+ j < ss.first.size &&
+ ss.first[j].first == ss.first[j - 1].first) {
+ ss.first[j] = Pair(ss.first[j].first, ss.first[j].second + ss.first[j - 1].second)
+ ss.first.removeAt(j - 1)
+ j -= 1
+ } else {
+ break
+ }
+ }
+ stack.add(ss)
+ }
+ }
+ }
+ return rv
+}
+
+fun main() {
+
+ if (collectpoints(listOf(2, 4, 3, 3, 3, 4, 5, 4, 2)) == 23) {
+ print("Pass")
+ } else {
+ print("Fail")
+ }
+ print(" ")
+ if (collectpoints(listOf(1, 2, 2, 2, 2, 1)) == 20) {
+ print("Pass")
+ } else {
+ print("Fail")
+ }
+ print(" ")
+ if (collectpoints(listOf(1)) == 1) {
+ print("Pass")
+ } else {
+ print("Fail")
+ }
+ print(" ")
+ if (collectpoints(listOf(2, 2, 2, 1, 1, 2, 2, 2)) == 40) {
+ print("Pass")
+ } else {
+ print("Fail")
+ }
+ println("")
+
+}
diff --git a/challenge-214/roger-bell-west/lua/ch-1.lua b/challenge-214/roger-bell-west/lua/ch-1.lua
new file mode 100755
index 0000000000..d656246e7d
--- /dev/null
+++ b/challenge-214/roger-bell-west/lua/ch-1.lua
@@ -0,0 +1,102 @@
+#! /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
+
+-- Roger's lualib
+function keys(t)
+ local a = {}
+ for k, v in pairs(t) do
+ table.insert(a, k)
+ end
+ return a
+end
+
+function rankscore(a)
+ local av = {}
+ for i, s in ipairs(a) do
+ if av[s] == nil then
+ av[s] = 1
+ else
+ av[s] = av[s] + 1
+ end
+ end
+ local kk = keys(av)
+ table.sort(kk, function (aa, bb) return bb < aa end)
+ local rank = 1
+ local tab = {}
+ for i, k in ipairs(kk) do
+ local siz = av[k]
+ local r = ""
+ if rank <= 3 then
+ r = string.sub("GSB", rank, rank)
+ else
+ r = tostring(rank)
+ end
+ if siz > 1 then
+ r = r .. "="
+ end
+ tab[k] = r
+ rank = rank + siz
+ end
+ local out = {}
+ for i, s in ipairs(a) do
+ table.insert(out, tab[s])
+ end
+ return out
+end
+
+if recursive_compare(rankscore({1, 2, 4, 3, 5}), {"5", "4", "S", "B", "G"}) then
+ io.write("Pass")
+else
+ io.write("FAIL")
+end
+io.write(" ")
+
+if recursive_compare(rankscore({8, 5, 6, 7, 4}), {"G", "4", "B", "S", "5"}) then
+ io.write("Pass")
+else
+ io.write("FAIL")
+end
+io.write(" ")
+
+if recursive_compare(rankscore({3, 5, 4, 2}), {"B", "G", "S", "4"}) then
+ io.write("Pass")
+else
+ io.write("FAIL")
+end
+io.write(" ")
+
+if recursive_compare(rankscore({2, 5, 2, 1, 7, 5, 1}), {"4=", "S=", "4=", "6=", "G", "S=", "6="}) then
+ io.write("Pass")
+else
+ io.write("FAIL")
+end
+print("")
+
diff --git a/challenge-214/roger-bell-west/lua/ch-2.lua b/challenge-214/roger-bell-west/lua/ch-2.lua
new file mode 100755
index 0000000000..04a9cf7f6f
--- /dev/null
+++ b/challenge-214/roger-bell-west/lua/ch-2.lua
@@ -0,0 +1,86 @@
+#! /usr/bin/lua
+
+-- from Roger's lualib
+function deepcopy(src)
+ local dst = {}
+ for k, v in pairs(src) do
+ if type(v) == "table" then
+ v = deepcopy(v)
+ end
+ dst[k] = v
+ end
+ return dst
+end
+
+function collectpoints(a)
+ local m = {}
+ local s = 1
+ while s <= #a do
+ local k = a[s]
+ local e = s
+ while e <= #a and a[e] == k do
+ e = e + 1
+ end
+ table.insert(m, {k, e - s})
+ s = e
+ end
+ local rv = 0
+ local stack = { { m, 0 } }
+ while #stack > 0 do
+ local s = table.remove(stack)
+ if #(s[1]) == 0 then
+ if rv < s[2] then
+ rv = s[2]
+ end
+ else
+ for i = 1, #(s[1]) do
+ local ss = deepcopy(s)
+ ss[2] = ss[2] + ss[1][i][2] * ss[1][i][2]
+ table.remove(ss[1], i)
+ j = i
+ while true do
+ if j > 1 and
+ j <= #(ss[1]) and
+ ss[1][j][1] == ss[1][j - 1][1] then
+ ss[1][j][2] = ss[1][j][2] + ss[1][j - 1][2]
+ table.remove(ss[1], j - 1)
+ j = j - 1
+ else
+ break
+ end
+ end
+ table.insert(stack, ss)
+ end
+ end
+ end
+ return rv
+end
+
+if collectpoints({2, 4, 3, 3, 3, 4, 5, 4, 2}) == 23 then
+ io.write("Pass")
+else
+ io.write("FAIL")
+end
+io.write(" ")
+
+if collectpoints({1, 2, 2, 2, 2, 1}) == 20 then
+ io.write("Pass")
+else
+ io.write("FAIL")
+end
+io.write(" ")
+
+if collectpoints({1}) == 1 then
+ io.write("Pass")
+else
+ io.write("FAIL")
+end
+io.write(" ")
+
+if collectpoints({2, 2, 2, 1, 1, 2, 2, 2}) == 40 then
+ io.write("Pass")
+else
+ io.write("FAIL")
+end
+print("")
+
diff --git a/challenge-214/roger-bell-west/perl/ch-1.pl b/challenge-214/roger-bell-west/perl/ch-1.pl
new file mode 100755
index 0000000000..1c27c6a80b
--- /dev/null
+++ b/challenge-214/roger-bell-west/perl/ch-1.pl
@@ -0,0 +1,36 @@
+#! /usr/bin/perl
+
+use strict;
+use warnings;
+use experimental 'signatures';
+
+use Test::More tests => 4;
+
+is_deeply(rankscore([1, 2, 4, 3, 5]), ['5', '4', 'S', 'B', 'G'], 'example 1');
+is_deeply(rankscore([8, 5, 6, 7, 4]), ['G', '4', 'B', 'S', '5'], 'example 2');
+is_deeply(rankscore([3, 5, 4, 2]), ['B', 'G', 'S', '4'], 'example 3');
+is_deeply(rankscore([2, 5, 2, 1, 7, 5, 1]), ['4=', 'S=', '4=', '6=', 'G', 'S=', '6='], 'example 4');
+
+sub rankscore($a) {
+ my %av;
+ foreach my $s (@{$a}) {
+ $av{$s}++;
+ }
+ my $rank = 1;
+ my %tab;
+ foreach my $k (sort {$::b <=> $::a} keys %av) {
+ my $siz = $av{$k};
+ my $r;
+ if ($rank <= 3) {
+ $r = [qw(G S B)]->[$rank - 1];
+ } else {
+ $r = $rank;
+ }
+ if ($siz > 1) {
+ $r .= "=";
+ }
+ $tab{$k} = $r;
+ $rank += $siz;
+ }
+ return [map {$tab{$_}} @{$a}];
+}
diff --git a/challenge-214/roger-bell-west/perl/ch-2.pl b/challenge-214/roger-bell-west/perl/ch-2.pl
new file mode 100755
index 0000000000..741c69ff65
--- /dev/null
+++ b/challenge-214/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 => 4;
+
+is(collectpoints([2, 4, 3, 3, 3, 4, 5, 4, 2]), 23, 'example 1');
+is(collectpoints([1, 2, 2, 2, 2, 1]), 20, 'example 2');
+is(collectpoints([1]), 1, 'example 3');
+is(collectpoints([2, 2, 2, 1, 1, 2, 2, 2]), 40, 'example 4');
+
+use Storable qw(dclone);
+use List::Util qw(max);
+
+sub collectpoints($a) {
+ my @m;
+ my $s = 0;
+ while ($s <= $#{$a}) {
+ my $k = $a->[$s];
+ my $e = $s;
+ while ($e <= $#{$a} && $a->[$e] == $k) {
+ $e++;
+ }
+ push @m,[$k, $e - $s];
+ $s = $e;
+ }
+ my $rv = 0;
+ my @stack = ([\@m, 0]);
+ while (scalar @stack > 0) {
+ my $s = pop @stack;
+ if (scalar @{$s->[0]} == 0) {
+ $rv = max($rv, $s->[1]);
+ } else {
+ foreach my $i (0..$#{$s->[0]}) {
+ my $ss = dclone($s);
+ $ss->[1] += $ss->[0][$i][1] * $ss->[0][$i][1];
+ splice @{$ss->[0]}, $i, 1;
+ my $j = $i;
+ while (1) {
+ if ($j > 0 &&
+ $j < scalar @{$ss->[0]} &&
+ $ss->[0][$j][0] == $ss->[0][$j-1][0]) {
+ $ss->[0][$j][1] += $ss->[0][$j-1][1];
+ splice @{$ss->[0]}, $j - 1, 1;
+ $j--;
+ } else {
+ last;
+ }
+ }
+ push @stack, $ss;
+ }
+ }
+ }
+ return $rv;
+}
diff --git a/challenge-214/roger-bell-west/postscript/ch-1.ps b/challenge-214/roger-bell-west/postscript/ch-1.ps
new file mode 100644
index 0000000000..3e2caf889f
--- /dev/null
+++ b/challenge-214/roger-bell-west/postscript/ch-1.ps
@@ -0,0 +1,256 @@
+%!PS
+
+% begin included library code
+% see https://codeberg.org/Firedrake/postscript-libraries/
+/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
+
+/quicksort.main { % lo hi -> (null)
+ 3 dict begin
+ /hi exch def
+ /lo exch def
+ /xit false def
+ lo 0 lt {
+ /xit true def
+ } if
+ hi 0 lt {
+ /xit true def
+ } if
+ lo hi ge {
+ /xit true def
+ } if
+ xit not {
+ /p quicksort.partition def
+ lo p quicksort.main
+ p 1 add hi quicksort.main
+ } if
+ end
+} bind def
+
+/quicksort.partition {
+ 3 dict begin
+ /pivot arr hi lo add 2 idiv get def
+ /i lo 1 sub def
+ /j hi 1 add def
+ {
+ {
+ /i i 1 add def
+ arr i get pivot ge {
+ exit
+ } if
+ } loop
+ {
+ /j j 1 sub def
+ arr j get pivot le {
+ exit
+ } if
+ } loop
+ i j ge {
+ j
+ exit
+ } if
+ i j quicksort.swap
+ } loop
+ end
+} bind def
+
+/quicksort { % [ a c b ] -> [ a b c ]
+ 1 dict begin
+ /arr exch def
+ arr length 0 gt {
+ 0 arr length 1 sub quicksort.main
+ } if
+ arr
+ end
+} bind def
+
+/reverse {
+ 1 dict begin
+ dup length /l exch def
+ [ exch
+ aload pop
+ 2 1 l {
+ -1 roll
+ } for
+ ]
+ end
+} bind def
+
+/quicksort.swap {
+ 2 dict begin
+ /bi exch def
+ /ai exch def
+ arr ai get
+ arr bi get
+ arr exch ai exch put
+ arr exch bi exch put
+ end
+} 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
+
+/safestring {
+ dup length string cvs
+} 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
+
+/keys { % dict -> array of dict keys
+ [ exch
+ {
+ pop
+ } forall
+ ]
+} bind def
+
+/test.start {
+ print (:) print
+ /test.pass 0 def
+ /test.count 0 def
+} bind def
+
+/alloccvs {
+ 2 dict begin
+ /n exch def
+ /a 1 def
+ n
+ dup 0 lt {
+ /a a 1 add def
+ neg
+ } if
+ {
+ dup 10 lt {
+ exit
+ } if
+ /a a 1 add def
+ 10 idiv
+ } loop
+ pop
+ n a string cvs
+ end
+} bind def
+
+
+% end included library code
+
+/rankscore {
+ 8 dict begin
+ /a exch def
+ /av 0 dict def
+ a {
+ /s exch def
+ av s known {
+ av s av s get 1 add put
+ } {
+ av s 1 put
+ } ifelse
+ } forall
+ /rank 1 def
+ /tab 0 dict def
+ av keys quicksort reverse {
+ /k exch def
+ /siz av k get def
+ rank 3 le {
+ /r [ (G) (S) (B) ] rank 1 sub get def
+ } {
+ /r rank alloccvs def
+ } ifelse
+ siz 1 gt {
+ /s r length 1 add string def
+ r s copy
+ s r length (=) putinterval
+ /r s def
+ } if
+ tab k r safestring put
+ /rank rank siz add def
+ } forall
+ [
+ a {
+ tab exch get
+ } forall
+ ]
+ end
+} bind def
+
+(rankscore) test.start
+[1 2 4 3 5] rankscore [(5) (4) (S) (B) (G)] deepeq test
+[8 5 6 7 4] rankscore [(G) (4) (B) (S) (5)] deepeq test
+[3 5 4 2] rankscore [(B) (G) (S) (4)] deepeq test
+[2 5 2 1 7 5 1] rankscore [(4=) (S=) (4=) (6=) (G) (S=) (6=)] deepeq test
+test.end
diff --git a/challenge-214/roger-bell-west/postscript/ch-2.ps b/challenge-214/roger-bell-west/postscript/ch-2.ps
new file mode 100644
index 0000000000..8cafbdd0e3
--- /dev/null
+++ b/challenge-214/roger-bell-west/postscript/ch-2.ps
@@ -0,0 +1,178 @@
+%!PS
+
+% begin included library code
+% see https://codeberg.org/Firedrake/postscript-libraries/
+/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
+
+/deepcopy {
+ 2 dict begin
+ /a exch def
+ a type /dicttype eq {
+ <<
+ a keys {
+ /k exch get
+ k
+ a k get deepcopy
+ } forall
+ >>
+ } {
+ a type /arraytype eq {
+ [
+ a {
+ deepcopy
+ } forall
+ ]
+ } {
+ a type /stringtype eq {
+ a dup length string cvs
+ } {
+ a
+ } ifelse
+ } ifelse
+ } ifelse
+ end
+} bind def
+
+/apush.right { % [a b] c -> [a b c]
+ exch
+ [ exch aload length 2 add -1 roll ]
+} bind def
+
+/apop.right { % [a b c] -> [a b] c
+ [ exch aload length 1 add 1 roll ] exch
+} bind def
+
+/keys { % dict -> array of dict keys
+ [ exch
+ {
+ pop
+ } forall
+ ]
+} bind def
+
+/remove {
+ 2 dict begin
+ /i exch def
+ aload length /l exch def
+ l i sub -1 roll pop
+ l 1 sub array astore
+ end
+} bind def
+
+/test.start {
+ print (:) print
+ /test.pass 0 def
+ /test.count 0 def
+} 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
+
+
+% end included library code
+
+/collectpoints {
+ 0 dict begin
+ /a exch def
+ /s 0 def
+ /m [
+ {
+ s a length ge {
+ exit
+ } if
+ /k a s get def
+ /e s def
+ {
+ e a length ge {
+ exit
+ } if
+ a e get k ne {
+ exit
+ } if
+ /e e 1 add def
+ } loop
+ [ k e s sub ]
+ /s e def
+ } loop
+ ] def
+ /rv 0 def
+ /stack [ [ m 0 ] ] def
+ {
+ stack length 0 eq {
+ exit
+ } if
+ stack apop.right /s exch def /stack exch def
+ s 0 get length 0 eq {
+ /rv rv s 1 get max def
+ } {
+ 0 1 s 0 get length 1 sub {
+ /i exch def
+ /ss s deepcopy def
+ ss 1 ss 1 get ss 0 get i get 1 get dup mul add put
+ ss 0 ss 0 get i remove put
+ {
+ /ex true def
+ i 1 add ss 0 get length lt {
+ ss 0 get i get 0 get ss 0 get i 1 add get 0 get eq {
+ ss 0 get i get 1
+ ss 0 get i get 1 get
+ ss 0 get i 1 add get 1 get
+ add
+ put
+ ss 0
+ ss 0 get i 1 add remove
+ put
+ /ex false def
+ } if
+ } if
+ ex {
+ i 0 gt i ss 0 get length lt and {
+ ss 0 get i get 0 get ss 0 get i 1 sub get 0 get eq {
+ ss 0 get i get 1
+ ss 0 get i get 1 get ss 0 get i 1 sub get 1 get add
+ put
+ ss 0
+ ss 0 get i 1 sub remove
+ put
+ /ex false def
+ } if
+ } if
+ } if