diff --git a/lib/player.rb b/lib/player.rb new file mode 100644 index 00000000..89653a62 --- /dev/null +++ b/lib/player.rb @@ -0,0 +1,73 @@ +require_relative '../lib/tilebag' + + +module Scrabble + class Player + + attr_reader :name, :player_score, :plays, :tiles + + def initialize(player_name) + @name = player_name + @player_score = 0 #This is total_score + @plays = [] + @tiles = [] + end + + + def play(word) + if @player_score > 100 + return false + end + + @plays << word + + score = Scrabble::Scoring.score(word) + @player_score += score.to_i + + return score + end + + def won? + @player_score > 100 ? true : false + end + + def highest_scoring_word + + highest_scoring_words = [] + max = 0 + + @plays.each do |word| + score = Scrabble::Scoring.score(word) + if score.to_i > max + highest_scoring_words << word + max = score + end + end + return highest_scoring_words[-1] + + end + + def highest_word_score + max = 0 + + @plays.each do |word| + score = Scrabble::Scoring.score(word) + if score.to_i > max + max = score + end + end + return max + end + + + def draw_tiles(tile_bag) + + until @tiles.length == 7 + new_tile = tile_bag.draw_tiles(1) + @tiles << new_tile + end + + end + + end +end diff --git a/lib/scoring.rb b/lib/scoring.rb index fb3a3f2d..e83eed5e 100644 --- a/lib/scoring.rb +++ b/lib/scoring.rb @@ -1,9 +1,72 @@ module Scrabble class Scoring + def self.score(word) + if word =~ /[\W]/ || word =~ /[\s+]/ || word == "" || word =~ /.{8,}$/ + return nil + elsif word.length == 7 + total_score = 50 + else + total_score = 0 + end + + letters_groups = [/[AaEeIiOoUuLlNnRrSsTt]/, /[DdGg]/, /[BbCcMmPp]/, /[FfHhVvWwYy]/, /[Kk]/, /[JjXx]/, /[QqZz]/] + point_options = [1, 2, 3, 4, 5, 8, 10] + letters_groups.each_with_index do |group, index| + matches = [] + + matches = word.scan(group) + + score = matches.length * point_options[index] + total_score += score + end + return total_score end + # # WE WANTED TO CREATE A METHOD THAT RETURNED ALL OF THE WORDS WITH THE HIGHEST SCORE RATHER THAN THE FIRST OCCURANCE. + def self.highest_score_from(array_of_words) + return nil if array_of_words.empty? + array_of_scores = [] + words_with_max = [] + array_of_words.each do |word| + array_of_scores << score(word) + end + + # # .max on array_of_scores if we want just one, no duplicates + # # Maybe we could do array_of_scores.rindex(array_of_scores.max) which would return the index for the max score which is equal to the index for the corresponding word in array_of_words + + array_of_scores.each_with_index do |score, index| + if score == array_of_scores.max + words_with_max << array_of_words[index] + end + end + + if words_with_max.length > 1 + + # # .Sort on lengths for words_with_max + # # But if we do refactoring mentioned above, words_with_max won't be created + # # Could possibly do .length on array_of_words[index from array of scores] + + words_with_max.each {|word| return word if word.length == 7} + + least_letters = [] + start_value = words_with_max[0].length + least_letters << words_with_max[0] + + words_with_max.each do |word| + if word == words_with_max[0] + next + else + if start_value > word.length + least_letters << word + end + end + end + return least_letters[-1] + end + + return words_with_max[0] end end end diff --git a/lib/tilebag.rb b/lib/tilebag.rb new file mode 100644 index 00000000..053ebfc5 --- /dev/null +++ b/lib/tilebag.rb @@ -0,0 +1,41 @@ +module Scrabble + class Tilebag + + TILE_BAG_LETTERS = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", + "T", "U", "V", "W", "X", "Y", "Z"] + + TILE_BAG_COUNT = [9, 2, 2, 4, 12, 2, 3, 2, 9, 1, 1, 4, 2, 6, 8, 2, 1, 6, 4, 6, 4, 2, 1, 2, 1] + + attr_reader :bag, :tiles_remaining + + def initialize + @bag = [] + TILE_BAG_COUNT.each_with_index do |count, index| + count.times do + tile = TILE_BAG_LETTERS[index] + @bag << tile + end + end + + @tiles_remaining = 96 + + end + + def draw_tiles(num) + + if @tiles_remaining >= num + @tiles_remaining -= num + picked_tiles = @bag.sample(num) + + picked_tiles.each do |tile| + @bag.delete_at(@bag.index(tile)) + end + + return picked_tiles + end + + return nil + end + + end +end diff --git a/specs/player_spec.rb b/specs/player_spec.rb new file mode 100644 index 00000000..2f956d55 --- /dev/null +++ b/specs/player_spec.rb @@ -0,0 +1,247 @@ +require 'minitest/autorun' +require 'minitest/reporters' +require 'minitest/skip_dsl' + +require_relative '../lib/player' +require_relative '../lib/tilebag' + +# Get that nice colorized output +Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new + +describe 'Player' do + describe 'initialize' do + it 'takes a player_name' do + player_name = "Ari" + + player = Scrabble::Player.new(player_name) + + player.must_respond_to :name + player.name.must_equal "Ari" + player.name.must_be_kind_of String + end + + it 'saves other instance variables' do + player_name = "Ari" + + player = Scrabble::Player.new(player_name) + + player.player_score.must_equal 0 + player.plays.must_be_kind_of Array + player.plays.empty?.must_equal true + player.tiles.must_be_kind_of Array + player.tiles.empty?.must_equal true + end + end + + describe 'play' do + it 'returns the score of a valid word' do + player = Scrabble::Player.new("Ari") + + player.play('dog').must_equal 5 + player.play('academy').must_equal 65 + end + + it 'returns nil for an invalid word' do + player = Scrabble::Player.new("Ari") + player.play('char^').must_be_nil + player.play(' ').must_be_nil + end + + it 'continues to play if the player has 100 points' do + player = Scrabble::Player.new("Ari") + # pass words to .play to reach @total_score = 100 + player.play('squeeze') + player.play('happy') + player.play('purple') + player.player_score.must_equal 100 + player.play('dog').must_equal 5 + end + + it 'returns false if the player has < 100 points' do + player = Scrabble::Player.new("Ari") + # pass word to .play to reach @total_score < 10 + player.play('cat') + player.play('dog').must_equal 5 + end + + it 'returns score if the player > 100 points' do + player = Scrabble::Player.new("Ari") + # pass word to .play to reach @total_score > 100 + player.play('squeeze') + player.play('quezals') + player.play('squiffy') + player.play('zombify') + player.play('dog').must_equal false + end + end + + describe 'words in plays array' do + it 'adds the word to plays array' do + player = Scrabble::Player.new("Ari") + player.play('dog') + player.plays.must_equal ["dog"] + end + + it 'keeps track of all words in plays array' do + player = Scrabble::Player.new("Ari") + player.play('cat') + player.play('mouse') + player.play('dog') + player.plays.must_equal ["cat", "mouse", "dog"] + end + + it 'returns plays even when word is invalid' do + player = Scrabble::Player.new("Ari") + player.play('oxyphenbutazone') + player.plays.must_equal ['oxyphenbutazone'] + end + end + +# testing the players score + describe 'running score as player_score' do + it 'calculates score with one play' do + player = Scrabble::Player.new("Ari") + player.play('cat') + player.player_score.must_equal 5 + end + + it 'calculates score with multiple plays' do + player = Scrabble::Player.new("Ari") + player.play('cat') + player.play('mouse') + player.play('dog') + player.player_score.must_equal 17 + end + + it 'provides score even when word is invalid' do + player = Scrabble::Player.new("Ari") + player.play('mouse') + player.play('oxyphenbutazone') + player.player_score.must_equal 7 + end + + it 'provides 0 even when word is invalid' do + player = Scrabble::Player.new("Ari") + player.play('oxyphenbutazone') + player.player_score.must_equal 0 + end + end + + describe 'winning' do + it 'returns true if the player has > 100 points' do + player = Scrabble::Player.new("Ari") + + player.play('squeeze') + player.play('quezals') + player.play('squiffy') + player.play('zombify') + player.won?.must_equal true + end + + it 'returns false if the player has < 100 points' do + player = Scrabble::Player.new("Ari") + + player.play('cat') + player.play('dog') + player.won?.must_equal false + end + + it 'returns false if the player has 100 points' do + player = Scrabble::Player.new("Ari") + + player.play('squeeze') + player.play('happy') + player.play('purple') + player.won?.must_equal false + end + + it 'returns false if the player has very few points' do + player = Scrabble::Player.new("Ari") + + player.play('an') + player.won?.must_equal false + end + end + + describe 'highest scoring word' do + it 'returns the highest scoring word with one word' do + player = Scrabble::Player.new("Ari") + player.play('cat') + player.highest_scoring_word.must_equal 'cat' + end + it 'returns the highest scoring word with multiple words' do + player = Scrabble::Player.new("Ari") + player.play('cat') + player.play('mouse') + player.play('dog') + player.highest_scoring_word.must_equal "mouse" + + end + it 'returns the highest scoring word with no valid words' do + player = Scrabble::Player.new("Ari") + player.play('oxyphenbutazone') + player.highest_scoring_word.must_equal nil + end + end + + describe 'highest word score' do + it 'returns score from the highest scoring word with one word' do + player = Scrabble::Player.new("Ari") + player.play('cat') + player.highest_word_score.must_equal 5 + + end + + it 'returns score from the highest scoring word with multiple words' do + player = Scrabble::Player.new("Ari") + player.play('cat') + player.play('mouse') + player.play('dog') + player.highest_word_score.must_equal 7 + + end + + it 'returns score from the highest scoring word with no valid words' do + player = Scrabble::Player.new("Ari") + player.play('oxyphenbutazone') + player.highest_word_score.must_equal 0 + end + end + + describe 'draw_tiles function to get player tiles' do + it 'confirms the player gets 7 tiles to start' do + our_bag = Scrabble::Tilebag.new + player = Scrabble::Player.new("Ari") + player.tiles.length.must_equal 0 + player.draw_tiles(our_bag) + player.tiles.length.must_equal 7 + end + + it 'confirms the player gets no more than 7 times' do + our_bag = Scrabble::Tilebag.new + player = Scrabble::Player.new("Ari") + # first draw + player.draw_tiles(our_bag) + # second draw + player.draw_tiles(our_bag) + player.tiles.length.must_equal 7 + end + + it 'confirms the player gets extra tiles with small amount in hand' do + our_bag = Scrabble::Tilebag.new + player = Scrabble::Player.new("Ari") + player.tiles.length == 1 + player.draw_tiles(our_bag) + player.tiles.length.must_equal 7 + end + + it 'confirms the player gets extra tiles with large amount in hand' do + our_bag = Scrabble::Tilebag.new + player = Scrabble::Player.new("Ari") + player.tiles.length == 5 + player.draw_tiles(our_bag) + player.tiles.length.must_equal 7 + end + + end +end diff --git a/specs/scoring_spec.rb b/specs/scoring_spec.rb index ab498929..68121802 100644 --- a/specs/scoring_spec.rb +++ b/specs/scoring_spec.rb @@ -26,13 +26,13 @@ end it 'returns nil for strings containing bad characters' do - Scrabble::Scoring.score('#$%^').must_be_nil - Scrabble::Scoring.score('char^').must_be_nil - Scrabble::Scoring.score(' ').must_be_nil + Scrabble::Scoring.score('#$%^').must_be_nil + Scrabble::Scoring.score('char^').must_be_nil + Scrabble::Scoring.score(' ').must_be_nil end it 'returns nil for words > 7 letters' do - Scrabble::Scoring.score('abcdefgh').must_be_nil + Scrabble::Scoring.score('oxyphenbutazone').must_be_nil end it 'returns nil for empty words' do @@ -42,21 +42,39 @@ describe 'highest_score_from' do it 'returns nil if no words were passed' do + array_of_words = [] + result = Scrabble::Scoring.highest_score_from(array_of_words) + result.must_be_nil end it 'returns the only word in a length-1 array' do + array_of_words = ["cat"] + result = Scrabble::Scoring.highest_score_from(array_of_words) + result.must_equal "cat" end it 'returns the highest word if there are two words' do + array_of_words = ["cat", "mouse"] + result = Scrabble::Scoring.highest_score_from(array_of_words) + result.must_equal "mouse" end it 'if tied, prefer a word with 7 letters' do + array_of_words = ["queazy", "puzzles"] + result = Scrabble::Scoring.highest_score_from(array_of_words) + result.must_equal "puzzles" end it 'if tied and no word has 7 letters, prefers the word with fewer letters' do + array_of_words = ["zippy", "jynx"] + result = Scrabble::Scoring.highest_score_from(array_of_words) + result.must_equal "jynx" end it 'returns the first word of a tie with same letter count' do + array_of_words = ["yak", "key"] + result = Scrabble::Scoring.highest_score_from(array_of_words) + result.must_equal "yak" end end end diff --git a/specs/tilebag_spec.rb b/specs/tilebag_spec.rb new file mode 100644 index 00000000..a90fbbc3 --- /dev/null +++ b/specs/tilebag_spec.rb @@ -0,0 +1,100 @@ +require 'minitest/autorun' +require 'minitest/reporters' +require 'minitest/skip_dsl' + +require_relative '../lib/tilebag' + +# Get that nice colorized output +Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new + + +describe 'Tilebag' do + describe 'initialize' do + it 'returns bag' do + + our_bag = Scrabble::Tilebag.new + our_bag.bag.must_be_kind_of Array + our_bag.bag.must_equal ["A", "A", "A", "A", "A", "A", "A", "A", "A", "B", "B", "C", "C", "D", "D", "D", "D", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "F", "F", "G", "G", "G", "H", "H", "I", "I", "I", "I", "I", "I", "I", "I", "I", "J", "K", "L", "L", "L", "L", "M", "M", "N", "N", "N", "N", "N", "N", "O", "O", "O", "O", "O", "O", "O", "O", "P", "P", "Q", "R", "R", "R", "R", "R", "R", "S", "S", "S", "S", "T", "T", "T", "T", "T", "T", "U", "U", "U", "U", "V", "V", "W", "X", "X", "Y"] + + end + + it 'returns remaining tiles' do + + our_bag = Scrabble::Tilebag.new + our_bag.tiles_remaining.must_equal 96 + + end + end + + describe 'draw_tiles' do + it 'returns nil if not enough tiles remain' do + our_bag = Scrabble::Tilebag.new + picked_tiles = our_bag.draw_tiles(100) + picked_tiles.must_be_nil + end + + it 'returns appropriate number of tiles when small number requested' do + our_bag = Scrabble::Tilebag.new + picked_tiles = our_bag.draw_tiles(3) + picked_tiles.must_be_kind_of Array + picked_tiles.length.must_equal 3 + end + + it 'returns appropriate number of tiles when large number requested' do + our_bag = Scrabble::Tilebag.new + picked_tiles = our_bag.draw_tiles(80) + picked_tiles.must_be_kind_of Array + picked_tiles.length.must_equal 80 + end + + it 'removes picked tiles from the bag with small number' do + our_bag = Scrabble::Tilebag.new + + our_bag.draw_tiles(3) + + our_bag.bag.length.must_equal 93 + end + + it 'removes picked tiles from the bag with small number' do + our_bag = Scrabble::Tilebag.new + + our_bag.draw_tiles(80) + + our_bag.bag.length.must_equal 16 + end + + # # AFTER STARTING THIS DRAFT WE LEARNED, THAT WE DON'T HAVE THE SKILLS TO COMPLETE THIS TEST-- OUR GOAL WAS TO CHECK THAT THE CORRECT TILES WERE REMOVED FROM THE BAG + + # it 'removes the appropriate tiles are removed the bag' do + # our_bag = Scrabble::Tilebag.new + # picked_tiles = our_bag.draw_tiles(10) + # + # counts = Hash.new 0 + # picked_tiles.each do |tile| + # counts[tile] += 1 + # end + # + # updated_bag = our_bag.bag + # + # array_of_key_value_pairs = counts.to_a + # + # counts_as_array_of_tiles = [] + # + # array_of_key_value_pairs.each do |key_value| + # key_value[1].times + # counts_as_array_of_tiles << key_value[0] + # end + # + # counts_as_array_of_tiles.each do |picked_letter| + # our_bag.bag.drop(1) if updated_bag.include?(picked_letter) + # end + # + # + # + # + # end + + + + end +end