diff options
| author | Roger Bell_West <roger@firedrake.org> | 2025-08-19 12:16:29 +0100 |
|---|---|---|
| committer | Roger Bell_West <roger@firedrake.org> | 2025-08-19 12:16:29 +0100 |
| commit | b3d35809f9e728cd1e057ccc7980e0d77f6970f4 (patch) | |
| tree | 288ec39d893dfcadd4dd24be4294a9b76efaf1a3 | |
| parent | 72115ca8dee469436857991c88d7002158725057 (diff) | |
| download | perlweeklychallenge-club-b3d35809f9e728cd1e057ccc7980e0d77f6970f4.tar.gz perlweeklychallenge-club-b3d35809f9e728cd1e057ccc7980e0d77f6970f4.tar.bz2 perlweeklychallenge-club-b3d35809f9e728cd1e057ccc7980e0d77f6970f4.zip | |
RogerBW solutions for challenge no. 335
25 files changed, 2041 insertions, 0 deletions
diff --git a/challenge-335/roger-bell-west/crystal/ch-1.cr b/challenge-335/roger-bell-west/crystal/ch-1.cr new file mode 100755 index 0000000000..d16cb98692 --- /dev/null +++ b/challenge-335/roger-bell-west/crystal/ch-1.cr @@ -0,0 +1,55 @@ +#! /usr/bin/crystal + +def counterify(a) + cc = Hash(Char, Int32).new(default_value: 0) + a.each do |x| + cc[x] += 1 + end + return cc +end + +def commoncharacters(a) + mc = Hash(Char, Int32).new + first = true + a.each do |s| + mk = counterify(s.chars) + if first + mc = mk + first = false + else + mc.keys.each do |k| + if mk.has_key?(k) + mc[k] = [mc[k], mk[k]].min + else + mc.delete(k) + end + end + end + end + out = Array(String).new + mc.keys.sort.each do |c| + 1.upto(mc[c]) do + out.push(c.to_s) + end + end + out +end + +require "spec" +describe "commoncharacters" do + it "test_ex1" do + commoncharacters(["bella", "label", "roller"]).should eq ["e", "l", "l"] + end + it "test_ex2" do + commoncharacters(["cool", "lock", "cook"]).should eq ["c", "o"] + end + it "test_ex3" do + commoncharacters(["hello", "world", "pole"]).should eq ["l", "o"] + end + it "test_ex4" do + commoncharacters(["abc", "def", "ghi"]).should eq Array(String).new + end + it "test_ex5" do + commoncharacters(["aab", "aac", "aaa"]).should eq ["a", "a"] + end +end diff --git a/challenge-335/roger-bell-west/crystal/ch-2.cr b/challenge-335/roger-bell-west/crystal/ch-2.cr new file mode 100755 index 0000000000..29405bd9d8 --- /dev/null +++ b/challenge-335/roger-bell-west/crystal/ch-2.cr @@ -0,0 +1,63 @@ +#! /usr/bin/crystal + +def findwinner(a) + board = [ + [ 0, 0, 0 ], + [ 0, 0, 0 ], + [ 0, 0, 0 ] + ] + player = 1 + a.each do |play| + board[play[0]][play[1]] = player + player = 3 - player + end + [ + [0, 0, 1, 0], + [0, 1, 1, 0], + [0, 2, 1, 0], + [0, 0, 0, 1], + [1, 0, 0, 1], + [2, 0, 0, 1], + [0, 0, 1, 1], + [0, 2, 1, -1], + ].each do |pattern| + cellvals = Set(Int32).new + 0.upto(2) do |i| + x = pattern[0] + i * pattern[2] + y = pattern[1] + i * pattern[3] + cellvals.add(board[y][x]) + end + if cellvals.size == 1 + winner = cellvals.to_a[0] + if winner == 1 + return "A" + elsif winner == 2 + return "B" + end + end + end + if a.size == 9 + return "Draw" + else + return "Pending" + end +end + +require "spec" +describe "findwinner" do + it "test_ex1" do + findwinner([[0, 0], [2, 0], [1, 1], [2, 1], [2, 2]]).should eq "A" + end + it "test_ex2" do + findwinner([[0, 0], [1, 1], [0, 1], [0, 2], [1, 0], [2, 0]]).should eq "B" + end + it "test_ex3" do + findwinner([[0, 0], [1, 1], [2, 0], [1, 0], [1, 2], [2, 1], [0, 1], [0, 2], [2, 2]]).should eq "Draw" + end + it "test_ex4" do + findwinner([[0, 0], [1, 1]]).should eq "Pending" + end + it "test_ex5" do + findwinner([[1, 1], [0, 0], [2, 2], [0, 1], [1, 0], [0, 2]]).should eq "B" + end +end diff --git a/challenge-335/roger-bell-west/javascript/ch-1.js b/challenge-335/roger-bell-west/javascript/ch-1.js new file mode 100755 index 0000000000..7c002de222 --- /dev/null +++ b/challenge-335/roger-bell-west/javascript/ch-1.js @@ -0,0 +1,101 @@ +#! /usr/bin/node + +"use strict" + +function commoncharacters(a) { + let mc = new Map; + let first = true; + for (let s of a) { + const mk = counterify(s.split("")); + if (first) { + mc = mk; + first = false; + } else { + for (let k of mc.keys()) { + if (mk.has(k)) { + mc.set(k, Math.min(mc.get(k), mk.get(k))); + } else { + mc.delete(k); + } + } + } + } + let out = []; + let kl = [...mc.keys()]; + kl.sort(); + for (let c of kl) { + for (let n = 1; n <= mc.get(c); n++) { + out.push(c); + } + } + return out; +} + +function counterify(a) { + let cc = new Map; + for (let x of a) { + if (!cc.has(x)) { + cc.set(x, 0); + } + cc.set(x, cc.get(x) + 1); + } + return cc; +} + +// 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; + } +} + +if (deepEqual(commoncharacters(['bella', 'label', 'roller']), ['e', 'l', 'l'])) { + process.stdout.write("Pass"); +} else { + process.stdout.write("FAIL"); +} +process.stdout.write(" "); +if (deepEqual(commoncharacters(['cool', 'lock', 'cook']), ['c', 'o'])) { + process.stdout.write("Pass"); +} else { + process.stdout.write("FAIL"); +} +process.stdout.write(" "); +if (deepEqual(commoncharacters(['hello', 'world', 'pole']), ['l', 'o'])) { + process.stdout.write("Pass"); +} else { + process.stdout.write("FAIL"); +} +process.stdout.write(" "); +if (deepEqual(commoncharacters(['abc', 'def', 'ghi']), [])) { + process.stdout.write("Pass"); +} else { + process.stdout.write("FAIL"); +} +process.stdout.write(" "); +if (deepEqual(commoncharacters(['aab', 'aac', 'aaa']), ['a', 'a'])) { + process.stdout.write("Pass"); +} else { + process.stdout.write("FAIL"); +} +process.stdout.write("\n"); diff --git a/challenge-335/roger-bell-west/javascript/ch-2.js b/challenge-335/roger-bell-west/javascript/ch-2.js new file mode 100755 index 0000000000..a3eda21565 --- /dev/null +++ b/challenge-335/roger-bell-west/javascript/ch-2.js @@ -0,0 +1,73 @@ +#! /usr/bin/node + +"use strict" + +function findwinner(a) { + let board = [ [0, 0, 0], [0, 0, 0], [0, 0, 0] ]; + let player = 1; + for (let play of a) { + board[play[0]][play[1]] = player; + player = 3 - player; + } + for (let pattern of [ + [0, 0, 1, 0], + [0, 1, 1, 0], + [0, 2, 1, 0], + [0, 0, 0, 1], + [1, 0, 0, 1], + [2, 0, 0, 1], + [0, 0, 1, 1], + [0, 2, 1, -1] + ]) { + let cellvals = new Set; + for (let i = 0; i <= 2; i++) { + const x = pattern[0] + i * pattern[2]; + const y = pattern[1] + i * pattern[3]; + cellvals.add(board[y][x]); + } + if (cellvals.size == 1) { + let winner = [...cellvals][0]; + if (winner == 1) { + return "A"; + } else if (winner == 2) { + return "B"; + } + } + } + if (a.length == 9) { + return "Draw"; + } else { + return "Pending"; + } +} + +if (findwinner([[0, 0], [2, 0], [1, 1], [2, 1], [2, 2]]) == 'A') { + process.stdout.write("Pass"); +} else { + process.stdout.write("FAIL"); +} +process.stdout.write(" "); +if (findwinner([[0, 0], [1, 1], [0, 1], [0, 2], [1, 0], [2, 0]]) == 'B') { + process.stdout.write("Pass"); +} else { + process.stdout.write("FAIL"); +} +process.stdout.write(" "); +if (findwinner([[0, 0], [1, 1], [2, 0], [1, 0], [1, 2], [2, 1], [0, 1], [0, 2], [2, 2]]) == 'Draw') { + process.stdout.write("Pass"); +} else { + process.stdout.write("FAIL"); +} +process.stdout.write(" "); +if (findwinner([[0, 0], [1, 1]]) == 'Pending') { + process.stdout.write("Pass"); +} else { + process.stdout.write("FAIL"); +} +process.stdout.write(" "); +if (findwinner([[1, 1], [0, 0], [2, 2], [0, 1], [1, 0], [0, 2]]) == 'B') { + process.stdout.write("Pass"); +} else { + process.stdout.write("FAIL"); +} +process.stdout.write("\n"); diff --git a/challenge-335/roger-bell-west/kotlin/ch-1.kt b/challenge-335/roger-bell-west/kotlin/ch-1.kt new file mode 100644 index 0000000000..b63b668434 --- /dev/null +++ b/challenge-335/roger-bell-west/kotlin/ch-1.kt @@ -0,0 +1,70 @@ +fun counterify(a: List<Char>): Map<Char, Int> { + var cc = mutableMapOf<Char, Int>().withDefault({0}) + for (x in a) { + cc.set(x, cc.getValue(x) + 1) + } + return cc +} + +fun commoncharacters(a: List<String>): List<String> { + var mc = mutableMapOf<Char, Int>().withDefault({0}) + var first = true + for (s in a) { + val mk = counterify(s.toCharArray().toList()) + if (first) { + mc = mk.toMutableMap() + first = false + } else { + for (k in mc.keys.toList()) { + if (mk.contains(k)) { + mc.set(k, listOf(mc.getValue(k), mk.getValue(k)).minOrNull()!!) + } else { + mc.remove(k) + } + } + } + } + var out = ArrayList<String>() + for (c in mc.keys.sorted()) { + val s = c.toString() + for (n in 1 .. mc.getValue(c)) { + out.add(s) + } + } + return out.toList() +} + +fun main() { + + if (commoncharacters(listOf("bella", "label", "roller")) == listOf("e", "l", "l")) { + print("Pass") + } else { + print("Fail") + } + print(" ") + if (commoncharacters(listOf("cool", "lock", "cook")) == listOf("c", "o")) { + print("Pass") + } else { + print("Fail") + } + print(" ") + if (commoncharacters(listOf("hello", "world", "pole")) == listOf("l", "o")) { + print("Pass") + } else { + print("Fail") + } + print(" ") + if (commoncharacters(listOf("abc", "def", "ghi")) == emptyList<String>()) { + print("Pass") + } else { + print("Fail") + } + print(" ") + if (commoncharacters(listOf("aab", "aac", "aaa")) == listOf("a", "a")) { + print("Pass") + } else { + print("Fail") + } + println("") + +} diff --git a/challenge-335/roger-bell-west/kotlin/ch-2.kt b/challenge-335/roger-bell-west/kotlin/ch-2.kt new file mode 100644 index 0000000000..2cb9878611 --- /dev/null +++ b/challenge-335/roger-bell-west/kotlin/ch-2.kt @@ -0,0 +1,76 @@ +fun findwinner(a: List<List<Int>>): String { + var board = ArrayList(listOf(ArrayList(listOf(0, 0, 0)), + ArrayList(listOf(0, 0, 0)), + ArrayList(listOf(0, 0, 0)) + )) + var player = 1 + for (play in a) { + board[play[0]][play[1]] = player + player = 3 - player + } + for (pattern in listOf( + listOf(0, 0, 1, 0), + listOf(0, 1, 1, 0), + listOf(0, 2, 1, 0), + listOf(0, 0, 0, 1), + listOf(1, 0, 0, 1), + listOf(2, 0, 0, 1), + listOf(0, 0, 1, 1), + listOf(0, 2, 1, -1) + )) { + var cellvals = mutableSetOf<Int>() + for (i in 0 .. 2) { + val x = pattern[0] + i * pattern[2] + val y = pattern[1] + i * pattern[3] + cellvals.add(board[y][x]) + } + if (cellvals.size == 1) { + var winner = cellvals.toList()[0] + if (winner == 1) { + return "A" + } else if (winner == 2) { + return "B" + } + } + } + if (a.size == 9) { + return "Draw" + } else { + return "Pending" + } +} + +fun main() { + + if (findwinner(listOf(listOf(0, 0), listOf(2, 0), listOf(1, 1), listOf(2, 1), listOf(2, 2))) == "A") { + print("Pass") + } else { + print("Fail") + } + print(" ") + if (findwinner(listOf(listOf(0, 0), listOf(1, 1), listOf(0, 1), listOf(0, 2), listOf(1, 0), listOf(2, 0))) == "B") { + print("Pass") + } else { + print("Fail") + } + print(" ") + if (findwinner(listOf(listOf(0, 0), listOf(1, 1), listOf(2, 0), listOf(1, 0), listOf(1, 2), listOf(2, 1), listOf(0, 1), listOf(0, 2), listOf(2, 2))) == "Draw") { + print("Pass") + } else { + print("Fail") + } + print(" ") + if (findwinner(listOf(listOf(0, 0), listOf(1, 1))) == "Pending") { + print("Pass") + } else { + print("Fail") + } + print(" ") + if (findwinner(listOf(listOf(1, 1), listOf(0, 0), listOf(2, 2), listOf(0, 1), listOf(1, 0), listOf(0, 2))) == "B") { + print("Pass") + } else { + print("Fail") + } + println("") + +} diff --git a/challenge-335/roger-bell-west/lua/ch-1.lua b/challenge-335/roger-bell-west/lua/ch-1.lua new file mode 100755 index 0000000000..200f658fec --- /dev/null +++ b/challenge-335/roger-bell-west/lua/ch-1.lua @@ -0,0 +1,123 @@ +#! /usr/bin/lua + +function commoncharacters(a) + local mc = {} + for sn, s in ipairs(a) do + local mk = counterify(split(s)) + if sn == 1 then + mc = mk + else + for k, _v in pairs(mc) do + if mk[k] ~= nil then + mc[k] = math.min(mc[k], mk[k]) + else + mc[k] = nil + end + end + end + end + local out = {} + local kl = keys(mc) + table.sort(kl) + for _, c in ipairs(kl) do + for n = 1, mc[c] do + table.insert(out, c) + end + end + return out +end + +function keys(t) + local a = {} + for k, v in pairs(t) do + table.insert(a, k) + end + return a +end + +function counterify(a) + local cc = {} + for _, c in ipairs(a) do + if cc[c] == nil then + cc[c] = 0 + end + cc[c] = cc[c] + 1 + end + return cc +end + +function split(t) + local cl = {} + string.gsub(t, + "(.)", + function(c) + table.insert(cl, c) + end + ) + return cl +end + +-- 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 + +if recursive_compare(commoncharacters({"bella", "label", "roller"}), {"e", "l", "l"}) then + io.write("Pass") +else + io.write("FAIL") +end +io.write(" ") + +if recursive_compare(commoncharacters({"cool", "lock", "cook"}), {"c", "o"}) then + io.write("Pass") +else + io.write("FAIL") +end +io.write(" ") + +if recursive_compare(commoncharacters({"hello", "world", "pole"}), {"l", "o"}) then + io.write("Pass") +else + io.write("FAIL") +end +io.write(" ") + +if recursive_compare(commoncharacters({"abc", "def", "ghi"}), {}) then + io.write("Pass") +else + io.write("FAIL") +end +io.write(" ") + +if recursive_compare(commoncharacters({"aab", "aac", "aaa"}), {"a", "a"}) then + io.write("Pass") +else + io.write("FAIL") +end +print("") + diff --git a/challenge-335/roger-bell-west/lua/ch-2.lua b/challenge-335/roger-bell-west/lua/ch-2.lua new file mode 100755 index 0000000000..573112c886 --- /dev/null +++ b/challenge-335/roger-bell-west/lua/ch-2.lua @@ -0,0 +1,85 @@ +#! /usr/bin/lua + +function findwinner(a) + local board = { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } } + local player = 1 + for _, play in ipairs(a) do + board[1 + play[1]][1 + play[2]] = player + player = 3 - player + end + for _, pattern in ipairs({ + {0, 0, 1, 0}, + {0, 1, 1, 0}, + {0, 2, 1, 0}, + {0, 0, 0, 1}, + {1, 0, 0, 1}, + {2, 0, 0, 1}, + {0, 0, 1, 1}, + {0, 2, 1, -1} + }) do + local cellvals = {} + for i = 0, 2 do + local x = 1 + pattern[1] + i * pattern[3] + local y = 1 + pattern[2] + i * pattern[4] + cellvals[board[y][x]] = true + end + local w = keys(cellvals) + if #w == 1 then + local winner = w[1] + if winner == 1 then + return "A" + elseif winner == 2 then + return "B" + end + end + end + if #a == 9 then + return "Draw" + else + return "Pending" + end +end + +function keys(t) + local a = {} + for k, v in pairs(t) do + table.insert(a, k) + end + return a +end + +if findwinner({{0, 0}, {2, 0}, {1, 1}, {2, 1}, {2, 2}}) == "A" then + io.write("Pass") +else + io.write("FAIL") +end +io.write(" ") + +if findwinner({{0, 0}, {1, 1}, {0, 1}, {0, 2}, {1, 0}, {2, 0}}) == "B" then + io.write("Pass") +else + io.write("FAIL") +end +io.write(" ") + +if findwinner({{0, 0}, {1, 1}, {2, 0}, {1, 0}, {1, 2}, {2, 1}, {0, 1}, {0, 2}, {2, 2}}) == "Draw" then + io.write("Pass") +else + io.write("FAIL") +end +io.write(" ") + +if findwinner({{0, 0}, {1, 1}}) == "Pending" then + io.write("Pass") +else + io.write("FAIL") +end +io.write(" ") + +if findwinner({{1, 1}, {0, 0}, {2, 2}, {0, 1}, {1, 0}, {0, 2}}) == "B" then + io.write("Pass") +else + io.write("FAIL") +end +print("") + diff --git a/challenge-335/roger-bell-west/perl/ch-1.pl b/challenge-335/roger-bell-west/perl/ch-1.pl new file mode 100755 index 0000000000..e8c55e6a0c --- /dev/null +++ b/challenge-335/roger-bell-west/perl/ch-1.pl @@ -0,0 +1,43 @@ +#! /usr/bin/perl + +use strict; +use warnings; +use experimental 'signatures'; + +use Test::More tests => 5; + +is_deeply(commoncharacters(['bella', 'label', 'roller']), ['e', 'l', 'l'], 'example 1'); +is_deeply(commoncharacters(['cool', 'lock', 'cook']), ['c', 'o'], 'example 2'); +is_deeply(commoncharacters(['hello', 'world', 'pole']), ['l', 'o'], 'example 3'); +is_deeply(commoncharacters(['abc', 'def', 'ghi']), [], 'example 4'); +is_deeply(commoncharacters(['aab', 'aac', 'aaa']), ['a', 'a'], 'example 5'); + +use List::Util qw(min); + +sub commoncharacters($a) { + my %mc; + my $first = 1; + foreach my $s (@{$a}) { + my %mk; + map {$mk{$_}++} split '',$s; + if ($first) { + %mc = %mk; + $first = 0; + } else { + foreach my $k (keys %mc) { + if (exists $mk{$k}) { + $mc{$k} = min($mc{$k}, $mk{$k}); + } else { + delete $mc{$k}; + } + } + } + } + my @out; + foreach my $c (sort keys %mc) { + foreach (1 .. $mc{$c}) { + push @out, $c; + } + } + \@out; +} diff --git a/challenge-335/roger-bell-west/perl/ch-2.pl b/challenge-335/roger-bell-west/perl/ch-2.pl new file mode 100755 index 0000000000..bf5f0f13cc --- /dev/null +++ b/challenge-335/roger-bell-west/perl/ch-2.pl @@ -0,0 +1,56 @@ +#! /usr/bin/perl + +use strict; +use warnings; +use experimental 'signatures'; + +use Test::More tests => 5; + +is(findwinner([[0, 0], [2, 0], [1, 1], [2, 1], [2, 2]]), 'A', 'example 1'); +is(findwinner([[0, 0], [1, 1], [0, 1], [0, 2], [1, 0], [2, 0]]), 'B', 'example 2'); +is(findwinner([[0, 0], [1, 1], [2, 0], [1, 0], [1, 2], [2, 1], [0, 1], [0, 2], [2, 2]]), 'Draw', 'example 3'); +is(findwinner([[0, 0], [1, 1]]), 'Pending', 'example 4'); +is(findwinner([[1, 1], [0, 0], [2, 2], [0, 1], [1, 0], [0, 2]]), 'B', 'example 5'); + +sub findwinner($a) { + my @board = ( + [ 0, 0, 0 ], + [ 0, 0, 0 ], + [ 0, 0, 0 ], + ); + my $player = 1; + foreach my $play (@{$a}) { + $board[$play->[0]][$play->[1]] = $player; + $player = 3 - $player; + } + foreach my $pattern ( + [0, 0, 1, 0], + [0, 1, 1, 0], + [0, 2, 1, 0], + [0, 0, 0, 1], + [1, 0, 0, 1], + [2, 0, 0, 1], + [0, 0, 1, 1], + [0, 2, 1, -1], + ) { + my %cellvals; + foreach my $i (0 .. 2) { + my $x = $pattern->[0] + $i * $pattern->[2]; + my $y = $pattern->[1] + $i * $pattern->[3]; + $cellvals{$board[$y][$x]}++; + } + if (scalar keys %cellvals == 1) { + my $winner = (keys %cellvals)[0]; + if ($winner == 1) { + return "A"; + } elsif ($winner == 2) { + return "B"; + } + } + } + if (scalar @{$a} == 9) { + return "Draw"; + } else { + return "Pending"; + } +} diff --git a/challenge-335/roger-bell-west/postscript/ch-1.ps b/challenge-335/roger-bell-west/postscript/ch-1.ps new file mode 100644 index 0000000000..b70b315685 --- /dev/null +++ b/challenge-335/roger-bell-west/postscript/ch-1.ps @@ -0,0 +1,261 @@ +%!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 + +/s2a { + [ exch { } forall ] +} 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.with_comparator { % [ a c b ] { comparator } -> [ a b c ] + 2 dict begin + /cmp exch def + /arr exch def + arr length 0 gt { + 0 arr length 1 sub quicksort.main + } if + arr + end +} 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 + +/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 + +/quicksort.cmp { + 2 copy + lt { + pop pop -1 + } { + gt { + 1 + } { + 0 + } ifelse + } ifelse +} 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 + +/quicksort { + { quicksort.cmp } quicksort.with_comparator +} 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 cmp 0 ge { + exit + } if + } loop + { + /j j 1 sub def + arr j get pivot cmp 0 le { + exit + } if + } loop + i j ge { + j + exit + } if + i j quicksort.swap + } loop + end |
