DEV Community

Discussion on: Daily Challenge #8 - Scrabble Word Calculator

Collapse
 
kaspermeyer profile image
Kasper Meyer

Ruby solution

require "minitest/autorun"

class ScrabbleLetter
  SCORES = {
    '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
  }.freeze

  # Parses a string of scrabble letters and separates
  # them with their multiplier still intact.
  #
  # @example
  #
  #   ScrabbleLetter.parse("h^i**")
  #   # => [#<ScrabbleLetter @letter="h^">, #<ScrabbleLetter @letter="i**">]
  #
  def self.parse string
    string.chars.each_with_object([]) do |char, letters|
      SCORES[char] ? letters << char : letters[-1] << char
    end.map { |letter| new letter }
  end

  def initialize letter
    @letter = letter
  end

  def score
    letter_score * multiplier
  end

  private

    def letter_score
      SCORES[@letter.chr]
    end

    def multiplier
      return 0 if @letter.end_with?('^')
      return 3 if @letter.end_with?('**')
      return 2 if @letter.end_with?('*')
      return 1
    end
end

class ScrabbleWord
  DOUBLE_WORD_TOKEN = '(d)'.freeze
  TRIPLE_WORD_TOKEN = '(t)'.freeze

  def initialize word
    @word = word
  end

  def score
    letters_score * multiplier + length_bonus
  end

  private

    def letters_score
      letters.map(&:score).reduce(:+)
    end

    def multiplier
      return 2 if @word.end_with?(DOUBLE_WORD_TOKEN)
      return 3 if @word.end_with?(TRIPLE_WORD_TOKEN)
      return 1
    end

    def length_bonus
      letters.count == 7 ? 50 : 0
    end

    def letters
      ScrabbleLetter.parse word_without_multiplier
    end

    def word_without_multiplier
      @word
        .gsub(DOUBLE_WORD_TOKEN, "")
        .gsub(TRIPLE_WORD_TOKEN, "")
    end
end

class ScrabbleWordTest < MiniTest::Test
  def test_simple_word
    assert_equal 23, ScrabbleWord.new("quintessential").score
  end

  def test_double_and_triple_letters
    assert_equal 11, ScrabbleWord.new("he*llo**").score
  end

  def test_triple_word
    assert_equal 69, ScrabbleWord.new("quintessential(t)").score
  end

  def test_blank_tile_with_triple_word
    assert_equal 39, ScrabbleWord.new("q^uintessential(t)").score
  end

  def test_double_and_triple_letters_with_double_word
    assert_equal 22, ScrabbleWord.new("he*llo**(d)").score
  end

  def test_blank_tile_with_double_letter_and_double_word
    assert_equal 18, ScrabbleWord.new("he^llo**(d)").score
  end

  def test_seven_letter_word_bonus
    assert_equal 72, ScrabbleWord.new("wordier(d)").score
  end
end

I borrowed your tests, @yzhernand . Thank you for writing them, so I didn't have to.