### Re: Requesting submissions for Exercism track

Oh, you've done yacht, n'er mind, here's a few more that I quickly bashed out

function score_yacht(sequence hand, string category)
integer score = 0
if category[$]='s' then score = find(category,{"ones","twos","threes","fours","fives","sixes"}) score = sum(sq_eq(hand,score))*score else hand = sort(deep_copy(hand)) integer {c1,c2,c3,c4,c5} = hand if category="full house" then if (c1=c3 and c4=c5 and c3!=c4) or (c1=c2 and c3=c5 and c2!=c3) then score = sum(hand) end if elsif category="four of a kind" then if c2=c4 and (c1=c2 or c4=c5) then score = c3*4 end if elsif category="little straight" then if hand={1,2,3,4,5} then score = 30 end if elsif category="big straight" then if hand={2,3,4,5,6} then score = 30 end if elsif category="choice" then score = sum(hand) elsif category="yacht" then if c1=c5 then score = 50 end if else ?9/0 end if end if return score end function constant tests = {{"Yacht",{5, 5, 5, 5, 5},"yacht",50}, {"Not Yacht",{1, 3, 3, 2, 5},"yacht",0}, {"Ones",{1, 1, 1, 3, 5},"ones",3}, {"Ones, out of order",{3, 1, 1, 5, 1},"ones",3}, {"No ones",{4, 3, 6, 5, 5},"ones",0}, {"Twos",{2, 3, 4, 5, 6},"twos",2}, {"Fours",{1, 4, 1, 4, 1},"fours",8}, {"Yacht counted as threes",{3, 3, 3, 3, 3},"threes",15}, {"Yacht of 3s counted as fives",{3, 3, 3, 3, 3},"fives",0}, {"Fives",{1, 5, 3, 5, 3},"fives",10}, {"Sixes",{2, 3, 4, 5, 6},"sixes",6}, {"Full house two small, three big",{2, 2, 4, 4, 4},"full house",16}, {"Full house three small, two big",{5, 3, 3, 5, 3},"full house",19}, {"Two pair is not a full house",{2, 2, 4, 4, 5},"full house",0}, {"Four of a kind is not a full house",{1, 4, 4, 4, 4},"full house",0}, {"Yacht is not a full house",{2, 2, 2, 2, 2},"full house",0}, {"Four of a Kind",{6, 6, 4, 6, 6},"four of a kind",24}, {"Yacht can be scored as Four of a Kind",{3, 3, 3, 3, 3},"four of a kind",12}, {"Full house is not Four of a Kind",{3, 3, 3, 5, 5},"four of a kind",0}, {"Little Straight",{3, 5, 4, 1, 2},"little straight",30}, {"Little Straight as Big Straight",{1, 2, 3, 4, 5},"big straight",0}, {"Four in order but not a little straight",{1, 1, 2, 3, 4},"little straight",0}, {"No pairs but not a little straight",{1, 2, 3, 4, 6},"little straight",0}, {"Minimum is 1, maximum is 5, but not a little straight",{1, 1, 3, 4, 5},"little straight",0}, {"Big Straight",{4, 6, 2, 5, 3},"big straight",30}, {"Big Straight as little straight",{6, 5, 4, 3, 2},"little straight",0}, {"No pairs but not a big straight",{6, 5, 4, 3, 1},"big straight",0}, {"Choice",{3, 3, 5, 6, 6},"choice",23}, {"Yacht as choice",{2, 2, 2, 2, 2},"choice",10}} for t in tests do {string desc, sequence hand, string category, integer expected} = t assert(score_yacht(hand,category)=expected,desc) end for function encode(sequence data) sequence bytes = {} for d in reverse(data) do bytes &= and_bits(d,#7F) d = floor(d/#80) while d do bytes &= and_bits(d,#7F)+#80 d = floor(d/#80) end while end for bytes = reverse(bytes) return bytes end function function decode(sequence bytes) sequence data = {} if length(bytes) and and_bits(bytes[$],#80) then
return "incomplete sequence"
end if
atom d = 0
for b in bytes do
d = d*#80 + and_bits(b,#7F)
if not and_bits(b,#80) then
data &= d
d = 0
end if
end for
return data
end function

constant e = {{"zero",{#00},{#00}},
{"arbitrary single byte",{#40},{#40}},
{"largest single byte",{#7F},{#7F}},
{"smallest double byte",{#80},{#81, #00}},
{"arbitrary double byte",{#2000},{#C0, #00}},
{"largest double byte",{#3FFF},{#FF, #7F}},
{"smallest triple byte",{#4000},{#81, #80, #00}},
{"arbitrary triple byte",{#100000},{#C0, #80, #00}},
{"largest triple byte",{#1FFFFF},{#FF, #FF, #7F}},
{"smallest quadruple byte",{#200000},{#81, #80, #80, #00}},
{"arbitrary quadruple byte",{#8000000},{#C0, #80, #80, #00}},
{"largest quadruple byte",{#FFFFFFF},{#FF, #FF, #FF, #7F}},
{"smallest quintuple byte",{#10000000},{#81, #80, #80, #80, #00}},
{"arbitrary quintuple byte",{#FF000000},{#8F, #F8, #80, #80, #00}},
{"maximum 32-bit integer input",{#FFFFFFFF},{#8F, #FF, #FF, #FF, #7F}},
{"two single-byte values",{#40, #7F},{#40, #7F}},
{"two multi-byte values",{#4000, #123456},{#81, #80, #00, #C8, #E8, #56}},
{"many multi-byte values",{#2000, #123456, #FFFFFFF, #00, #3FFF, #4000},
{#C0, #0, #C8, #E8, #56, #FF, #FF, #FF, #7F, #00, #FF, #7F, #81, #80, #00}}},
d = {{"one byte",{#7F},{#7F}},
{"two bytes",{#C0, #00},{#2000}},
{"three bytes",{#FF, #FF, #7F},{#1FFFFF}},
{"four bytes",{#81, #80, #80, #0},{#200000}},
{"maximum 32-bit integer",{#8F, #FF, #FF, #FF, #7F},{#FFFFFFFF}},
{"incomplete sequence causes error",{#FF},"incomplete sequence"},
{"incomplete sequence causes error, even if value is zero",{#80},"incomplete sequence"},
{"multiple values",{#C0, #00, #C8, #E8, #56, #FF, #FF, #FF, #7F, #00, #FF, #7F, #81, #80, #00},
{#2000, #123456, #FFFFFFF, #00, #3FFF, #4000}}}

string desc; sequence data, expected
for t in e do
{desc, data, expected} = t
assert(encode(data)=expected,desc)
end for
for t in d do
{desc, data, expected} = t
assert(decode(data)=expected,desc)
end for

function sum_of_multiples(sequence f, integer lim)
integer res = 0
for n = 1 to lim-1 do
for k in f do
if k!=0 and remainder(n,k)=0 then
res += n
exit
end if
end for
end for
return res
end function

constant tests = {{"no multiples within limit",{3, 5},1,0},
{"one factor has multiples within limit",{3, 5},4,3},
{"more than one multiple within limit",{3},7,9},
{"more than one factor with multiples within limit",{3, 5},10,23},
{"each multiple is only counted once",{3, 5},100,2318},
{"a much larger limit",{3, 5},1000,233168},
{"three factors",{7, 13, 17},20,51},
{"factors not relatively prime",{4, 6},15,30},
{"some pairs of factors relatively prime and some not",{5, 6, 8},150,4419},
{"one factor is a multiple of another",{5, 25},51,275},
{"much larger factors",{43, 47},10000,2203160},
{"all numbers are multiples of 1",{1},100,4950},
{"no factors means an empty sum",{},10000,0},
{"the only multiple of 0 is 0",{0},1,0},
{"the factor 0 does not affect the sum of multiples of other factors",{3, 0},4,3},
{"solutions using include-exclude must extend to cardinality greater than 3",{2, 3, 5, 7, 11},10000,39614537}}
for t in tests do
{string desc, sequence f, integer lim, integer expected} = t
assert(sum_of_multiples(f,lim)=expected,desc)
end for

constant tests = {{"root of 1",1,1},
{"root of 4",4,2},
{"root of 25",25,5},
{"root of 81",81,9},
{"root of 196",196,14},
{"root of 65025",65025,255}}

for t in tests do
{string desc, integer n, integer expected} = t
assert(sqrt(n)=expected,desc)
end for

function spiral(integer n)
integer x = 1, y = 0, counter = 1,
len = n, dx = 0, dy = 1
sequence m = repeat(repeat(0,n),n)
for i=1 to 2*n do                       -- 2n runs..
for j=1 to len do                   -- of a length...
x += dx
y += dy
m[x][y] = counter
counter += 1
end for
len -= odd(i)                       -- ..-1 every other
{dx,dy} = {dy,-dx}                  -- in new direction
end for
return m
end function

constant tests = {{"empty spiral",0,{}},
{"trivial spiral",1,{{1}}},
{"spiral of size 2",2,{{1, 2},
{4, 3}}},
{"spiral of size 3",3,{{1, 2, 3},
{8, 9, 4},
{7, 6, 5}}},
{"spiral of size 4",4,{{ 1,  2,  3, 4},
{12, 13, 14, 5},
{11, 16, 15, 6},
{10,  9,  8, 7}}},
{"spiral of size 5",5,{{ 1,  2,  3,  4, 5},
{16, 17, 18, 19, 6},
{15, 24, 25, 20, 7},
{14, 23, 22, 21, 8},
{13, 12, 11, 10, 9}}}}
for t in tests do
{string desc, integer n, sequence expected} = t
assert(spiral(n)=expected,desc)
end for

constant ROMAN  = {"M", "CM", "D","CD", "C","XC","L","XL","X","IX","V","IV","I"},
DECML  = {1000, 900, 500, 400, 100, 90, 50,  40,  10,  9,  5,   4,  1 }

function roman(integer val)
string res = ""
for i=1 to length(ROMAN) do
while val>=DECML[i] do
res &= ROMAN[i]
val -= DECML[i]
end while
end for
return res
end function

constant tests = {{"1 is I",1,"I"},
{"2 is II",2,"II"},
{"3 is III",3,"III"},
{"4 is IV",4,"IV"},
{"5 is V",5,"V"},
{"6 is VI",6,"VI"},
{"9 is IX",9,"IX"},
{"16 is XVI",16,"XVI"},
{"27 is XXVII",27,"XXVII"},
{"48 is XLVIII",48,"XLVIII"},
{"49 is XLIX",49,"XLIX"},
{"59 is LIX",59,"LIX"},
{"66 is LXVI",66,"LXVI"},
{"93 is XCIII",93,"XCIII"},
{"141 is CXLI",141,"CXLI"},
{"163 is CLXIII",163,"CLXIII"},
{"166 is CLXVI",166,"CLXVI"},
{"402 is CDII",402,"CDII"},
{"575 is DLXXV",575,"DLXXV"},
{"666 is DCLXVI",666,"DCLXVI"},
{"911 is CMXI",911,"CMXI"},
{"1024 is MXXIV",1024,"MXXIV"},
{"1666 is MDCLXVI",1666,"MDCLXVI"},
{"3000 is MMM",3000,"MMM"},
{"3001 is MMMI",3001,"MMMI"},
{"3999 is MMMCMXCIX",3999,"MMMCMXCIX"}}
for t in tests do
{string desc, integer n, string expected} = t
assert(roman(n)=expected,desc)
end for

constant tests = {
{"an empty string","",""},
{"a word","robot","tobor"},
{"a capitalized word","Ramen","nemaR"},
{"a sentence with punctuation","I'm hungry!","!yrgnuh m'I"},
{"a palindrome","racecar","racecar"},
{"an even-sized word","drawer","reward"}}
for t in tests do
string {desc, s, expected} = t
assert(reverse(s)=expected,desc)
end for

function check(sequence p)
integer {r,c} = p
if r<0 then return "row not positive" end if
if r>7 then return "row not on board" end if
if c<0 then return "column not positive" end if
if c>7 then return "column not on board" end if
return 0
end function

function can_attack(sequence p)
integer {{r1,c1},{r2,c2}} = p
return r1=r2 or c1=c2 or r1-c1=r2-c2 or r1+c1=r2+c2
end function

constant places = {{"queen with a valid position",{2,2},0},
{"queen must have positive row",{-2,2},"row not positive"},
{"queen must have row on board",{8,4},"row not on board"},
{"queen must have positive column",{2,-2},"column not positive"},
{"queen must have column on board",{4,8},"column not on board"}},
attacks = {{"cannot attack",{{2,4},{6,6}},false},
{"can attack on same row",{{2,4},{2,6}},true},
{"can attack on same column",{{4,5},{2,5}},true},
{"can attack on first diagonal",{{2,2},{0,4}},true},
{"can attack on second diagonal",{{2,2},{3,1}},true},
{"can attack on third diagonal",{{2,2},{1,1}},true},
{"can attack on fourth diagonal",{{1,7},{0,6}},true},
{"cannot attack if falling diagonals are only the same when reflected across the longest falling diagonal",{{4,1},{2,5}},false}}
string desc; sequence p; object expected
for p in places do
{desc,p,expected} = p
assert(check(p)=expected,desc)
end for
for a in attacks do
{desc,p,expected} = a
assert(can_attack(p)=expected,desc)
end for

function pythagorean_triplets(integer perim)
sequence res = {}
for a=1 to floor(perim/3) do
for b=a+1 to floor((perim-a)/2) do
integer c = perim-(a+b)
if a*a+b*b=c*c then
res = append(res,{a,b,c})
end if
end for
end for
return res
end function

constant tests = {{"triplets whose sum is 12",12,{{3, 4, 5}}},
{"triplets whose sum is 108",108,{{27, 36, 45}}},
{"triplets whose sum is 1000",1000,{{200, 375, 425}}},
{"no matching triplets for 1001",1001,{}},
{"returns all matching triplets",90,{{9, 40, 41},{15, 36, 39}}},
{"several matching triplets",840,{{40, 399, 401},{56, 390, 394},{105, 360, 375},{120, 350, 370},{140, 336, 364},{168, 315, 357},{210, 280, 350},{240, 252, 348}}},
{"triplets for large number",30000,{{1200, 14375, 14425},{1875, 14000, 14125},{5000, 12000, 13000},{6000, 11250, 12750},{7500, 10000, 12500}}}}
for t in tests do
{string desc, integer n, sequence expected} = t
assert(pythagorean_triplets(n)=expected,desc)
end for

function pascal(integer n)
sequence res = {}, row = repeat(1,n)
for r=1 to n do
for n=r-1 to 2 by -1 do
row[n] += row[n-1]
end for
res = append(res,row[1..r])
end for
return res
end function

constant pt = {{1},
{1, 1},
{1, 2, 1},
{1, 3, 3, 1},
{1, 4, 6, 4, 1},
{1, 5, 10, 10, 5, 1},
{1, 6, 15, 20, 15, 6, 1},
{1, 7, 21, 35, 35, 21, 7, 1},
{1, 8, 28, 56, 70, 56, 28, 8, 1},
{1, 9, 36, 84, 126, 126, 84, 36, 9, 1}}
for n=0 to 10 do
assert(pascal(n)=pt[1..n])
end for

function matrix(string s, rc, integer idx)
sequence m = split(s,"\n")
for i,r in m do
m[i] = apply(split(r,' '),to_integer)
end for
if rc="row" then return m[idx] end if
return vslice(m,idx)
end function

constant tests = {{"extract row from one number matrix","row","1",1,{1}},
{"can extract row","row","1 2\n3 4",2,{3,4}},
{"extract row where numbers have different widths","row","1 2\n10 20",2,{10, 20}},
{"can extract row from non-square matrix with no corresponding column","row","1 2 3\n4 5 6\n7 8 9\n8 7 6",4,{8, 7, 6}},
{"extract column from one number matrix","column","1",1,{1}},
{"can extract column","column","1 2 3\n4 5 6\n7 8 9",3,{3, 6, 9}},
{"can extract column from non-square matrix with no corresponding row","column","1 2 3 4\n5 6 7 8\n9 8 7 6",4,{4, 8, 6}},
{"extract column where numbers have different widths","column","89 1903 3\n18 3 1\n9 4 800",2,{1903, 3, 4}}}

for t in tests do
string desc, rc, m; integer idx; sequence expected
{desc, rc, m, idx, expected} = t
printf(1,"%s : %s[%d] = %v (%t)\n",{m,rc,idx,matrix(m,rc,idx),matrix(m,rc,idx)=expected})
assert(matrix(m,rc,idx)=expected,desc)
end for

function matching_brackets(string s)
sequence stack = {}
string openers = "[{(",
closers = "]})"
for ch in s do
integer k = find(ch,openers)
if k then
stack &= closers[k]
else
k = find(ch,closers)
if k then
if stack={} or ch!=stack[$] then return false end if stack = stack[1..$-1]
end if
end if
end for
return stack = {}
end function

constant tests = {{"paired square brackets","[]",true},
{"empty string","",true},
{"unpaired brackets","[[",false},
{"wrong ordered brackets","}{",false},
{"wrong closing bracket","{]",false},
{"paired with whitespace","{ }",true},
{"partially paired brackets","{[])",false},
{"simple nested brackets","{[]}",true},
{"several paired brackets","{}[]",true},
{"paired and nested brackets","([{}({}[])])",true},
{"unopened closing brackets","{[)][]}",false},
{"unpaired and nested brackets","([{])",false},
{"paired and wrong nested brackets","[({]})",false},
-- Ensures last opened bracket is not the only one being traced
{"paired and wrong nested brackets but innermost are correct","[({}])",false},
{"paired and incomplete brackets","{}[",false},
{"too many closing brackets","[]]",false},
{"early unexpected brackets",")()",false},
{"early mismatched brackets","{)()",false},
{"math expression","(((185 + 223.85) * 15) - 543)/2",true},
{"complex latex expression","\\left(\\begin{array}{cc} \\frac{1}{3} & x\\\\ \\mathrm{e}^{x} &... x^2 \\end{array}\\right)",true}}

for t in tests do
{string desc, string b, bool expected} = t
printf(1,"%s : %t\n",{b,matching_brackets(b)=expected})
assert(matching_brackets(b)=expected,desc)
end for

function luhn(string s)
s = reverse(filter(s,"out"," "))
if length(s)<=1 then return false end if
integer checksum = 0
for i,c in s do
c -= '0'
if c<0 or c>9 then return false end if
if even(i) then
c *= 2
if c>9 then c -= 9 end if
end if
checksum += c
end for
return remainder(checksum,10)=0
end function

constant tests = {{"single digit strings can not be valid","1",false},
{"a single zero is invalid","0",false},
{"a simple valid SIN that remains valid if reversed","059",true},
{"a simple valid SIN that becomes invalid if reversed","59",true},
{"a valid Canadian SIN","055 444 285",true},
{"invalid credit card","8273 1232 7352 0569",false},
{"invalid long number with an even remainder","1 2345 6789 1234 5678 9012",false},
{"invalid long number with a remainder divisible by 5","1 2345 6789 1234 5678 9013",false},
{"valid number with an even number of digits","095 245 88",true},
{"valid number with an odd number of spaces","234 567 891 234",true},
{"valid strings with a non-digit added at the end become invalid","059a",false},
{"valid strings with punctuation included become invalid","055-444-285",false},
{"valid strings with symbols included become invalid","055# 444\$ 285",false},
{"single zero with space is invalid"," 0",false},
{"more than a single zero is valid","0000 0",true},
{"input digit 9 is correctly converted to output digit 9","091",true},
-- Designed to prevent converting input to a single number as this approach can risk an overflow
{"very long input is valid","9999999999 9999999999 9999999999 9999999999",true},
{"valid luhn with an odd number of digits and non zero first digit","109",true},
-- Convert non-digits to their ascii values and then offset them by 48 sometimes accidentally
-- declare an invalid string to be valid. Next two tests are designed to avoid that solution.
{"using ascii value for non-doubled non-digit isn't allowed","055b 444 285",false},
{"using ascii value for doubled non-digit isn't allowed",":9",false},
{"non-numeric, non-space char in the middle with a sum that's divisible by 10 isn't allowed","59%59",false}}

for t in tests do
{string desc, string n, bool expected} = t
printf(1,"%s : %t\n",{n,luhn(n)=expected})
assert(luhn(n)=expected,desc)
end for