diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 00000000..1ad899db Binary files /dev/null and b/.DS_Store differ 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..7778ef33 --- /dev/null +++ b/lib/player.rb @@ -0,0 +1,72 @@ +#require_relative '../scrabble' # allows this class to access scrabble and run through irb + +class Scrabble::Player + include Scrabble + MAX_TILES_ON_TRAY = 7 + attr_reader :name + + def initialize(player_info) + @name = player_info[:name] + @plays = [] + @tiles = [] # these are the tiles that the player has on their little tray + @tilebag = Scrabble::TileBag.new + draw_tiles(@tilebag) + end + + # thought about putting this in attr_accessor, but that would let the player edit it in IRB??? + def plays + @plays + end + + def play(word) + @plays << word + score = Scrabble::Scoring.score(word) + won? == true ? false : score + #return false if the player has already won + + end + + def words_and_matching_scores + total_score_hash = {} + + plays.each do |word| + total_score_hash[word] = Scrabble::Scoring.score(word) + end + total_score_hash + end + + def total_score + # gets value from the scores_for_each_word method + words_and_matching_scores.values.reduce(:+) + end + + def won? + total_score >= 100 ? true : false + end + + def highest_scoring_word + highest_score[0] + end + + def highest_score + high_score = words_and_matching_scores.max_by do |word, score| + score + end + high_score + end + + def highest_word_score + highest_score[1] + end + + # thought about putting this in attr_accessor, but that would let the player edit it in IRB??? + def tiles + @tiles + end + + def draw_tiles(tile_bag) + num = MAX_TILES_ON_TRAY - tiles.length + @tiles = tile_bag.draw_tiles(num) + end + +end diff --git a/lib/scoring.rb b/lib/scoring.rb new file mode 100644 index 00000000..70d3ee78 --- /dev/null +++ b/lib/scoring.rb @@ -0,0 +1,62 @@ +#require_relative '../scrabble' # allows this class to access scrabble and run through irb + +class Scrabble::Scoring + include Scrabble + LETTER_POINTS = { + 1 => ["A", "E", "I", "O", "U", "L", "N", "R", "S", "T"], + 2 => ["D", "G"], + 3 => ["B", "C", "M", "P"], + 4 => ["F", "H", "V", "W", "Y"], + 5 => ["K"], + 8 => ["J", "X"], + 10 => ["Q", "Z"] + } + + # returns the score value for a single given word + def self.score(word) + score = 0 + tiles = 0 + + word_array = word.upcase.split("") + + word_array.each do |letter| + LETTER_POINTS.each do |points, letters_array| + if letters_array.include? letter + score += points + tiles += 1 + end + end + end + # if all seven tiles are used the below tenary will add 50 points to the users score else return score + tiles == 7 ? score += 50 : score + score + end + + def self.highest_score_from(array_of_words) # array_of_words = ["cats", "fee", "no"] + + array_of_word_values = [] + array_of_words.each do |word| + array_of_word_values << [word, self.score(word), word.length] # = [["cats", 7, 4], ["fee", 7, 3], ["no", 2, 2]] + end + + highest_score_array = array_of_word_values[0] # ["cats", 7, 4] + + array_of_word_values.each do |word_array| # ["cats", 7, 4] + # compares the score of the words + if word_array[1] == highest_score_array[1] # compare score + # compares the length of the words + if word_array[2] < highest_score_array[2] + highest_score_array[2] == 7 ? highest_score_array : highest_score_array = word_array + #highest_score_array = word_array # replace the highest score to the word_array being referenced + elsif word_array[2] >= highest_score_array[2] + if highest_score_array[2] < 7 + word_array[2] == 7 ? highest_score_array = word_array : highest_score_array + end + end + elsif word_array[1] > highest_score_array[1] + highest_score_array = word_array + end + end + return highest_score_array[0] + end +end diff --git a/lib/tilebag.rb b/lib/tilebag.rb new file mode 100644 index 00000000..f9d4a103 --- /dev/null +++ b/lib/tilebag.rb @@ -0,0 +1,58 @@ +# require_relative './scrabble.rb' + +class Scrabble::TileBag + + include Scrabble + + attr_reader :default_tiles + + def initialize + @default_tiles = [["A", 1], ["A", 1], ["A", 1], ["A", 1], ["A", 1], ["A", 1], ["A", 1], ["A", 1], ["A", 1], + ["B", 1], ["B", 1], + ["C", 1], ["C", 1], + ["D", 1], ["D", 1], ["D", 1], ["D", 1], + ["E", 1], ["E", 1], ["E", 1], ["E", 1], ["E", 1], ["E", 1], ["E", 1], + ["E", 1], ["E", 1], ["E", 1], ["E", 1], ["E", 1], + ["F", 1], ["F", 1], + ["G", 1], ["G", 1],["G", 1], + ["H", 1], ["H", 1], + ["I", 1], ["I", 1], ["I", 1], ["I", 1], ["I", 1], ["I", 1], ["I", 1], ["I", 1], ["I", 1], + ["J", 1], + ["K", 1], + ["L", 1], ["L", 1], ["L", 1], ["L", 1], + ["M", 1], ["M", 1], + ["N", 1], ["N", 1], ["N", 1], ["N", 1], ["N", 1], ["N", 1], + ["O", 1], ["O", 1], ["O", 1], ["O", 1], ["O", 1], ["O", 1], ["O", 1], ["O", 1], + ["P", 1], ["P", 1], + ["Q", 1], + ["R", 1], ["R", 1], ["R", 1], ["R", 1], ["R", 1], ["R", 1], + ["S", 1], ["S", 1], ["S", 1], ["S", 1], + ["T", 1], ["T", 1], ["T", 1], ["T", 1], ["T", 1], ["T", 1], + ["U", 1], ["U", 1], ["U", 1], ["U", 1], + ["V", 1], ["V", 1], + ["W", 1], ["W", 1], + ["X", 1], + ["Y", 1], ["Y", 1], + ["Z", 1]] + end + + def draw_tiles(num) + + array_of_selected_tiles =[] + + # picks a random number that will be used as the index value for selecting a tile, + # and then it adds the tile that has that index to array_of_selected_words, then + # it will delete the tile at that index + num.times do + selected_tile_index = rand(0..default_tiles.length) + array_of_selected_tiles << @default_tiles[selected_tile_index] + @default_tiles.delete_at(selected_tile_index) + end + array_of_selected_tiles + end + + def tiles_remaining + default_tiles.length + end + +end diff --git a/scrabble.rb b/scrabble.rb new file mode 100644 index 00000000..fc18637f --- /dev/null +++ b/scrabble.rb @@ -0,0 +1,12 @@ + +# using this module as a namespace, not a mixin +module Scrabble + + +end + +# putting this at the end because otherwise it will read scoring.rb before it creates +# the Scrabble module, meaning the code in scoring.rb won't work +require_relative './lib/scoring' +require_relative './lib/player' +require_relative './lib/tilebag' diff --git a/specs/player_spec.rb b/specs/player_spec.rb new file mode 100644 index 00000000..72faebe6 --- /dev/null +++ b/specs/player_spec.rb @@ -0,0 +1,130 @@ +require_relative './spec_helper' + +describe Scrabble::Player do + it "should be an object we have access to" do + Scrabble::Player.wont_be_nil + end +end + +describe "Scrabble::Player#name" do + # returns the value of the @name instance variable + it "should return the value 'Joe' when player instance is named Joe" do + joe = Scrabble::Player.new(name: "Joe") + joe.name.must_equal ("Joe") + end +end + +describe "Scrabble::Player#plays" do + joe = Scrabble::Player.new(name: "Joe") + + it "should return the score '5' for the word 'cat'" do + joe.play("cat").must_equal 5 + end + +end + +describe "Scrabble::Player#play(word)" do + mary = Scrabble::Player.new(name: "Mary") + + it "should return false if player has already won" do + # starts mary off with a bunch of words already played, then adds "cat" + array_of_words = ["nose", "aaaaaad", "eeeeeed", "frog", "rrrrrrr", "qqqqqj"] + + # create an each method that will play the words in the array one by one + array_of_words.each do |word_played| + mary.play(word_played) + end + + mary.play("cat").must_equal false + end +end + +describe "Scrabble::Player#total_score" do + jane = Scrabble::Player.new(name: "Jane") + it %!should return '243' for array_of_words = ["nose", "aaaaaad", "eeeeeed", "frog", "rrrrrrr", "qqqqqj"]! do + array_of_words = ["nose", "aaaaaad", "eeeeeed", "frog", "rrrrrrr", "qqqqqj"] + + # create an each method that will play the words in the array one by one + array_of_words.each do |word_played| + jane.play(word_played) + end + + jane.total_score.must_equal 243 + end +end + +describe "Scrabble::Player#highest_scoring_word" do + april = Scrabble::Player.new(name: "April") + + # it should return the highest scoring played WORD + it %!should return "frog" for the words played "frog" and "nose"! do + april.play("frog") + april.play("nose") + april.highest_scoring_word.must_equal "frog" + end + + it %!should return 'aaaaaad' for array_of_words = ["nose", "aaaaaad", "eeeeeed", "frog", "rrrrrrr", "qqqqqj"]! do + fox = Scrabble::Player.new(name: "Fox") + array_of_words = ["nose", "aaaaaad", "eeeeeed", "frog", "rrrrrrr", "qqqqqj"] + # create an each method that will play the words in the array one by one + array_of_words.each do |word_played| + fox.play(word_played) + end + + fox.highest_scoring_word.must_equal "aaaaaad" + end + + +end + +describe "Scrabble::Player#highest_word_score" do + jody = Scrabble::Player.new(name: "Jody") + + # it should return the highest scoring played WORD + it %!should return "8" for the words played "frog" and "nose"! do + jody.play("frog") + jody.play("nose") + jody.highest_word_score.must_equal 8 + end + + it %!should return '58' for array_of_words = ["nose", "aaaaaad", "eeeeeed", "frog", "rrrrrrr", "qqqqqj"]! do + fox = Scrabble::Player.new(name: "Fox") + array_of_words = ["nose", "aaaaaad", "eeeeeed", "frog", "rrrrrrr", "qqqqqj"] + # create an each method that will play the words in the array one by one + array_of_words.each do |word_played| + fox.play(word_played) + end + + fox.highest_word_score.must_equal 58 + end + +end + +describe "Scrabble::Player#won?" do + + it %!should return 'true' for array_of_words = ["nose", "aaaaaad", "eeeeeed", "frog", "rrrrrrr", "qqqqqj"]! do + fox = Scrabble::Player.new(name: "Fox") + array_of_words = ["nose", "aaaaaad", "eeeeeed", "frog", "rrrrrrr", "qqqqqj"] + # create an each method that will play the words in the array one by one + array_of_words.each do |word_played| + fox.play(word_played) + end + + fox.won?.must_equal true + end + + it %!should return "false" for the words played "frog" and "nose"! do + jody = Scrabble::Player.new(name: "Jody") + jody.play("frog") + jody.play("nose") + jody.won?.must_equal false + end +end + +describe "Scrabble::Player#tiles" do + bill = Scrabble::Player.new(name: "Bill") + # should return a collection of letters that the player can play (max 7) -- that's their own personal little tray of letters + it "should return 7 letters" do + bill.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..8876bd42 --- /dev/null +++ b/specs/scoring_spec.rb @@ -0,0 +1,95 @@ +require_relative './spec_helper' + +describe Scrabble::Scoring do + it "is an object we have access to" do + Scrabble::Scoring.wont_be_nil + end +end + +describe "Scrabble::Score.score" do + TEST_SCRABBLE_SCORE = { + 1 => ["A", "E", "I", "O", "U", "L", "N", "R", "S", "T"], + 2 => ["D", "G"], + 3 => ["B", "C", "M", "P"], + 4 => ["F", "H", "V", "W", "Y"], + 5 => ["K"], + 8 => ["J", "X"], + 10 => ["Q", "Z"] + } + + # tests single letter + TEST_SCRABBLE_SCORE.each do |points, letters_array| + it "should return the scrabble score of #{points} for the letter #{letters_array}" do + letters_array.each do |letter_from_array| + Scrabble::Scoring.score(letter_from_array).must_equal points + end + end + end + + # tests 2 characters + it "should return the value '2' for the word 'AE' " do + Scrabble::Scoring.score("AE").must_equal 2 + end + + # check case sensativity and multiple characters with different points for total score value + it "should return the value '5' for the word 'cAt'" do + Scrabble::Scoring.score("cAt").must_equal 5 + end + + # check if user used all 7 tiles and adds 50 points to the score + it "should return the value '57' for the word 'aaaaaaa'" do + Scrabble::Scoring.score('aaaaaaa').must_equal 57 + end + + # checked another 7 letter word =) + it "should return the value '60' for the word 'Valerie'" do + Scrabble::Scoring.score('Valerie').must_equal 60 + end +end + +describe "Scrabble::Scoring.highest_score_from(array_of_words)" do + + # build of array of words and return the highest value word + + it "should return the word 'hello' for the word_array = ['hello']" do + array_of_words = ["hello"] + Scrabble::Scoring.highest_score_from(array_of_words).must_equal "hello" + end + + it "should return the word 'hello' as the highest score from the word_array = ['hello', 'cat']" do + array_of_words = ["hello", "cat"] + Scrabble::Scoring.highest_score_from(array_of_words).must_equal "hello" + end + + # for tiebreaker, the word with less tiles used is returned + it "should return the word 'fee' from the word_array = ['cats', 'fee', 'no']" do + array_of_words = ["cats", "fee", "no"] + Scrabble::Scoring.highest_score_from(array_of_words).must_equal "fee" + end + + # if top score is tied between multiple words but one used all seven letters, that one wins + it "should return the word 'aaaaaaa' from the word_array = ['feet', 'aaaaaad', 'no', 'qqqqqj']" do + # chose the following words because aaaaaad's score is 58 including the 7-letter bonus, + # and qqqqqj's score is also 58 just because of the rare letters + array_of_words = ["feet", "aaaaaad", "no", "qqqqqj"] + Scrabble::Scoring.highest_score_from(array_of_words).must_equal "aaaaaad" + end + + it "should return the word 'aaaaaaa' from the word_array = ['feet', 'qqqqqj, 'no', 'aaaaaad']! BACKWARDS MODE!" do + # chose the following words because aaaaaad's score is 58 including the 7-letter bonus, + # and qqqqqj's score is also 58 just because of the rare letters + array_of_words = ["feet", "qqqqqj", "no", "aaaaaad"] + Scrabble::Scoring.highest_score_from(array_of_words).must_equal "aaaaaad" + end + + # testing multiple words with same score and same length + it "should return 'aaaaaaa' from the word_array = ['aaaaaaa', 'eeeeeee', 'frog']" do + array_of_words = ["aaaaaaa", "eeeeeee", "frog"] + Scrabble::Scoring.highest_score_from(array_of_words).must_equal "aaaaaaa" + end + + it %!should return 'aaaaaad' from the word_array = ["nose", "aaaaaad", "eeeeeed", "frog", "rrrrrrr", "qqqqqj"]! do + array_of_words = ["nose", "aaaaaad", "eeeeeed", "frog", "rrrrrrr", "qqqqqj"] + Scrabble::Scoring.highest_score_from(array_of_words).must_equal "aaaaaad" + end +end diff --git a/specs/spec_helper.rb b/specs/spec_helper.rb new file mode 100644 index 00000000..d33c7096 --- /dev/null +++ b/specs/spec_helper.rb @@ -0,0 +1,11 @@ +require 'simplecov' +SimpleCov.start + +require 'minitest' +require 'minitest/spec' +require 'minitest/autorun' +require 'minitest/reporters' + +require_relative '../scrabble' + +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..abbb76ce --- /dev/null +++ b/specs/tilebag_spec.rb @@ -0,0 +1,41 @@ +require_relative './spec_helper' + +describe Scrabble::TileBag do + it "should be an object we have access to" do + Scrabble::TileBag.wont_be_nil + end +end + +describe "Scrabble::TileBag.default_tiles" do + it "should be an instance variable" do + Scrabble::TileBag.new.default_tiles.wont_be_nil + end +end + +describe "Scrabble::TileBag#draw_tiles" do + it "should return 5 random tiles" do + joe_tiles = Scrabble::TileBag.new + joe_tiles.draw_tiles(5).length.must_equal 5 + end + + it "should return 7 random tiles" do + joe_tiles = Scrabble::TileBag.new + joe_tiles.draw_tiles(7).length.must_equal 7 + end + +end + +describe "Scrabble::TileBag#tiles_remaining" do + # returns the number of tiles remaining in the bag + it "should return 98 for draw_tiles(0)" do + joe_tiles = Scrabble::TileBag.new + joe_tiles.tiles_remaining.must_equal 98 + end + + it "should return '93' for draw_tiles(5)" do + joe_tiles = Scrabble::TileBag.new + joe_tiles.draw_tiles(5) + joe_tiles.tiles_remaining.must_equal 93 + end + +end