I had forgotten that you can have several elements to the Head in a pattern match (then I saw @stevemoon
’s solution), so I used lists:foldr to process the word from the end, which means I accumulate the multipliers and apply them once I encounter a letter. I could have named variables better, but with short names it’s easier on the eye, with this state tuple I’m moving around.
For fun I decided to allow several word multipliers, and to allow the blank indicator before, after, or in the middle of the asterisks.
I made my own tests, and stole other peoples’ as well.
-module(scrabble).-export([word_score/1,letter_score/1]).-include_lib("eunit/include/eunit.hrl").letter_score(Letter)->Points=#{$a=>1,$b=>3,$c=>3,$d=>2,$e=>1,$f=>4,$g=>2,$h=>4,$i=>1,$j=>8,$k=>5,$l=>1,$m=>3,$n=>1,$o=>1,$p=>3,$q=>10,$r=>1,$s=>1,$t=>1,$u=>1,$v=>4,$w=>4,$x=>8,$y=>4,$z=>10},maps:get(Letter,Points).word_score(Word)->{Score,Wm,_Lm,Lc,_State}=lists:foldr(funchar/2,{0,1,1,0,normal},string:lowercase(Word)),Bonus=caseLcof7->50;_->0end,Score*Wm+Bonus.% Score
% Wm = Word multiplier
% Lm = Letter multiplier
% Lc = Letter count
% Parser state
char($\),{Score,Wm,Lm,Lc,normal})->{Score,Wm,Lm,Lc,word_mult};char($d,{Score,Wm,Lm,Lc,word_mult})->{Score,2*Wm,Lm,Lc,word_mult};char($t,{Score,Wm,Lm,Lc,word_mult})->{Score,3*Wm,Lm,Lc,word_mult};char($\(,{Score,Wm,Lm,Lc,word_mult})->{Score,Wm,Lm,Lc,normal};char($*,{Score,Wm,0,Lc,normal})->{Score,Wm,0,Lc,normal};char($*,{Score,Wm,1,Lc,normal})->{Score,Wm,2,Lc,normal};char($*,{Score,Wm,2,Lc,normal})->{Score,Wm,3,Lc,normal};char($^,{Score,Wm,_Lm,Lc,normal})->{Score,Wm,0,Lc,normal};char(L,{Score,Wm,Lm,Lc,normal})->{Score+Lm*letter_score(L),Wm,1,Lc+1,normal}.char_test()->[?assert(char($\),{0,1,1,0,normal})=:={0,1,1,0,word_mult}),?assert(char($d,{0,1,1,0,word_mult})=:={0,2,1,0,word_mult}),?assert(char($d,{0,2,1,0,word_mult})=:={0,4,1,0,word_mult}),?assert(char($t,{0,2,1,0,word_mult})=:={0,6,1,0,word_mult}),?assert(char($\(,{0,3,1,0,word_mult})=:={0,3,1,0,normal}),?assert(char($a,{0,1,1,0,normal})=:={1,1,1,1,normal}),?assert(char($b,{1,1,1,1,normal})=:={4,1,1,2,normal}),?assert(char($*,{4,1,1,2,normal})=:={4,1,2,2,normal}),?assert(char($*,{4,1,2,2,normal})=:={4,1,3,2,normal}),?assert(char($^,{4,1,1,2,normal})=:={4,1,0,2,normal}),?assert(char($*,{4,1,0,2,normal})=:={4,1,0,2,normal})].score_test()->[1=word_score("A"),2=word_score("A(d)"),3=word_score("A(t)"),6=word_score("A(dt)"),6=word_score("A(td)"),12=word_score("A(ddt)"),12=word_score("A(dtd)"),18=word_score("A(ttd)"),4=word_score("AB"),5=word_score("A*B"),6=word_score("A**B"),14=word_score("SCRABBLE"),28=word_score("SCRABBLE(d)"),42=word_score("SCRABBLE(t)"),21=word_score("F**OX"),38=word_score("F**O*X**"),63=word_score("PROBLEM"),77=word_score("PR*OB**LE*M**"),12=word_score("ZER^O"),12=word_score("ZER*^O"),12=word_score("ZER**^O"),12=word_score("ZER^*O"),12=word_score("ZER^**O"),12=word_score("ZER*^*O"),68=word_score("P**RO*B^LE*M"),23=word_score("QUINTESSENTIAL"),11=word_score("HE*LLO**"),69=word_score("QUINTESSENTIAL(t)"),39=word_score("Q^UINTESSENTIAL(t)"),22=word_score("HE*LLO**(d)"),18=word_score("HE^LLO**(d)"),72=word_score("WORDIER(d)"),680=word_score("Z**Z**Z**Z**Z**Z**Z**(t)"),19=word_score("THISWASFUN")].
I’m learning Erlang.
I had forgotten that you can have several elements to the Head in a pattern match (then I saw @stevemoon ’s solution), so I used
lists:foldr
to process the word from the end, which means I accumulate the multipliers and apply them once I encounter a letter. I could have named variables better, but with short names it’s easier on the eye, with this state tuple I’m moving around.For fun I decided to allow several word multipliers, and to allow the blank indicator before, after, or in the middle of the asterisks.
I made my own tests, and stole other peoples’ as well.
To run: