diff --git a/lib/player.rb b/lib/player.rb new file mode 100644 index 00000000..05c8d207 --- /dev/null +++ b/lib/player.rb @@ -0,0 +1,50 @@ +require_relative "scoring" + +# The constructor for Scrabble::Player should take exactly one argument: the player's name. Instances of the class should respond to the following messages: +# +# #play(word): Adds the input word to the plays Array +# Returns false if player has already won +# Otherwise returns the score of the word + +# #total_score: Returns the sum of scores of played words +# #won?: If the player has over 100 points, returns true, otherwise returns false +# #highest_scoring_word: Returns the highest scoring played word +# #highest_word_score: Returns the highest_scoring_word score +require 'minitest/autorun' +require 'minitest/reporters' + + +module Scrabble + class Player + + attr_accessor :name, :plays, :total_score, :tiles + + def initialize(name) + @name = name + # #name: returns the value of the @name instance variable + @plays = [] + # #plays: returns an Array of the words played by the player + @total_score = 0 + @tiles=[] + + end + + def winner + return @total_score > 100 + end + + def play(word) + if winner == false + @plays << word + @total_score += Scoring.score(word) + else + return false + end + end + + + + + + end +end diff --git a/lib/scoring.rb b/lib/scoring.rb index fb3a3f2d..462669e3 100644 --- a/lib/scoring.rb +++ b/lib/scoring.rb @@ -1,9 +1,81 @@ + +LETTER_VALUES = { + "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 +} + module Scrabble class Scoring + def self.score(word) + + word = word.upcase + letters = word.split("") + character_check = LETTER_VALUES.keys + values_of_letters = [] + + letters.each do |character| + + # Checking if character input is a valid letter or not + # First part is splitting the hash into an array of the + # key values 'A-Z' and then we are checking if any characters + # are outside that range (This includes blank or nothing). + # If so, automatically return nil + # + # Else, if all the characters are valid letters, take the value + # associated with the key and put that in an array of integers + + + if !character_check.include?(character) || letters.length == 0 || letters.length > 7 + return nil + + else + values_of_letters << LETTER_VALUES.fetch(character) + + end + end + + score = values_of_letters.sum + + return letters.length == 7 ? score + 50 : score + end def self.highest_score_from(array_of_words) + + all_scores = {} + + return nil if array_of_words.length == 0 + + if array_of_words.length == 1 + winning_word = array_of_words.first + + elsif array_of_words.length > 1 + array_of_words.each do |word| + all_scores[word] = score(word) + + max_score_words = all_scores.delete_if { |word, score| score != all_scores.values.max }.keys + + if max_score_words.any? { |word| word.length == 7 } + winning_word = max_score_words.max_by(&:length) + + elsif max_score_words.all? { |word| word.length == word.length } + winning_word = max_score_words[0] + + else + winning_word = max_score_words.min_by(&:length) + + end + end + + return winning_word + + end end end end diff --git a/lib/tilebag.rb b/lib/tilebag.rb new file mode 100644 index 00000000..9bca2b70 --- /dev/null +++ b/lib/tilebag.rb @@ -0,0 +1,52 @@ +module Scrabble + class TileBag + #player can see letters + attr_reader :letter_quantity + + + # Creating an instance of letter quantity to be used though class tilebag. + def initialize + @default_set = {A:9, B:2, C:2, D:4, E:12, F:2, G:3, H:2, I:9, J:1, K:1, L:4, M:2, N:6, O:8, P:2, Q:1, R:6, S:4, T:6, U:4, V:2, W:2, X:1, Y:2, Z:1} + end + + # Define tiles remaining method to be used in the method for drawing the tiles. + def tiles_remaining + # still not sure why or how this is working. TODO: may take out later + total_num_tiles = @default_set.inject(0) { |letter, letter_quantity| letter += letter_quantity[1] } + p "++++TEST++++" + p total_num_tiles + return total_num_tiles + end + # Define draw tiles, put the tiles into array. + def draw_tiles(num) + player_hand = [] + # array will return tiles to player. Needs much refactoring. + return nil if num > tiles_remaining + #to account for test, returns nil if more tiles are drawn than tiles remain. + while player_hand.length != num + new_tile = rand(@default_set.size) + starting_hand = 0 + + @default_set.each do |letter, letter_quantity| + #Need to continue working on, this is becoming harder to read. TODO: REFACTOR! + # if the amount of tiles drawn(starting at 0) is the same as the amount of new tiles drawn, + if starting_hand == new_tile && letter_quantity != 0 + #if the condition above, and the total tiles isnt 0, add the new tile (letter), to all of the tiles (player_hand array) + # if letter_quantity != 0 + player_hand << letter + #Then subtract the letter from the tilebag, reducing the total amount of tiles by 1, and reducing the letter by one specifically from the letters. + @default_set[letter] = letter_quantity - 1 + else + new_tile = rand(@default_set.size) + + end + #increases the amount of tiles had by player plus one, each time a tile is drawn + starting_hand += 1 + end + end + #returns array of all tiles to player + return player_hand + end + + end +end diff --git a/specs/player_spec.rb b/specs/player_spec.rb new file mode 100644 index 00000000..20f137ad --- /dev/null +++ b/specs/player_spec.rb @@ -0,0 +1,32 @@ +require 'minitest/autorun' +require 'minitest/reporters' +require 'minitest/skip_dsl' + +require_relative '../lib/player' + +describe 'player' do + before do + @player = Scrabble::Player.new("Maddie") + end + + describe "initialize" do + + it "must be an instance of player class" do + @player.must_be_instance_of Scrabble::Player + end + + it "must returns the value of the @name instance variable" do + @player.name.must_equal "Maddie" + end + + describe "plays" do +#TODO: Need to test for 100 points.. + it "must return an array" do + @player.plays.must_be_kind_of Array + end +end + + + + end +end diff --git a/specs/scoring_spec.rb b/specs/scoring_spec.rb index ab498929..7d289e0b 100644 --- a/specs/scoring_spec.rb +++ b/specs/scoring_spec.rb @@ -9,54 +9,66 @@ describe 'Scoring' do describe 'score' do - it 'correctly scores simple words' do + xit 'correctly scores simple words' do Scrabble::Scoring.score('dog').must_equal 5 Scrabble::Scoring.score('cat').must_equal 5 Scrabble::Scoring.score('pig').must_equal 6 end - it 'adds 50 points for a 7-letter word' do + xit 'adds 50 points for a 7-letter word' do Scrabble::Scoring.score('academy').must_equal 65 end - it 'handles all upper- and lower-case letters' do + xit 'handles all upper- and lower-case letters' do Scrabble::Scoring.score('dog').must_equal 5 Scrabble::Scoring.score('DOG').must_equal 5 Scrabble::Scoring.score('DoG').must_equal 5 end - it 'returns nil for strings containing bad characters' do + xit '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 end - it 'returns nil for words > 7 letters' do + xit 'returns nil for words > 7 letters' do Scrabble::Scoring.score('abcdefgh').must_be_nil end - it 'returns nil for empty words' do + xit 'returns nil for empty words' do Scrabble::Scoring.score('').must_be_nil end end describe 'highest_score_from' do it 'returns nil if no words were passed' do + array_of_words = [] + Scrabble::Scoring.highest_score_from(array_of_words).must_be_nil end it 'returns the only word in a length-1 array' do + array_of_words = ['one'] + Scrabble::Scoring.highest_score_from(array_of_words).must_equal('one') end it 'returns the highest word if there are two words' do + array_of_words = ["zebra", "zebras"] + Scrabble::Scoring.highest_score_from(array_of_words).must_equal("zebras") end it 'if tied, prefer a word with 7 letters' do + array_of_words = ["ww", "bananas"] + Scrabble::Scoring.highest_score_from(array_of_words).must_equal("bananas") end it 'if tied and no word has 7 letters, prefers the word with fewer letters' do + array_of_words = ["x", "brasas"] + Scrabble::Scoring.highest_score_from(array_of_words).must_equal("x") end it 'returns the first word of a tie with same letter count' do + array_of_words = ["zebraa", "zebras"] + Scrabble::Scoring.highest_score_from(array_of_words).must_equal("zebraa") end end end diff --git a/specs/tilebag_spec.rb b/specs/tilebag_spec.rb new file mode 100644 index 00000000..635a61c3 --- /dev/null +++ b/specs/tilebag_spec.rb @@ -0,0 +1,41 @@ +require_relative '../lib/tilebag' +#With this, i wont have to retype scrabble::tilebag.new so many times. +describe "tilebag" do + before do + @tile_bag = Scrabble::TileBag.new + end + + describe "tile bag can be created/initialized" do + it "creates instance of tilebag with a collection of all tiles" do + @tile_bag.must_be_instance_of Scrabble::TileBag + end + end + #testing for edge cases of drawing tiles, like drawing more than are in the tilebag, or drawing no tiles. + describe "draw tiles" do + it "returns nil if input is more than tiles in tilebag" do + @tile_bag.draw_tiles(50000).must_be_nil true + end + #in between case + # Making sure drawn tiles will be returned to player + it "returns tiles to user in array" do + @tile_bag.draw_tiles(5).must_be_kind_of Array + end + # Testing for an edge case. + it "returns an empty array of tiles to user" do + @tile_bag.draw_tiles(0).must_be_empty Array + end + end + + describe "tiles left in tilebag" do + it "takes a tile away from total letter quantity and returns num of remaining + tiles in tilebag" do + @tile_bag.draw_tiles(7) + @tile_bag.tiles_remaining.must_equal 91 + end + it "returns the total letter quantity when no tile(s) is drawn" do + @tile_bag.draw_tiles(0) + @tile_bag.tiles_remaining.must_equal 98 + # Wont need to test for edge case if all the tiles are drawn with return of 0, because we already did this in previous draw tile test. + end +end +end diff --git a/wave-1-game.rb b/wave-1-game.rb index da13d000..416a0135 100644 --- a/wave-1-game.rb +++ b/wave-1-game.rb @@ -44,7 +44,7 @@ def print_score(word) end def conclude - highest_word = Scrabble::Scoring.highest_score_from_array(@words) + highest_word = Scrabble::Scoring.highest_score_from(@words) puts "The final highest scoring word is #{ highest_word }" end end