re: Daily Challenge #8 - Scrabble Word Calculator VIEW POST

FULL DISCUSSION
 

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.

-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(
        fun char/2,
        { 0, 1, 1, 0, normal },
        string:lowercase( Word )
    ),
    Bonus = case Lc of 7 -> 50; _ -> 0 end,
    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")
].

To run:

% erl
1> c(scrabble).
{ok,scrabble}
2> scrabble:test().
  2 tests passed.
ok
code of conduct - report abuse