diff --git a/README.md b/README.md index 7d949258..4e789e48 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ Create a `Scrabble::Scoring` class with a __minimum of 8 specs__. The class shou - There is a bonus for words that are seven letters. If the top score is tied between multiple words and one used all seven letters, choose the one with seven letters over the one with fewer tiles. - If the there are multiple words that are the same score and same length, pick the first one in the supplied list. - diff --git a/Rakefile b/Rakefile new file mode 100644 index 00000000..82e5a661 --- /dev/null +++ b/Rakefile @@ -0,0 +1,7 @@ +require 'rake/testtask' + +Rake::TestTask.new do |t| + t.test_files = FileList['specs/*_spec.rb'] + end + +task default: :test diff --git a/lib/player.rb b/lib/player.rb new file mode 100644 index 00000000..7fa1728d --- /dev/null +++ b/lib/player.rb @@ -0,0 +1,76 @@ +require_relative "scoring" + +module Scrabble + class Player + + attr_reader :name, :winner, :words_played, :tile_tray + + def initialize(name) + @name = name + @words_played = [] + @winner = false + @tile_tray = [] + end + + def plays + return @words_played + end + + def play(word) + raise ArgumentError.new("Invalid word") if word.upcase[/[A-Z]+/] != word.upcase + if @winner == true + return false + end + word_score = Scoring.score(word) #return score + @words_played << word # dont forget this adds to instance variable every time it runs + + return word_score + end + + def total_score + player_score = 0 + plays.each do |word| + current_score = Scoring.score(word) + player_score += current_score + end + return player_score + end + + def won? + if total_score > 100 + return true + else + return false + end + end #end won? method + + def highest_scoring_word + best_word = Scoring.highest_score_from(plays) + return best_word + end + + def highest_word_score + best_score = Scoring.score(highest_scoring_word) + return best_score + end + + def tiles + return @tile_tray + end + + def draw_tiles(tile_bag) + begin + result = tile_bag.draw_tiles(1) + @tile_tray << result + end until @tile_tray.length == 7 + return @tile_tray + + end # @todo finish this method + + end + + + + + +end diff --git a/lib/scoring.rb b/lib/scoring.rb new file mode 100644 index 00000000..5cfb55f6 --- /dev/null +++ b/lib/scoring.rb @@ -0,0 +1,92 @@ +# @todo fix error for empty word +module Scrabble + + class Scoring + + TILES = { + "A" => 1, + "E" => 1, + "I" => 1, + "O" => 1, + "U" => 1, + "L" => 1, + "N" => 1, + "R" => 1, + "S" => 1, + "T" => 1, + "D" => 2, + "G" => 2, + "B" => 3, + "C" => 3, + "M" => 3, + "P" => 3, + "F" => 4, + "H" => 4, + "V" => 4, + "W" => 4, + "Y" => 4, + "K" => 5, + "J" => 8, + "X" => 8, + "Q" => 10, + "Z" => 10 + } + SEVEN_LETTER_BONUS = 50 + + attr_reader :word + + def initialize(word) + @word = word + + + end + + def self.score(word) #won't raise error for '' whyyyy + invalid_words = word.upcase[/[^A-Z]/] + current_word = word.upcase + + raise ArgumentError.new("Invalid word") if + invalid_words == current_word + score = 0 + word_array = word.upcase.split(//) + word_array.each do |letter| + score += Scrabble::Scoring::TILES[letter] + end + if word_array.length !=7 + return score + else + + return score += SEVEN_LETTER_BONUS + end + end + + def self.highest_score_from(array_of_words) + max_score = 0 + max_words = [] + winning_word = 'PIZZAZZas' + array_of_words.each do |word| + current_score = score(word) + if current_score == max_score + max_words << word + elsif current_score > max_score + max_words = [word] + max_score = current_score + else + #karion + end + end #each + max_words.each do |word| + if word.length < winning_word.length + winning_word = word + elsif word.length == 7 + winning_word = word + return winning_word + else + # karion + end + end + return winning_word # will return the first if tie breaker + end + end + +end diff --git a/lib/tile_bag.rb b/lib/tile_bag.rb new file mode 100644 index 00000000..7ce4b9a7 --- /dev/null +++ b/lib/tile_bag.rb @@ -0,0 +1,64 @@ +module Scrabble + class TileBag + + TILES_BAG = { + "A" => 9, + "E" => 1, + "I" => 9, + "O" => 8, + "U" => 4, + "L" => 4, + "N" => 6, + "R" => 6, + "S" => 4, + "T" => 6, + "D" => 4, + "G" => 3, + "B" => 2, + "C" => 2, + "M" => 2, + "P" => 2, + "F" => 2, + "H" => 2, + "V" => 2, + "W" => 2, + "Y" => 2, + "K" => 1, + "J" => 1, + "X" => 1, + "Q" => 1, + "Z" => 1 + } + + attr_reader :game_tile_bag + + def initialize + @game_tile_bag = TILES_BAG.clone + + end + + def draw_tiles(num) + sum_of_all_tiles = @game_tile_bag.values.reduce(:+) + if sum_of_all_tiles < num + raise Exception.new("Cannot draw more tiles than currently in bag.") + end + new_player_tiles = 0 + alphabet_array = [] + @game_tile_bag.map do |key, value| + value.times do + alphabet_array << key + # =>["A", "A", "A", "F", "F", "G"] + end + end + + new_player_tiles = alphabet_array.sample(num) #array of drawn letters + new_player_tiles.each do |letter| + @game_tile_bag[letter] -= 1 + end + return new_player_tiles #array of letters + end #draw_tiles + + + + end +end diff --git a/specs/player_spec.rb b/specs/player_spec.rb new file mode 100644 index 00000000..91f70e99 --- /dev/null +++ b/specs/player_spec.rb @@ -0,0 +1,125 @@ +require_relative "../lib/player.rb" +require_relative 'spec_helper' +module Scrabble + + describe Player do + describe "#initialize" do + let(:player) { Player.new(:name) } + + it "can create an instance of Player" do + player.must_be_instance_of(Player) + end + + it "must respond to name attribute" do + player.must_respond_to(:name) + end + + end + + describe "#plays" do + let(:player) { Player.new(:name) } + it "should return an array" do + player.plays.must_be_instance_of(Array) + end + + it "should return an array of words/string" do + player.plays.each{|word| word.must_be_instance_of(String)} + end + end + + describe "#play(word)" do + let(:player) { Player.new("Alma") } + + it "should raise an error if word is not provided at all" do + proc{player.play('')}.must_raise(ArgumentError) + + end + + it "should append words to @words_played" do + player.play("dog") + player.play("foot") + "dog".must_equal(player.plays.first) + "foot".must_equal(player.plays.last) + end + + it "method returns the score of a word from Scoring" do + player.play("imposter").must_equal(12) + end + end #play(word) + + describe "#total_score" do + let(:player) { Player.new("Alma") } + + it "should check total score from plays array" do + player.play("dog") #returns score = 5 + player.play("foot") #returns => 7 + player.play("coffee") #returns => 14 + player.total_score.must_equal(26) + end + + end #end describe total score + + describe "#won?" do + let(:player) { Player.new("Alma") } + + it "should return true if total player score is greater than 100" do + player.play("pizzazz") + player.play("coffee") + player.total_score #will return sum + player.won?.must_equal(true) + end + end #end won? method + + describe "#highest_scoring_word" do + let(:player) { Player.new("Alma") } + + it "should return the highest scoring word player played" do + player.play("pizzazz") + player.play("coffee") + player.highest_scoring_word.must_equal("pizzazz") + end + end #end highest scoring word method + + describe "#highest_word_score" do + let(:player) { Player.new("Alma") } + + it "should return the score of the highest scoring word player played" do + player.play("pizzazz") + player.play("coffee") + player.highest_word_score.must_equal(95) + end + end + + describe "#tiles" do + let(:player) { Player.new("Alma") } + + it "should return an array of letters" do + player.tiles.must_be_instance_of(Array) + end + + it "should limit the tray to a max of 7" do + player.tiles.length.must_be(:<=, 7) + end + end + + describe "#draw_tiles(tile_bag)" do + let(:player) { Player.new("Alma") } + it "should draw tiles until tray has 7 tiles" do + player.draw_tiles(TileBag.new) + player.tile_tray.length.must_equal(7) + end + end + end + + + + + # + # it "should not allow player to draw more tiles than tray_max" do + # + # end + # player need to care about their own tray + + + +end diff --git a/specs/scoring_spec.rb b/specs/scoring_spec.rb new file mode 100644 index 00000000..0487d103 --- /dev/null +++ b/specs/scoring_spec.rb @@ -0,0 +1,53 @@ +require_relative "../lib/scoring.rb" +require_relative 'spec_helper' +module Scrabble +describe Scoring do + + describe "#initialize" do + let(:scoring) {Scoring.new(:word) } + + it "can create an instance of Scoring" do + scoring.must_be_instance_of(Scoring) + end + + it "has a word attribute" do + scoring.must_respond_to(:word) + end + end + + describe "#self.score(word)" do + it "should raise an error when tile is invalid" do + proc { Scoring.score('3') }.must_raise(ArgumentError) + proc { Scoring.score(' ') }.must_raise(ArgumentError) + end + it "method will return a fixnum" do + Scoring.score("string").must_be_instance_of(Fixnum) + end + + it "must add up values of letters in word correctly" do + Scoring.score("STRING").must_equal(7) + end + + it "must add 50 points to score for seven-letter-words" do + Scoring.score("PIZZAZZ").must_equal(95) + end + end + + describe "#self.highest_score_from(array_of_words)" do + + it "method will return a string" do + Scoring.highest_score_from(["xena", "toy", "dog"]).must_be_instance_of(String) + end + #Tiebreaker tests + it "will return the shortest word within an array of equal scored words" do + Scoring.highest_score_from(["gels", "cat", "long"]).must_equal("cat") + end + + it "will return the word with the highest score and length of 7 in an an array" do + Scoring.highest_score_from(["qzqzqz", "aaaaaah"]).must_equal("aaaaaah") + end + + end + +end +end diff --git a/specs/spec_helper.rb b/specs/spec_helper.rb new file mode 100644 index 00000000..3f5ec15b --- /dev/null +++ b/specs/spec_helper.rb @@ -0,0 +1,9 @@ +require 'simplecov' +SimpleCov.start +require 'minitest' +require 'minitest/spec' +require "minitest/autorun" +require "minitest/reporters" +require 'minitest/pride' + +Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new diff --git a/specs/tile_bag_spec.rb b/specs/tile_bag_spec.rb new file mode 100644 index 00000000..918a0525 --- /dev/null +++ b/specs/tile_bag_spec.rb @@ -0,0 +1,44 @@ +require_relative "../lib/tile_bag.rb" +require_relative 'spec_helper' +module Scrabble + describe TileBag do + + #describe "#initialize" do + let(:tile_bag) { TileBag.new } + + it "can create an instance of TileBag" do + tile_bag.must_be_instance_of(TileBag) + end + + #end + + describe "#draw_tiles(num)" do + let(:tile_bag) { TileBag.new } + + it "should return an array" do + tile_bag.draw_tiles(1).must_be_kind_of(Array) + end + + it "should return an array of length equal to num" do + tile_bag.draw_tiles(2).length.must_equal(2) + end + + it "should remove tiles from the game_tile_bag" do + current_letters = (tile_bag.game_tile_bag).clone + test_tile_array = tile_bag.draw_tiles(2) #array of letters + test_tile_array.each do |tile_letter| + number_of_letters_available = tile_bag.game_tile_bag[tile_letter] + current_letters[tile_letter].wont_equal(number_of_letters_available) + end + end + + it "should return an error if withdrawing more tiles than available in bag" do + error_tile_bag = TileBag.new + error_tile_bag.draw_tiles(87) + proc {error_tile_bag.draw_tiles(1)}.must_raise(Exception) + end + end + + + end +end