Re: Requesting submissions for Exercism track
- Posted by petelomax Feb 26, 2023
- 946 views
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 Canadian SIN","055 444 286",false}, {"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