diff options
| author | Roger Bell_West <roger@firedrake.org> | 2023-05-10 17:43:37 +0100 |
|---|---|---|
| committer | Roger Bell_West <roger@firedrake.org> | 2023-05-10 17:43:37 +0100 |
| commit | bd36304d5d9691dbe21023741457df62d71da81c (patch) | |
| tree | 8d36df341efcdd5e3f1f24282bb7e7c2ee8b8bd3 | |
| parent | 722527ed475e56e5717e60f8d3b52d9bbcef492c (diff) | |
| download | perlweeklychallenge-club-bd36304d5d9691dbe21023741457df62d71da81c.tar.gz perlweeklychallenge-club-bd36304d5d9691dbe21023741457df62d71da81c.tar.bz2 perlweeklychallenge-club-bd36304d5d9691dbe21023741457df62d71da81c.zip | |
RogerBW solutions for challenge no. 216
19 files changed, 1451 insertions, 0 deletions
diff --git a/challenge-216/roger-bell-west/javascript/ch-1.js b/challenge-216/roger-bell-west/javascript/ch-1.js new file mode 100755 index 0000000000..cfebc90c62 --- /dev/null +++ b/challenge-216/roger-bell-west/javascript/ch-1.js @@ -0,0 +1,76 @@ +#! /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 word2set(word) { + let r = new Set(); + for (let c of word.toLowerCase()) { + if (c >= 'a' && c <= 'z') { + r.add(c); + } + } + return r +} + +function registrationnumber(words, reg) { + let out = []; + for (let w of words) { + let ss = word2set(reg); + for (let char of word2set(w)) { + if (ss.has(char)) { + ss.delete(char); + if (ss.size == 0) { + out.push(w); + break; + } + } + } + } + return out; +} + +if (deepEqual(registrationnumber(['abc', 'abcd', 'bcd'], 'AB1 2CD'), ['abcd'])) { + process.stdout.write("Pass"); +} else { + process.stdout.write("FAIL"); +} +process.stdout.write(" "); +if (deepEqual(registrationnumber(['job', 'james', 'bjorg'], '007 JB'), ['job', 'bjorg'])) { + process.stdout.write("Pass"); +} else { + process.stdout.write("FAIL"); +} +process.stdout.write(" "); +if (deepEqual(registrationnumber(['crack', 'road', 'rac'], 'C7 RA2'), ['crack', 'rac'])) { + process.stdout.write("Pass"); +} else { + process.stdout.write("FAIL"); +} +process.stdout.write("\n"); diff --git a/challenge-216/roger-bell-west/javascript/ch-2.js b/challenge-216/roger-bell-west/javascript/ch-2.js new file mode 100755 index 0000000000..aa8c83d535 --- /dev/null +++ b/challenge-216/roger-bell-west/javascript/ch-2.js @@ -0,0 +1,91 @@ +#! /usr/bin/node + +"use strict" + +function word2map(word) { + let m = new Map(); + for (let c of word.toLowerCase()) { + if (m.has(c)) { + m.set(c, m.get(c) + 1); + } else { + m.set(c, 1); + } + } + return m; +} + +function shallowclonemap(m) { + let mm = new Map(); + for (let k of m.keys()) { + mm.set(k, m.get(k)); + } + return mm; +} + +function wordstickers(stickers, word) { + const w = word2map(word); + let t = shallowclonemap(w); + let stick = []; + for (let s of stickers) { + let f = word2map(s); + for (let c of f.keys()) { + t.delete(c); + } + stick.push(f); + } + if (t.size > 0) { + return 0; + } + let stack = [[w, 0]]; + while (stack.length > 0) { + const st = stack.shift(); + if (st[0].size == 0) { + return st[1]; + } else { + const n = st[1] + 1; + for (let sti of stick) { + let sp = shallowclonemap(st[0]); + let v = false; + for (let l of sti.keys()) { + if (sp.has(l)) { + v = true; + const p = sp.get(l) - sti.get(l); + if (p > 0) { + sp.set(l, p); + } else { + sp.delete(l); + } + } + } + if (v) { + stack.push([sp, n]); + } + } + } + } +} + +if (wordstickers(['perl', 'raku', 'python'], 'peon') == 2) { + process.stdout.write("Pass"); +} else { + process.stdout.write("FAIL"); +} +process.stdout.write(" "); +if (wordstickers(['love', 'hate', 'angry'], 'goat') == 3) { + process.stdout.write("Pass"); +} else { + process.stdout.write("FAIL"); +} +process.stdout.write(" "); +if (wordstickers(['come', 'nation', 'delta'], 'accomodation') == 4) { + process.stdout.write("Pass"); +} else { + process.stdout.write("FAIL"); +} +process.stdout.write(" "); +if (wordstickers(['come', 'country', 'delta'], 'accomodation') == 0) { + process.stdout.write("Pass"); +} else { + process.stdout.write("FAIL"); +} +process.stdout.write("\n"); diff --git a/challenge-216/roger-bell-west/kotlin/ch-1.kt b/challenge-216/roger-bell-west/kotlin/ch-1.kt new file mode 100644 index 0000000000..5f0333a7ff --- /dev/null +++ b/challenge-216/roger-bell-west/kotlin/ch-1.kt @@ -0,0 +1,49 @@ +fun word2set(word: String): MutableSet<Char> { + var r = mutableSetOf<Char>() + for (c in word.lowercase()) { + if (c >= 'a' && c <= 'z') { + r.add(c) + } + } + return r +} + +fun registrationnumber(words: List<String>, reg: String): List<String> { + var out = ArrayList<String>() + for (w in words) { + var ss = word2set(reg); + for (char in word2set(w)) { + if (ss.contains(char)) { + ss.remove(char); + if (ss.size == 0) { + out.add(w) + break + } + } + } + } + return out +} + +fun main() { + + if (registrationnumber(listOf("abc", "abcd", "bcd"), "AB1 2CD") == listOf("abcd")) { + print("Pass") + } else { + print("Fail") + } + print(" ") + if (registrationnumber(listOf("job", "james", "bjorg"), "007 JB") == listOf("job", "bjorg")) { + print("Pass") + } else { + print("Fail") + } + print(" ") + if (registrationnumber(listOf("crack", "road", "rac"), "C7 RA2") == listOf("crack", "rac")) { + print("Pass") + } else { + print("Fail") + } + println("") + +} diff --git a/challenge-216/roger-bell-west/kotlin/ch-2.kt b/challenge-216/roger-bell-west/kotlin/ch-2.kt new file mode 100644 index 0000000000..bd624f6ee0 --- /dev/null +++ b/challenge-216/roger-bell-west/kotlin/ch-2.kt @@ -0,0 +1,92 @@ +fun word2map(word: String): Map<Char, Int> { + var m = mutableMapOf<Char, Int>() + for (c in word.lowercase()) { + if (m.contains(c)) { + m.set(c, m.get(c)!! + 1) + } else { + m.set(c, 1) + } + } + return m +} + +fun shallowclonemap(m: Map<Char, Int>): MutableMap<Char, Int> { + var mm = mutableMapOf<Char, Int>() + for (k in m.keys) { + mm.set(k, m.get(k)!!) + } + return mm +} + +fun wordstickers(stickers: List<String>, word: String): Int { + var w = word2map(word) + var t = shallowclonemap(w) + var stick = ArrayList<Map<Char, Int>>() + for (s in stickers) { + val f = word2map(s) + for (c in f.keys) { + t.remove(c) + } + stick.add(f) + } + if (t.size > 0) { + return 0 + } + var stack = arrayListOf(Pair(w, 0)) + while (stack.size > 0) { + val st = stack.removeFirst() + if (st.first.size == 0) { + return st.second + } else { + val n = st.second + 1; + for (sti in stick) { + var sp = shallowclonemap(st.first) + var v = false + for (l in sti.keys) { + if (sp.contains(l)) { + v = true + val p = sp.get(l)!! - sti.get(l)!! + if (p > 0) { + sp.put(l, p) + } else { + sp.remove(l) + } + } + } + if (v) { + stack.add(Pair(sp, n)) + } + } + } + } + return 0 +} + +fun main() { + + if (wordstickers(listOf("perl", "raku", "python"), "peon") == 2) { + print("Pass") + } else { + print("Fail") + } + print(" ") + if (wordstickers(listOf("love", "hate", "angry"), "goat") == 3) { + print("Pass") + } else { + print("Fail") + } + print(" ") + if (wordstickers(listOf("come", "nation", "delta"), "accomodation") == 4) { + print("Pass") + } else { + print("Fail") + } + print(" ") + if (wordstickers(listOf("come", "country", "delta"), "accomodation") == 0) { + print("Pass") + } else { + print("Fail") + } + println("") + +} diff --git a/challenge-216/roger-bell-west/lua/ch-1.lua b/challenge-216/roger-bell-west/lua/ch-1.lua new file mode 100755 index 0000000000..0de0a79536 --- /dev/null +++ b/challenge-216/roger-bell-west/lua/ch-1.lua @@ -0,0 +1,97 @@ +#! /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 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 propersize(t) + local l=0 + for k,v in pairs(t) do + l = l + 1 + end + return l +end + +function word2set(word) + local s = {} + for c in string.gmatch(string.lower(word), "%a") do + s[c] = true + end + return s +end + +function registrationnumber(words, reg) + local s = word2set(reg) + local out = {} + for _, w in ipairs(words) do + local ss = deepcopy(s) + for c, _ in pairs(word2set(w)) do + if s[c] ~= nil then + s[c] = nil + if propersize(s) == 0 then + table.insert(out, w) + break + end + end + end + end + return out +end + +if recursive_compare(registrationnumber({"abc", "abcd", "bcd"}, "AB1 2CD"), {"abcd"}) then + io.write("Pass") +else + io.write("FAIL") +end +io.write(" ") + +if recursive_compare(registrationnumber({"job", "james", "bjorg"}, "007 JB"), {"job", "bjorg"}) then + io.write("Pass") +else + io.write("FAIL") +end +io.write(" ") + +if recursive_compare(registrationnumber({"crack", "road", "rac"}, "C7 RA2"), {"crack", "rac"}) then + io.write("Pass") +else + io.write("FAIL") +end +print("") + diff --git a/challenge-216/roger-bell-west/lua/ch-2.lua b/challenge-216/roger-bell-west/lua/ch-2.lua new file mode 100755 index 0000000000..da804cb8f1 --- /dev/null +++ b/challenge-216/roger-bell-west/lua/ch-2.lua @@ -0,0 +1,112 @@ +#! /usr/bin/lua + +function keys(t) + local a = {} + for k, v in pairs(t) do + table.insert(a, k) + end + return a +end + +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 propersize(t) + local l=0 + for k,v in pairs(t) do + l = l + 1 + end + return l +end + +function word2map(word) + local m = {} + for c in string.gmatch(string.lower(word), "%a") do + if m[c] == nil then + m[c] = 1 + else + m[c] = m[c] + 1 + end + end + return m +end + +function wordstickers(stickers, word) + local w = word2map(word) + local t = deepcopy(w) + local stick = {} + for _, s in ipairs(stickers) do + local f = word2map(s) + for _, c in ipairs(keys(f)) do + t[c] = nil + end + table.insert(stick, f) + end + if propersize(t) > 0 then + return 0 + end + local stack = { {w, 0} } + while #stack > 0 do + local st = table.remove(stack, 1) + if propersize(st[1]) == 0 then + return st[2] + else + local n = st[2] + 1 + for _a, sti in ipairs(stick) do + local sp = deepcopy(st[1]) + local v = false + for _b, l in ipairs(keys(sti)) do + if sp[l] ~= nil then + v = true + p = sp[l] - sti[l] + if p > 0 then + sp[l] = p + else + sp[l] = nil + end + end + end + if v then + table.insert(stack, {sp, n}) + end + end + end + end +end + +if wordstickers({"perl", "raku", "python"}, "peon") == 2 then + io.write("Pass") +else + io.write("FAIL") +end +io.write(" ") + +if wordstickers({"love", "hate", "angry"}, "goat") == 3 then + io.write("Pass") +else + io.write("FAIL") +end +io.write(" ") + +if wordstickers({"come", "nation", "delta"}, "accomodation") == 4 then + io.write("Pass") +else + io.write("FAIL") +end +io.write(" ") + +if wordstickers({"come", "country", "delta"}, "accomodation") == 0 then + io.write("Pass") +else + io.write("FAIL") +end +print("") + diff --git a/challenge-216/roger-bell-west/perl/ch-1.pl b/challenge-216/roger-bell-west/perl/ch-1.pl new file mode 100755 index 0000000000..4fb06c032c --- /dev/null +++ b/challenge-216/roger-bell-west/perl/ch-1.pl @@ -0,0 +1,35 @@ +#! /usr/bin/perl + +use strict; +use warnings; +use experimental 'signatures'; + +use Test::More tests => 3; + +is_deeply(registrationnumber(['abc', 'abcd', 'bcd'], 'AB1 2CD'), ['abcd'], 'example 1'); +is_deeply(registrationnumber(['job', 'james', 'bjorg'], '007 JB'), ['job', 'bjorg'], 'example 2'); +is_deeply(registrationnumber(['crack', 'road', 'rac'], 'C7 RA2'), ['crack', 'rac'], 'example 3'); + +use Storable qw(dclone); + +sub word2set($word) { + return {map {$_ => 1} grep /[a-z]/, split '', lc($word)}; +} + +sub registrationnumber($words, $reg) { + my $s = word2set($reg); + my @out; + foreach my $w (@{$words}) { + my $ss = dclone($s); + foreach my $char (keys %{word2set($w)}) { + if (exists $ss->{$char}) { + delete $ss->{$char}; + if (scalar %{$ss} == 0) { + push @out, $w; + last; + } + } + } + } + return \@out; +} diff --git a/challenge-216/roger-bell-west/perl/ch-2.pl b/challenge-216/roger-bell-west/perl/ch-2.pl new file mode 100755 index 0000000000..2ad6af790c --- /dev/null +++ b/challenge-216/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(wordstickers(['perl', 'raku', 'python'], 'peon'), 2, 'example 1'); +is(wordstickers(['love', 'hate', 'angry'], 'goat'), 3, 'example 2'); +is(wordstickers(['come', 'nation', 'delta'], 'accomodation'), 4, 'example 3'); +is(wordstickers(['come', 'country', 'delta'], 'accomodation'), 0, 'example 4'); + +use Storable qw(dclone); + +sub wordstickers($stickers, $word) { + my %w; + map {$w{$_}++} split '',lc($word); + my $t = dclone(\%w); + my @stick; + foreach my $s (@{$stickers}) { + my %f; + map {$f{$_}++} split '',lc($s); + map {delete $t->{$_}} keys %f; + push @stick, \%f; + } + if (scalar %{$t}) { + return 0; + } + my @stack = ([\%w, 0]); + while (scalar @stack > 0) { + my $st = shift @stack; + if (scalar %{$st->[0]} == 0) { + return $st->[1]; + } else { + my $n = $st->[1] + 1; + foreach my $sti (@stick) { + my $sp = dclone($st->[0]); + my $v = 0; + foreach my $l (keys %{$sti}) { + if (exists $sp->{$l}) { + $v = 1; + my $p = $sp->{$l} - $sti->{$l}; + if ($p > 0) { + $sp->{$l} = $p; + } else { + delete $sp->{$l}; + } + } + } + if ($v) { + push @stack, [$sp, $n]; + } + } + } + } +} diff --git a/challenge-216/roger-bell-west/postscript/ch-1.ps b/challenge-216/roger-bell-west/postscript/ch-1.ps new file mode 100644 index 0000000000..727c189748 --- /dev/null +++ b/challenge-216/roger-bell-west/postscript/ch-1.ps @@ -0,0 +1,178 @@ +%!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 + +/deepcopy { + 2 dict begin + /a exch def + a type /dicttype eq { + << + a keys { + /k exch def + 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 + +/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 + +/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.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 + + +% end included library code + +/word2set { + 2 dict begin + /s 0 dict def + { + /c exch def + c 65 ge c 90 le and { + /c c 32 add def + } if + c 97 ge c 122 le and { + s c true put + } if + } forall + s + end +} bind def + +/registrationnumber { + 6 dict begin + /reg exch def + /words exch def + /s reg word2set def + [ + words { + /w exch def + /ss s deepcopy def + w word2set keys { + /char exch def + ss char known { + ss char undef + ss length 0 eq { + w + exit + } if + } if + } forall + } forall + ] + end +} bind def + +(registrationnumber) test.start +[(abc) (abcd) (bcd)] (AB1 2CD) registrationnumber [(abcd)] deepeq test +[(job) (james) (bjorg)] (007 JB) registrationnumber [(job) (bjorg)] deepeq test +[(crack) (road) (rac)] (C7 RA2) registrationnumber [(crack) (rac)] deepeq test +test.end diff --git a/challenge-216/roger-bell-west/postscript/ch-2.ps b/challenge-216/roger-bell-west/postscript/ch-2.ps new file mode 100644 index 0000000000..adede24f3c --- /dev/null +++ b/challenge-216/roger-bell-west/postscript/ch-2.ps @@ -0,0 +1,165 @@ +%!PS + +% begin included library code +% see https://codeberg.org/Firedrake/postscript-libraries/ +/keys { % dict -> array of dict keys + [ exch + { + pop + } forall + ] +} bind def + +/deepcopy { + 2 dict begin + /a exch def + a type /dicttype eq { + << + a keys { + /k exch def + 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 + +/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 + +/test.start { + print (:) print + /test.pass 0 def + /test.count 0 def +} bind def + +/apop.left { % [a b c] -> [b c] a + dup 0 get exch + [ exch aload length -1 roll pop ] exch +} 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 + +/apush.right { % [a b] c -> [a b c] + exch + [ exch aload length 2 add -1 roll ] +} bind def + + +% end included library code + +/word2map { + 2 dict begin + /m 0 dict def + { + /c exch def + c 65 ge c 90 le and { + /c c 32 add def + } if + c 97 ge c 122 le and { + m c known { + m c m c get 1 add put + } { + m c 1 put + } ifelse + } if + } forall + m + end +} bind def + +/wordstickers { + 12 dict begin + word2map /w exch def + /t w deepcopy def + /stick exch + [ exch + { + /f exch word2map def + f keys { + /c exch def + t c known { + t c undef + } if + } forall + f + } forall + ] def + t length 0 gt { + 0 + } { + /stack [ [ w 0 ] ] def + { + stack apop.left /st exch def /stack exch def + st 0 get length 0 eq { + st 1 get + exit + } { + /n st 1 get 1 add def + stick { + /sti exch def + /sp st 0 get deepcopy def + /v false def + sti keys { + /l exch def + sp l known { + /v true def + /p sp l get sti l get sub def + p 0 gt { + sp l p put + } { + sp l undef + } ifelse + } if + } forall + v { + /stack stack [ sp n ] apush.right def + } if + } forall + } ifelse + } loop + } ifelse + end +} bind def + +(wordstickers) test.start +[(perl) (raku) (python)] (peon) wordstickers 2 eq test +[(love) (hate) (angry)] (goat) wordstickers 3 eq test +[(come) (nation) (delta)] (accomodation) wordstickers 4 eq test +[(come) (country) (delta)] (accomodation) wordstickers 0 eq test +test.end diff --git a/challenge-216/roger-bell-west/python/ch-1.py b/challenge-216/roger-bell-west/python/ch-1.py new file mode 100755 index 0000000000..adfba72f9a --- /dev/null +++ b/challenge-216/roger-bell-west/python/ch-1.py @@ -0,0 +1,38 @@ +#! /usr/bin/python3 + +from copy import deepcopy + +def word2set(word): + r = set() + for c in word.lower(): + if c >= 'a' and c <= 'z': + r.add(c) + return r + +def registrationnumber(words, reg): + s = word2set(reg) + out = [] + for w in words: + ss = deepcopy(s) + for char in word2set(w): + if char in ss: + ss -= set(char) + if len(ss) == 0: + out.append(w) + break + return out + +import unittest + +class TestRegistrationnumber(unittest.TestCase): + + def test_ex1(self): + self.assertEqual(registrationnumber(["abc", "abcd", "bcd"], "AB1 2CD"), ["abcd"], 'example 1') + + def test_ex2(self): + self.assertEqual(registrationnumber(["job", "james", "bjorg"], "007 JB"), ["job", "bjorg"], 'example 2' |
