aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoger Bell_West <roger@firedrake.org>2024-09-24 09:04:03 +0100
committerRoger Bell_West <roger@firedrake.org>2024-09-24 09:04:03 +0100
commitaac78df4327f42e2daad8ba16818fa3ee81e680e (patch)
treea0d07b38d0c67061473cc5c8b8588547e72b68e0
parent9ced81d32e594001ffe943db9363bb48a4583d67 (diff)
downloadperlweeklychallenge-club-aac78df4327f42e2daad8ba16818fa3ee81e680e.tar.gz
perlweeklychallenge-club-aac78df4327f42e2daad8ba16818fa3ee81e680e.tar.bz2
perlweeklychallenge-club-aac78df4327f42e2daad8ba16818fa3ee81e680e.zip
RogerBW solutions for challenge no. 288
-rwxr-xr-xchallenge-288/roger-bell-west/crystal/ch-1.cr32
-rwxr-xr-xchallenge-288/roger-bell-west/crystal/ch-2.cr55
-rwxr-xr-xchallenge-288/roger-bell-west/javascript/ch-1.js43
-rwxr-xr-xchallenge-288/roger-bell-west/javascript/ch-2.js75
-rw-r--r--challenge-288/roger-bell-west/kotlin/ch-1.kt43
-rw-r--r--challenge-288/roger-bell-west/kotlin/ch-2.kt64
-rwxr-xr-xchallenge-288/roger-bell-west/lua/ch-1.lua44
-rwxr-xr-xchallenge-288/roger-bell-west/lua/ch-2.lua94
-rwxr-xr-xchallenge-288/roger-bell-west/perl/ch-1.pl26
-rwxr-xr-xchallenge-288/roger-bell-west/perl/ch-2.pl66
-rw-r--r--challenge-288/roger-bell-west/postscript/ch-1.ps168
-rw-r--r--challenge-288/roger-bell-west/postscript/ch-2.ps212
-rwxr-xr-xchallenge-288/roger-bell-west/python/ch-1.py30
-rwxr-xr-xchallenge-288/roger-bell-west/python/ch-2.py47
-rwxr-xr-xchallenge-288/roger-bell-west/raku/ch-1.p624
-rwxr-xr-xchallenge-288/roger-bell-west/raku/ch-2.p662
-rwxr-xr-xchallenge-288/roger-bell-west/ruby/ch-1.rb38
-rwxr-xr-xchallenge-288/roger-bell-west/ruby/ch-2.rb73
-rwxr-xr-xchallenge-288/roger-bell-west/rust/ch-1.rs37
-rwxr-xr-xchallenge-288/roger-bell-west/rust/ch-2.rs86
-rw-r--r--challenge-288/roger-bell-west/scala/ch-1.scala45
-rw-r--r--challenge-288/roger-bell-west/scala/ch-2.scala66
-rw-r--r--challenge-288/roger-bell-west/tests.json51
23 files changed, 1481 insertions, 0 deletions
diff --git a/challenge-288/roger-bell-west/crystal/ch-1.cr b/challenge-288/roger-bell-west/crystal/ch-1.cr
new file mode 100755
index 0000000000..425eedbb56
--- /dev/null
+++ b/challenge-288/roger-bell-west/crystal/ch-1.cr
@@ -0,0 +1,32 @@
+#! /usr/bin/crystal
+
+def closestpalindrome(a)
+ n = a.to_i
+ delta = -1
+ while true
+ q = (n + delta).to_s
+ if q == q.reverse
+ return q
+ end
+ delta = -delta
+ if delta < 0
+ delta -= 1
+ end
+ end
+end
+
+require "spec"
+describe "closestpalindrome" do
+ it "test_ex1" do
+ closestpalindrome("123").should eq "121"
+ end
+ it "test_ex2" do
+ closestpalindrome("2").should eq "1"
+ end
+ it "test_ex3" do
+ closestpalindrome("1400").should eq "1441"
+ end
+ it "test_ex4" do
+ closestpalindrome("1000").should eq "999"
+ end
+end
diff --git a/challenge-288/roger-bell-west/crystal/ch-2.cr b/challenge-288/roger-bell-west/crystal/ch-2.cr
new file mode 100755
index 0000000000..f0a72033ce
--- /dev/null
+++ b/challenge-288/roger-bell-west/crystal/ch-2.cr
@@ -0,0 +1,55 @@
+#! /usr/bin/crystal
+
+def contiguousblock(a)
+ y = a.size
+ x = a[0].size
+ starts = Set(Array(Int32)).new
+ 0.upto(x - 1) do |cx|
+ 0.upto(y - 1) do |cy|
+ starts.add([cx, cy])
+ end
+ end
+ maxblock = 0
+ while starts.size > 0
+ start = starts.to_a[0]
+ queue = Array(Array(Int32)).new
+ visited = Set(Array(Int32)).new
+ visited.add(start)
+ queue.push(start)
+ while queue.size > 0
+ here = queue.shift
+ [[-1, 0], [1, 0], [0, -1], [0, 1]].each do |delta|
+ if (delta[0] >= 0 || here[0] > 0) &&
+ (delta[0] <= 0 || here[0] < x - 1) &&
+ (delta[1] >= 0 || here[1] > 0) &&
+ (delta[1] <= 0 || here[1] < y - 1)
+ there = [here[0] + delta[0], here[1] + delta[1]]
+ if (!visited.includes?(there) &&
+ a[there[1]][there[0]] == a[start[1]][start[0]])
+ visited.add(there)
+ queue.push(there)
+ end
+ end
+ end
+ end
+ sz = visited.size
+ if (sz > maxblock)
+ maxblock = sz
+ end
+ starts -= visited
+ end
+ return maxblock
+end
+
+require "spec"
+describe "contiguousblock" do
+ it "test_ex1" do
+ contiguousblock([["x", "x", "x", "x", "o"], ["x", "o", "o", "o", "o"], ["x", "o", "o", "o", "o"], ["x", "x", "x", "o", "o"]]).should eq 11
+ end
+ it "test_ex2" do
+ contiguousblock([["x", "x", "x", "x", "x"], ["x", "o", "o", "o", "o"], ["x", "x", "x", "x", "o"], ["x", "o", "o", "o", "o"]]).should eq 11
+ end
+ it "test_ex3" do
+ contiguousblock([["x", "x", "x", "o", "o"], ["o", "o", "o", "x", "x"], ["o", "x", "x", "o", "o"], ["o", "o", "o", "x", "x"]]).should eq 7
+ end
+end
diff --git a/challenge-288/roger-bell-west/javascript/ch-1.js b/challenge-288/roger-bell-west/javascript/ch-1.js
new file mode 100755
index 0000000000..0500b1bf34
--- /dev/null
+++ b/challenge-288/roger-bell-west/javascript/ch-1.js
@@ -0,0 +1,43 @@
+#! /usr/bin/node
+
+"use strict"
+
+function closestpalindrome(a) {
+ const n = parseInt(a);
+ let delta = -1;
+ while (true) {
+ const q = (n + delta).toString();
+ if (q == q.split("").reverse().join("")) {
+ return q;
+ }
+ delta = -delta;
+ if (delta < 0) {
+ delta -= 1;
+ }
+ }
+}
+
+if (closestpalindrome('123') == '121') {
+ process.stdout.write("Pass");
+} else {
+ process.stdout.write("FAIL");
+}
+process.stdout.write(" ");
+if (closestpalindrome('2') == '1') {
+ process.stdout.write("Pass");
+} else {
+ process.stdout.write("FAIL");
+}
+process.stdout.write(" ");
+if (closestpalindrome('1400') == '1441') {
+ process.stdout.write("Pass");
+} else {
+ process.stdout.write("FAIL");
+}
+process.stdout.write(" ");
+if (closestpalindrome('1000') == '999') {
+ process.stdout.write("Pass");
+} else {
+ process.stdout.write("FAIL");
+}
+process.stdout.write("\n");
diff --git a/challenge-288/roger-bell-west/javascript/ch-2.js b/challenge-288/roger-bell-west/javascript/ch-2.js
new file mode 100755
index 0000000000..935c3505b6
--- /dev/null
+++ b/challenge-288/roger-bell-west/javascript/ch-2.js
@@ -0,0 +1,75 @@
+#! /usr/bin/node
+
+"use strict"
+
+function encode(x, y) {
+ return x * 1e6 + y;
+}
+
+function decode(c) {
+ return [Math.floor(c / 1e6), c % 1e6];
+}
+
+function contiguousblock(a) {
+ const y = a.length;
+ const x = a[0].length;
+ let starts = new Set;
+ for (let cx = 0; cx < x; cx++) {
+ for (let cy = 0; cy < y; cy++) {
+ starts.add(encode(cx, cy));
+ }
+ }
+ let maxblock = 0;
+ while (starts.size > 0) {
+ const start = [...starts.keys()][0];
+ const cstart = decode(start);
+ let queue = [];
+ let visited = new Set;
+ visited.add(start);
+ queue.push(start);
+ while (queue.length > 0) {
+ const here = queue.shift();
+ const chere = decode(here);
+ for (let delta of [[-1, 0], [1, 0], [0, -1], [0, 1]]) {
+ if ((delta[0] >= 0 || chere[0] > 0)
+ && (delta[0] <= 0 || chere[0] < x - 1)
+ && (delta[1] >= 0 || chere[1] > 0)
+ && (delta[1] <= 0 || chere[1] < y - 1)) {
+ const cthere = [chere[0] + delta[0], chere[1] + delta[1]];
+ const there = encode(...cthere);
+ if (!visited.has(there) &&
+ a[cthere[1]][cthere[0]] ==
+ a[cstart[1]][cstart[0]]) {
+ visited.add(there);
+ queue.push(there);
+ }
+ }
+ }
+ }
+ const sz = visited.size;
+ if (sz > maxblock) {
+ maxblock = sz;
+ }
+ starts = new Set([...starts].filter(i => !visited.has(i)));
+ }
+ return maxblock;
+}
+
+if (contiguousblock([['x', 'x', 'x', 'x', 'o'], ['x', 'o', 'o', 'o', 'o'], ['x', 'o', 'o', 'o', 'o'], ['x', 'x', 'x', 'o', 'o']]) == 11) {
+ process.stdout.write("Pass");
+} else {
+ process.stdout.write("FAIL");
+}
+process.stdout.write(" ");
+if (contiguousblock([['x', 'x', 'x', 'x', 'x'], ['x', 'o', 'o', 'o', 'o'], ['x', 'x', 'x', 'x', 'o'], ['x', 'o', 'o', 'o', 'o']]) == 11) {
+ process.stdout.write("Pass");
+} else {
+ process.stdout.write("FAIL");
+}
+process.stdout.write(" ");
+if (contiguousblock([['x', 'x', 'x', 'o', 'o'], ['o', 'o', 'o', 'x', 'x'], ['o', 'x', 'x', 'o', 'o'], ['o', 'o', 'o', 'x', 'x']]) == 7) {
+ process.stdout.write("Pass");
+} else {
+ process.stdout.write("FAIL");
+}
+process.stdout.write("\n");
diff --git a/challenge-288/roger-bell-west/kotlin/ch-1.kt b/challenge-288/roger-bell-west/kotlin/ch-1.kt
new file mode 100644
index 0000000000..de766baabe
--- /dev/null
+++ b/challenge-288/roger-bell-west/kotlin/ch-1.kt
@@ -0,0 +1,43 @@
+fun closestpalindrome(a: String): String {
+ val n = a.toInt()
+ var delta = -1
+ while (true) {
+ val q = (n + delta).toString()
+ if (q == q.reversed()) {
+ return q
+ }
+ delta = -delta;
+ if (delta < 0) {
+ delta -= 1
+ }
+ }
+}
+
+fun main() {
+
+ if (closestpalindrome("123") == "121") {
+ print("Pass")
+ } else {
+ print("Fail")
+ }
+ print(" ")
+ if (closestpalindrome("2") == "1") {
+ print("Pass")
+ } else {
+ print("Fail")
+ }
+ print(" ")
+ if (closestpalindrome("1400") == "1441") {
+ print("Pass")
+ } else {
+ print("Fail")
+ }
+ print(" ")
+ if (closestpalindrome("1000") == "999") {
+ print("Pass")
+ } else {
+ print("Fail")
+ }
+ println("")
+
+}
diff --git a/challenge-288/roger-bell-west/kotlin/ch-2.kt b/challenge-288/roger-bell-west/kotlin/ch-2.kt
new file mode 100644
index 0000000000..0764251bef
--- /dev/null
+++ b/challenge-288/roger-bell-west/kotlin/ch-2.kt
@@ -0,0 +1,64 @@
+fun contiguousblock(a: List<List<Char>>): Int {
+ val y = a.size
+ val x = a[0].size
+ var starts = mutableSetOf<Pair<Int, Int>>()
+ for (cx in 0..x - 1) {
+ for (cy in 0..y - 1) {
+ starts.add(Pair(cx, cy))
+ }
+ }
+ var maxblock = 0
+ while (starts.size > 0) {
+ val start = starts.toList()[0]
+ var queue = ArrayDeque<Pair<Int, Int>>()
+ var visited = mutableSetOf<Pair<Int, Int>>()
+ visited.add(start)
+ queue.add(start)
+ while (queue.size > 0) {
+ val here = queue.removeFirst()
+ for (delta in listOf(Pair(-1, 0), Pair(1, 0), Pair(0, -1), Pair(0, 1))) {
+ if ((delta.first >= 0 || here.first > 0) &&
+ (delta.first <= 0 || here.first < x - 1) &&
+ (delta.second >= 0 || here.second > 0) &&
+ (delta.second <= 0 || here.second < y - 1)) {
+ val there = Pair(here.first + delta.first, here.second + delta.second)
+ if (!visited.contains(there)
+ && a[there.second ][there.first]
+ == a[start.second][start.first]) {
+ visited.add(there)
+ queue.add(there)
+ }
+ }
+ }
+ }
+ val sz = visited.size
+ if (sz > maxblock) {
+ maxblock = sz
+ }
+ starts -= visited
+ }
+ return maxblock
+}
+
+fun main() {
+
+ if (contiguousblock(listOf(listOf('x', 'x', 'x', 'x', 'o'), listOf('x', 'o', 'o', 'o', 'o'), listOf('x', 'o', 'o', 'o', 'o'), listOf('x', 'x', 'x', 'o', 'o'))) == 11) {
+ print("Pass")
+ } else {
+ print("Fail")
+ }
+ print(' ')
+ if (contiguousblock(listOf(listOf('x', 'x', 'x', 'x', 'x'), listOf('x', 'o', 'o', 'o', 'o'), listOf('x', 'x', 'x', 'x', 'o'), listOf('x', 'o', 'o', 'o', 'o'))) == 11) {
+ print("Pass")
+ } else {
+ print("Fail")
+ }
+ print(' ')
+ if (contiguousblock(listOf(listOf('x', 'x', 'x', 'o', 'o'), listOf('o', 'o', 'o', 'x', 'x'), listOf('o', 'x', 'x', 'o', 'o'), listOf('o', 'o', 'o', 'x', 'x'))) == 7) {
+ print("Pass")
+ } else {
+ print("Fail")
+ }
+ println("")
+
+}
diff --git a/challenge-288/roger-bell-west/lua/ch-1.lua b/challenge-288/roger-bell-west/lua/ch-1.lua
new file mode 100755
index 0000000000..422de668ff
--- /dev/null
+++ b/challenge-288/roger-bell-west/lua/ch-1.lua
@@ -0,0 +1,44 @@
+#! /usr/bin/lua
+
+function closestpalindrome(a)
+ local delta = -1
+ while true do
+ q = string.format("%d", a + delta)
+ if q == string.reverse(q) then
+ return q
+ end
+ delta = -delta
+ if delta < 0 then
+ delta = delta - 1
+ end
+ end
+end
+
+if closestpalindrome("123") == "121" then
+ io.write("Pass")
+else
+ io.write("FAIL")
+end
+io.write(" ")
+
+if closestpalindrome("2") == "1" then
+ io.write("Pass")
+else
+ io.write("FAIL")
+end
+io.write(" ")
+
+if closestpalindrome("1400") == "1441" then
+ io.write("Pass")
+else
+ io.write("FAIL")
+end
+io.write(" ")
+
+if closestpalindrome("1000") == "999" then
+ io.write("Pass")
+else
+ io.write("FAIL")
+end
+print("")
+
diff --git a/challenge-288/roger-bell-west/lua/ch-2.lua b/challenge-288/roger-bell-west/lua/ch-2.lua
new file mode 100755
index 0000000000..8ee81de6ec
--- /dev/null
+++ b/challenge-288/roger-bell-west/lua/ch-2.lua
@@ -0,0 +1,94 @@
+#! /usr/bin/lua
+
+function propersize(t)
+ local l=0
+ for k,v in pairs(t) do
+ l = l + 1
+ end
+ return l
+end
+
+function encode(x, y)
+ return x * 1e6 + y
+end
+
+function decode(c)
+ return {c // 1e6, c % 1e6}
+end
+
+function contiguousblock(a)
+ local y = #a
+ local x = #(a[1])
+ local starts = {}
+ for cx = 1, x do
+ for cy = 1, y do
+ starts[encode(cx, cy)] = true
+ end
+ end
+ local maxblock = 0
+ while propersize(starts) > 0 do
+ local start
+ for k, v in pairs(starts) do
+ start = k
+ break
+ end
+ local cstart = decode(start)
+ local queue = {}
+ local visited = {}
+ table.insert(queue, start)
+ visited[start] = true
+ while #queue > 0 do
+ local here = table.remove(queue, 1)
+ local chere = decode(here)
+ for i, delta in ipairs({
+ {-1, 0},
+ {1, 0},
+ {0, -1},
+ {0, 1}
+ }) do
+ if (delta[1] >= 0 or chere[1] > 1) and
+ (delta[1] <= 0 or chere[1] < x) and
+ (delta[2] >= 0 or chere[2] > 1) and
+ (delta[2] <= 0 or chere[2] < y) then
+ local cthere = {chere[1] + delta[1], chere[2] + delta[2]}
+ local there = encode(cthere[1], cthere[2])
+ if visited[there] == nil and
+ a[cthere[2]][cthere[1]] == a[cstart[2]][cstart[1]] then
+ visited[there] = true
+ table.insert(queue, there)
+ end
+ end
+ end
+ end
+ local sz = propersize(visited)
+ if sz > maxblock then
+ maxblock = sz
+ end
+ for k, v in pairs(visited) do
+ starts[k] = nil
+ end
+ end
+ return maxblock
+end
+
+if contiguousblock({{"x", "x", "x", "x", "o"}, {"x", "o", "o", "o", "o"}, {"x", "o", "o", "o", "o"}, {"x", "x", "x", "o", "o"}}) == 11 then
+ io.write("Pass")
+else
+ io.write("FAIL")
+end
+io.write(" ")
+
+if contiguousblock({{"x", "x", "x", "x", "x"}, {"x", "o", "o", "o", "o"}, {"x", "x", "x", "x", "o"}, {"x", "o", "o", "o", "o"}}) == 11 then
+ io.write("Pass")
+else
+ io.write("FAIL")
+end
+io.write(" ")
+
+if contiguousblock({{"x", "x", "x", "o", "o"}, {"o", "o", "o", "x", "x"}, {"o", "x", "x", "o", "o"}, {"o", "o", "o", "x", "x"}}) == 7 then
+ io.write("Pass")
+else
+ io.write("FAIL")
+end
+print("")
+
diff --git a/challenge-288/roger-bell-west/perl/ch-1.pl b/challenge-288/roger-bell-west/perl/ch-1.pl
new file mode 100755
index 0000000000..4a0f22be83
--- /dev/null
+++ b/challenge-288/roger-bell-west/perl/ch-1.pl
@@ -0,0 +1,26 @@
+#! /usr/bin/perl
+
+use strict;
+use warnings;
+use experimental 'signatures';
+
+use Test::More tests => 4;
+
+is(closestpalindrome('123'), '121', 'example 1');
+is(closestpalindrome('2'), '1', 'example 2');
+is(closestpalindrome('1400'), '1441', 'example 3');
+is(closestpalindrome('1000'), '999', 'example 4');
+
+sub closestpalindrome($a) {
+ my $delta = -1;
+ while (1) {
+ my $q = ($a + $delta);
+ if ($q eq reverse($q)) {
+ return $q;
+ }
+ $delta = -$delta;
+ if ($delta < 0) {
+ $delta -= 1;
+ }
+ }
+}
diff --git a/challenge-288/roger-bell-west/perl/ch-2.pl b/challenge-288/roger-bell-west/perl/ch-2.pl
new file mode 100755
index 0000000000..e3a878d09a
--- /dev/null
+++ b/challenge-288/roger-bell-west/perl/ch-2.pl
@@ -0,0 +1,66 @@
+#! /usr/bin/perl
+
+use strict;
+use warnings;
+use experimental 'signatures';
+
+use Test::More tests => 3;
+
+is(contiguousblock([['x', 'x', 'x', 'x', 'o'], ['x', 'o', 'o', 'o', 'o'], ['x', 'o', 'o', 'o', 'o'], ['x', 'x', 'x', 'o', 'o']]), 11, 'example 1');
+is(contiguousblock([['x', 'x', 'x', 'x', 'x'], ['x', 'o', 'o', 'o', 'o'], ['x', 'x', 'x', 'x', 'o'], ['x', 'o', 'o', 'o', 'o']]), 11, 'example 2');
+is(contiguousblock([['x', 'x', 'x', 'o', 'o'], ['o', 'o', 'o', 'x', 'x'], ['o', 'x', 'x', 'o', 'o'], ['o', 'o', 'o', 'x', 'x']]), 7, 'example 3');
+
+sub encode($x, $y) {
+ return $x * 1e6 + $y;
+}
+
+sub decode($c) {
+ return [int($c / 1e6), $c % 1e6];
+}
+
+sub contiguousblock($a) {
+ my $y = scalar @{$a};
+ my $x = scalar @{$a->[0]};
+ my %starts;
+ foreach my $cx (0 .. $x - 1) {
+ foreach my $cy (0 .. $y - 1) {
+ $starts{encode($cx, $cy)} = 1;
+ }
+ }
+ my $maxblock = 0;
+ while (scalar keys %starts > 0) {
+ my $start = (keys %starts)[0];
+ my $cstart = decode($start);
+ my @queue;
+ my %visited;
+ $visited{$start} = 1;
+ push @queue, $start;
+ while (scalar @queue > 0) {
+ my $here = shift @queue;
+ my $chere = decode($here);
+ foreach my $delta ([-1, 0], [1, 0], [0, -1], [0, 1]) {
+ if (($delta->[0] >= 0 || $chere->[0] > 0)
+ && ($delta->[0] <= 0 || $chere->[0] < $x - 1)
+ && ($delta->[1] >= 0 || $chere->[1] > 0)
+ && ($delta->[1] <= 0 || $chere->[1] < $y - 1)) {
+ my $cthere = [$chere->[0] + $delta->[0], $chere->[1] + $delta->[1]];
+ my $there = encode(@{$cthere});
+ if (!exists $visited{$there} &&
+ $a->[$cthere->[1]][$cthere->[0]]
+ eq $a->[$cstart->[1]][$cstart->[0]]) {
+ $visited{$there} = 1;
+ push @queue, $there;
+ }
+ }
+ }
+ }
+ my $size = scalar keys %visited;
+ if ($size > $maxblock) {
+ $maxblock = $size;
+ }
+ foreach my $k (keys %visited) {
+ delete $starts{$k};
+ }
+ }
+ return $maxblock;
+}
diff --git a/challenge-288/roger-bell-west/postscript/ch-1.ps b/challenge-288/roger-bell-west/postscript/ch-1.ps
new file mode 100644
index 0000000000..36cd4f9512
--- /dev/null
+++ b/challenge-288/roger-bell-west/postscript/ch-1.ps
@@ -0,0 +1,168 @@
+%!PS
+
+% begin included library code
+% see https://codeberg.org/Firedrake/postscript-libraries/
+/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
+
+/reverse {
+ 1 dict begin
+ dup length /l exch def
+ [ exch
+ aload pop
+ 2 1 l {
+ -1 roll
+ } for
+ ]
+ end
+} 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
+
+/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
+
+/s2a {
+ [ exch { } 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
+
+/closestpalindrome {
+ 0 dict begin
+ cvi /n exch def
+ /delta -1 def
+ {
+ /q n delta add alloccvs def
+ q dup s2a reverse a2s deepeq {
+ q
+ exit
+ } if
+ /delta delta neg def
+ delta 0 lt {
+ /delta delta 1 sub def
+ } if
+ } loop
+ end
+} bind def
+
+(closestpalindrome) test.start
+(123) closestpalindrome (121) eq test
+(2) closestpalindrome (1) eq test
+(1400) closestpalindrome (1441) eq test
+(1000) closestpalindrome (999) eq test
+test.end
diff --git a/challenge-288/roger-bell-west/postscript/ch-2.ps b/challenge-288/roger-bell-west/postscript/ch-2.ps
new file mode 100644
index 0000000000..015259721e
--- /dev/null
+++ b/challenge-288/roger-bell-west/postscript/ch-2.ps
@@ -0,0 +1,212 @@
+%!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
+
+/apush.right { % [a b] c -> [a b c]
+ exch
+ [ exch aload length 2 add -1 roll ]
+} 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
+
+/apop.left { % [a b c] -> [b c] a
+ dup 0 get exch
+ [ exch aload length -1 roll pop ] exch
+} bind def
+
+/test.start {
+ print (:) print
+ /test.pass 0 def
+ /test.count 0 def
+} bind def
+
+/keys { % dict -> array of dict keys
+ [ exch
+ {
+ pop
+ } forall
+ ]
+} bind def
+
+
+/set.difference {
+ 4 dict begin
+ /s 0 dict def
+ /b exch def
+ /a exch def
+ a keys {
+ /k exch def
+ b k known not {
+ s k true put
+ } if
+ } forall
+ s
+ end
+} 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
+
+
+% end included library code
+
+/encode {
+ aload pop
+ exch 1000000 mul add
+} bind def
+
+/decode {
+ dup 1000000 idiv
+ exch
+ 1000000 mod
+ 2 array astore
+} bind def
+
+/contiguousblock {
+ 0 dict begin
+ /a exch def
+ /y a length def
+ /x a 0 get length def
+ /starts 0 dict def
+ 0 1 x 1 sub {
+ /cx exch def
+ 0 1 y 1 sub {
+ cx exch
+ 2 array astore
+ encode
+ starts exch true put
+ } for
+ } for
+ /maxblock 0 def
+ {
+ starts length 0 le {
+ exit
+ } if
+ /start starts keys 0 get def
+ /cstart start decode def
+ /queue [ start ] def
+ /visited << start true >> def
+ {
+ queue length 0 le {
+ exit
+ } if
+ queue apop.left /here exch def /queue exch def
+ /chere here decode def
+ [
+ [ -1 0 ]
+ [ 1 0 ]
+ [ 0 -1 ]
+ [ 0 1 ]
+ ] {
+ /delta exch def
+ delta 0 get 0 ge chere 0 get 0 gt or
+ delta 0 get 0 le chere 0 get x 1 sub lt or and
+ delta 1 get 0 ge chere 1 get 0 gt or and
+ delta 1 get 0 le chere 1 get y 1 sub lt or and {
+ /cthere [
+ chere 0 get delta 0 get add
+ chere 1 get delta 1 get add
+ ] def
+ /there cthere encode def