diff --git a/.ruby-gemset b/.ruby-gemset new file mode 100644 index 00000000..b0582e1f --- /dev/null +++ b/.ruby-gemset @@ -0,0 +1 @@ +Scrabble diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 00000000..276cbf9e --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +2.3.0 diff --git a/Rakefile b/Rakefile new file mode 100644 index 00000000..deb52f2c --- /dev/null +++ b/Rakefile @@ -0,0 +1,9 @@ +require 'rake/testtask' + +Rake::TestTask.new do |t| + t.libs = ["lib"] + t.warning = true + 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..c7858e0a --- /dev/null +++ b/lib/player.rb @@ -0,0 +1,78 @@ +class Player +attr_accessor :name, :words_played, :tiles + def initialize (name) + @name = name + @words_played = [] + @tiles = [] + end + + + def plays + return @words_played + end + + # def have_letters? #WE WERE GOING TO DO THIS BUT DIDNT FINISH YET: NOT IN REQUIREMENTS ^_^ + + # word_letters = @word_played.split("") + # temp_tiles = @tiles + + # word_letters.each do |letter| #this checks to be sure we have the letters that are in the word we are trying to play + # if temp_tiles.include?(letter) + # temp_tiles.delete_at(tiles.index(letter) || tiles.length) + # else + # return false + # end + # end + # @tiles = temp_tiles + # return true + # end + + + + def play(word) + if won? == true + return false + end + + @words_played << word + return Scoring.score(word) + end + + + def total_score + sum_of_scores = 0 + @words_played.each do |word| + sum_of_scores = sum_of_scores + Scoring.score(word) + end + return sum_of_scores + end + + + def won? + if total_score > 100 + return true + else + return false + end + end + + + def highest_scoring_word + winner_word = Scoring.highest_score_from(@words_played) + return winner_word + end + + + def highest_word_score + winner_score = Scoring.score(Scoring.highest_score_from(@words_played)) + return winner_score + end + + + def draw_tiles(tile_bag) + x = 7 - @tiles.length + @tiles.concat(tile_bag.draw_tiles(x)) + end + + +end diff --git a/lib/scoring.rb b/lib/scoring.rb new file mode 100644 index 00000000..00521a22 --- /dev/null +++ b/lib/scoring.rb @@ -0,0 +1,56 @@ +class Scoring + LETTER_VALUE = { "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 + } + + def self.score(word) #this is going to find the total value of the word.... self. bc its a method of the class, not an instance (the numbers are always the same for the letters) + total = 0 #defining total (variable) as zero for now + word.upcase.each_char do |key| #turning the word into upcase and iterating through each character(letter) of the word + total = total + LETTER_VALUE[key] #tally the total sum of the value of those letters, when we call [key] on LETTER_VALUE it will give us the value of that key and add it to our total + end + word.length == 7 ? total + 50 : total #Return is implicit #if the word's length is 7 then we add 50 to our total/ this is an ternary!!! + end + + + + def self.highest_score_from(array) + hash ={} #this hash will contain words and their values/scores + + array.each do |word| #iterating through words given and assigning the score (through the score method) to the word + hash[word] = score(word) + end + + array_values = hash.values #this is taking the values of the hash and storing them in an array + + max_value = array_values.max #this is finding the max value of the values and storing as a variable + + array_tie = [] + + hash.each do |key, value| #iterating through the hash and if the value of the word is equal to the max_value + if value ==max_value #it pushes that corresponding word into an array for the ties + array_tie << key + end + end + + min = array_tie[0].length #we are setting the minimum by default to the length of the first word in the array + winner = array_tie[0] #we are setting the winner by default to the first word + + array_tie.each do |word| #iterating through the tie array and checking if the current word's length is less than the minimum + if word.length == 7 #add conditional so that if the word is 7 letters long, it is automatically the winner + return word #return the word and exit + end + if word.length < min + min = word.length #if it is, set it's length as the new min value + winner = word #set the corresponding word as the current winner (which might change the next iteration though) + end + end + + return winner + + end +end diff --git a/lib/tilebag.rb b/lib/tilebag.rb new file mode 100644 index 00000000..d315f9e5 --- /dev/null +++ b/lib/tilebag.rb @@ -0,0 +1,57 @@ +class Tilebag + attr_accessor :tiles_in_bag + def initialize + @tiles_in_bag = {"A" => 9, "N" => 6, + "B" => 2, "O" => 8, + "C" => 2, "P" => 2, + "D" => 4, "Q" => 1, + "E" => 12, "R" => 6, + "F" => 2, "S" => 4, + "G" => 3, "T" => 6, + "H" => 2, "U" => 4, + "I" => 9, "V" => 2, + "J" => 1, "W" => 2, + "K" => 1, "X" => 1, + "L" => 4, "Y" => 2, + "M" => 2, "Z" => 1} + end + + + def draw_tiles(num) + #Build new array to consider all available letters to sample from + + #Raise an error if num is larger than 7??? + + array = [] + @tiles_in_bag.each do |key, value| + array << (key * value).split("") + array.flatten! + end + + + tiles_to_draw = array.sample(num) + + tiles_to_draw.each do |letter| + @tiles_in_bag[letter] = @tiles_in_bag[letter] - 1 + end + + @tiles_in_bag.delete_if {|key, value| value < 1 } + + return tiles_to_draw + + end + + + def tiles_remaining + array = [] + @tiles_in_bag.each do |key, value| + array << (key * value).split("") + array.flatten! + end + + return array.length + end + + + +end diff --git a/scrabble.rb b/scrabble.rb new file mode 100644 index 00000000..36102831 --- /dev/null +++ b/scrabble.rb @@ -0,0 +1,8 @@ +module Scrabble + + #require the class Scoring from scoring.rb + require_relative './lib/scoring.rb' + require_relative './lib/player.rb' + require_relative './lib/tilebag.rb' + +end diff --git a/specs/player_spec.rb b/specs/player_spec.rb new file mode 100644 index 00000000..e8c396fc --- /dev/null +++ b/specs/player_spec.rb @@ -0,0 +1,130 @@ +require_relative './spec_helper' +require_relative '../scrabble.rb' + +describe Player do #this is testing to make sure Player exists + it "will not be nil" do + Player.wont_be_nil + end +end + + + describe "Player#new(name)" do #this tests to make sure the initialize method exists + it "does the class initialize a name" do + Player.new(name).wont_be_nil + + end +end + + +describe "Player#play(word)" do + mindy = Player.new("mindy") #this is creating a new instance + + it "should return the score of the word played" do #this is testing that the score of the word played is correct + mindy.play("cat").must_equal(5) + end +end + + describe "Player#plays" do #this is creating a new instance + mindy = Player.new("mindy") + mindy.play("cat") + + it "should return the array of words played with the new word added" do + mindy.plays.must_equal(["cat"]) #this is testing that the word played was added to the array + end + + end + + describe "Player#total_score" do + mindy = Player.new("mindy") + mindy.play("cat") + + it "should return the sum of scores" do #this is testing that the sum of scores is correct + mindy.total_score.must_equal(5) + end + + end + + describe "Player#play(word)" do + mindy = Player.new("mindy") + it "should return the score of the word played" do + mindy.play("kittens").must_equal(61) + end + end + + describe "Player#plays" do + mindy = Player.new("mindy") + mindy.play("cat") + mindy.play("kittens") + + it "should return the array of words played with the new word added" do + mindy.plays.must_equal(["cat", "kittens"]) + end + end + + + describe "Player#total_score" do + mindy = Player.new("mindy") + mindy.play("cat") + mindy.play("kittens") + + it "should return the sum of scores" do + mindy.total_score.must_equal(66) + end + end + + describe "Player#won?" do + mindy = Player.new("mindy") + mindy.play("cat") + mindy.play("kittens") + + it "should return false when total_score is less than 100" do + mindy.won?.must_equal(false) + end + end + + describe "Player#won?" do + mindy = Player.new("mindy") + mindy.play("cat") + mindy.play("kittens") + mindy.play("singing") + + it "should return true when total_score is more than 100" do + mindy.won?.must_equal(true) + end + end + + describe "Player#won?" do + mindy = Player.new("mindy") + mindy.play("cat") + mindy.play("kittens") + + it "should give the highest_scoring_word" do + mindy.highest_scoring_word.must_equal("kittens") + end + end + + + describe "Player#won?" do + mindy = Player.new("mindy") + mindy.play("cat") + mindy.play("kittens") + + it "should give the highest_scoring_word's score" do + mindy.highest_word_score.must_equal(61) + end + end + + describe "Player#draw_tiles" do #this is testing to make sure draw_tiles exists + it "will not be nil" do + Player.draw_tiles.wont_be_nil + end + + + describe "Player#draw_tiles" do #this is testing that the new instance of bag will have the right number of tiles (7) + ania = Player.new("ania") + my_bag = Tilebag.new + ania.draw_tiles(my_bag) + it "should return the correct number of tiles" do + ania.tiles.length.must_equal(7) + end + end diff --git a/specs/scoring_spec.rb b/specs/scoring_spec.rb new file mode 100644 index 00000000..01d92acb --- /dev/null +++ b/specs/scoring_spec.rb @@ -0,0 +1,44 @@ +require_relative './spec_helper' +require_relative '../scrabble.rb' + +#describe -> works with minitest, its for specs** +describe Scoring do #this is testing to make sure Scoring exists + it "will not be nil" do + Scoring.wont_be_nil + end + + + describe "Scoring#score" do #this is testing the method that will return the numeric value of the word + TEST_CASES = { + "CAT" => 5, + "cat" => 5, + "kittens" => 61 + } + + + TEST_CASES.each do |word, score| #iterating through the test cases above to return the score of each word + it "should return the total score #{score} for the word #{word}" do + Scoring.score(word).must_equal(score) + end + end + end + + + describe "Scoring#highest_score_from" do #this is testing the method that will return the word with the greatest value + TEST_CASES_2 = { + [ "cat", "kittens", "dog"] => "kittens", + [ "fare", "mom"] => "mom", #testing that between two words with the same score (7), the one with fewer tiles wins + ["qzqzqz", "aeiounf"] => "aeiounf", #testing that between 2 words with the same score (60), the one with 7 tiles wins, even if it's not the first word in array + ["wadeiou", "kittens", "dog"] => "wadeiou", #testing that between 2 words with same score (61) with same number of tiles (7), the first one wins + ["cat", "hi"] => "hi" #testing that between two words with the same score, the one with the fewer tiles wins + } + + TEST_CASES_2.each do |array, highest_word| #iterating through the test cases above with the method to return the highest_word + it "should return the word with the highest score #{highest_word} for the array of words #{array}" do + Scoring.highest_score_from(array).must_equal(highest_word) + end + end + + + end +end diff --git a/specs/spec_helper.rb b/specs/spec_helper.rb new file mode 100644 index 00000000..1500c32e --- /dev/null +++ b/specs/spec_helper.rb @@ -0,0 +1,8 @@ +require 'minitest' +require 'minitest/spec' +require 'minitest/autorun' +require 'minitest/reporters' + +#give us some really pretty output :) + +Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new diff --git a/specs/tilebag_spec.rb b/specs/tilebag_spec.rb new file mode 100644 index 00000000..f97d48e1 --- /dev/null +++ b/specs/tilebag_spec.rb @@ -0,0 +1,64 @@ +require_relative './spec_helper' +require_relative '../scrabble.rb' + +describe Tilebag do #this is testing to make sure Tilebag exists + it "will not be nil" do + Tilebag.wont_be_nil + end +end + +#this tests to make sure the initialize method exists +describe "Tilebag#new" do + it "does the class initialize a collection of default tiles" do + my_bag = Tilebag.new + my_bag.tiles_in_bag.wont_be_nil + end +end + +# test that it takes correct number of tiles + describe "Tilebag#draw_tiles(num)" do + it "samples a given number of tiles from bag" do + my_bag = Tilebag.new + my_bag.draw_tiles(5).length.must_equal(5) + end + end + +# test the number of tiles left in bag is correct + describe "Tilebag#draw_tiles(num)" do + it "gives the correct number of tiles left in bag" do + my_bag = Tilebag.new + my_bag.draw_tiles(5) + result = my_bag.tiles_in_bag.values.reduce(0) { |sum, value| sum + value } + result.must_equal(93) + end + end + + + # test that if # of tiles requested is more than in the bag, will return the # of tiles left in bag + describe "Tilebag#draw_tiles(num)" do + it "gives the # of tiles left in bag without throwing an error when more tiles are requested than are in bag" do + my_bag = Tilebag.new + my_bag.draw_tiles(100) + result = my_bag.tiles_in_bag.values.reduce(0) { |sum, value| sum + value } + result.must_equal(0) + end + end + + # test that if # of tiles requested is more than in bag, will return the # of tiles availble without an error + describe "Tilebag#draw_tiles(num)" do + it "gives the number of tiles the player recieves, even if the number requested is more than the number in the bag, without throwing an error " do + my_bag = Tilebag.new + result = my_bag.draw_tiles(100) + result.length.must_equal(98) + end + end + + + #test that the remaining number of tiles is correct + describe "Tilebag#tiles_remaining" do + it "gives the remaining number of tiles left in bag after a certain number has been requested" do + my_bag = Tilebag.new + my_bag.draw_tiles(10) + my_bag.tiles_remaining.must_equal(88) + end + end