diff --git a/exercises/scrabble-score/example.rs b/exercises/scrabble-score/example.rs index 4a373dc2f..01a24d336 100644 --- a/exercises/scrabble-score/example.rs +++ b/exercises/scrabble-score/example.rs @@ -1,40 +1,35 @@ -use std::collections::HashMap; - pub fn score(word: &str) -> u16 { - let values = dictionary(); - word.to_lowercase() - .chars() - .map(|c| values.get(&c).clone()) - .fold(0, |score, v| score + v.unwrap_or(&0)) + let mut score: u16 = 0; + let mut previous_char_value: u16 = 0; + + // normalise the word to lowercase, for case-insensitivity, also, for easier iteration, + // reduce the multi-character value multipliers :double and :triple to a single char. + let tokenised_word = word.to_lowercase().replace(":double", "2").replace(":triple", "3"); + + for a_char in tokenised_word.chars() { + let value = char_value(a_char, previous_char_value); + score += value; + previous_char_value = value; + } + + score } -fn dictionary() -> HashMap { - let mut values = HashMap::new(); - values.insert('a', 1); - values.insert('b', 3); - values.insert('c', 3); - values.insert('d', 2); - values.insert('e', 1); - values.insert('f', 4); - values.insert('g', 2); - values.insert('h', 4); - values.insert('i', 1); - values.insert('j', 8); - values.insert('k', 5); - values.insert('l', 1); - values.insert('m', 3); - values.insert('n', 1); - values.insert('o', 1); - values.insert('p', 3); - values.insert('q', 10); - values.insert('r', 1); - values.insert('s', 1); - values.insert('t', 1); - values.insert('u', 1); - values.insert('v', 4); - values.insert('w', 4); - values.insert('x', 8); - values.insert('y', 4); - values.insert('z', 10); - values +/// Calculates the value of the current character. +/// +/// The previous characters' value is required in case the current +/// token is a multiplier, which affects the score of the previous char. +fn char_value(the_char: char, prev_value: u16) -> u16 { + match the_char { + 'a'|'e'|'i'|'o'|'u'|'l'|'n'|'r'|'s'|'t' => 1, + 'd'|'g' => 2, + 'b'|'c'|'m'|'p' => 3, + 'f'|'h'|'v'|'w'|'y' => 4, + 'k' => 5, + 'j'|'x' => 8, + 'q'|'z' => 10, + '2' => prev_value, // repeat the previous value, effectively doubling the previous value + '3' => 2*prev_value, // repeat the previous value twice, effectively multiplying it by 3x + _ => 0, // 'funny' characters, such as accented ones or foreign alphabets, count for 0 + } } diff --git a/exercises/scrabble-score/tests/scrabble-score.rs b/exercises/scrabble-score/tests/scrabble-score.rs index caa777266..f98f16dfd 100644 --- a/exercises/scrabble-score/tests/scrabble-score.rs +++ b/exercises/scrabble-score/tests/scrabble-score.rs @@ -61,3 +61,71 @@ fn non_english_scrabble_letters_do_not_score() { fn empty_words_are_worth_zero() { assert_eq!(score(""), 0); } + +// ============================================= +// Extensions +// +// The tests below correspond to the optional +// extensions described in the README +// ============================================= + +#[test] +#[ignore] +fn single_letter_double_score() { + assert_eq!(score("a:double"), 2); +} + +#[test] +#[ignore] +fn other_single_letter_double_score() { + assert_eq!(score("g:double"), 4); +} + +#[test] +#[ignore] +fn double_scoring_letter_in_a_word() { + assert_eq!(score("zo:doubleo"), 13); +} + +#[test] +#[ignore] +fn double_letters_at_word_boundary() { + assert_eq!(score("fabulous"), 13); + assert_eq!(score("f:doubleabulous"), 17); + assert_eq!(score("fabulous:double"), 14); +} + +#[test] +#[ignore] +fn single_letter_triple_score() { + assert_eq!(score("a:triple"), 3); +} + +#[test] +#[ignore] +fn other_single_letter_triple_score() { + assert_eq!(score("g:triple"), 6); +} + +#[test] +#[ignore] +fn triple_scoring_letter_in_a_word() { + assert_eq!(score("zo:tripleo"), 14); +} + +#[test] +#[ignore] +fn triple_letters_at_word_boundary() { + assert_eq!(score("fabulous"), 13); + assert_eq!(score("f:tripleabulous"), 21); + assert_eq!(score("fabulous:triple"), 15); +} + +#[test] +#[ignore] +fn zero_scoring_letters_not_multiplied() { + assert_eq!(score("pinata"), 8); + assert_eq!(score("piñata"), 7); + assert_eq!(score("piñ:doubleata"), 7); + assert_eq!(score("piñ:tripleata"), 7); +}