Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
c7d7019
Added Scrabble Module and Scoring Class with letter scores
nahmisa Mar 8, 2016
9958762
Updated for JNF clarifications about directory structure
nahmisa Mar 8, 2016
5c4108f
Added boilerplate for testing.
nahmisa Mar 8, 2016
3ee9a15
Made a test for Scoring
nahmisa Mar 8, 2016
adcf680
self.score and self.highest_score_from. Incomplete conditional flow
nicosaki Mar 8, 2016
ced08dd
Match up with head
nahmisa Mar 8, 2016
cd95f2b
Lunchtime commit - 1 error in scoring_spec still
nahmisa Mar 8, 2016
134c672
We passed the tests! Fun with class methods (which take a parameter …
nahmisa Mar 8, 2016
49510c9
Added TEST_CASES hash for score method and it passed. We rule.
nahmisa Mar 8, 2016
bb339af
second test for compare_words_by_length passed! yay
nicosaki Mar 8, 2016
154ce7f
second test for compare_words_length passed
nicosaki Mar 8, 2016
df588aa
Tested that shortest word still wins even when scores are equal
nahmisa Mar 8, 2016
102de36
Passed test for case of multiple 7 winners.
nahmisa Mar 8, 2016
e2a8eb2
Wave 1 complete
nicosaki Mar 8, 2016
1119a1a
More tests on Wave 1 for user input weirdness
nicosaki Mar 8, 2016
2cdf257
Refactored duplicate code for methods, changed variables/argument nam…
nahmisa Mar 9, 2016
b0961a6
Reordered TEST CASES so they increase in complexity
nahmisa Mar 9, 2016
0ef9f86
More refeactoring for clarity
nahmisa Mar 9, 2016
24fbbf6
Wave 2 complete.
nicosaki Mar 9, 2016
606497c
Reordered tests by method tested
nahmisa Mar 9, 2016
4dfa199
Lunchtime commit
nahmisa Mar 9, 2016
da23458
Added TileBag class and test for existence of class
nahmisa Mar 9, 2016
3f4a6e4
Draw tiles method and test for random tiles are drawn, right length a…
nahmisa Mar 10, 2016
37ad1c8
start of wave 3 tilebag and tilebag spec
nicosaki Mar 10, 2016
49e41e8
Modifications to player to include #tiles and #draw_tiles
nicosaki Mar 10, 2016
66b1ef8
First refactor complete including rearranging Scrabble module and rem…
nicosaki Mar 10, 2016
3658371
Added removal of player's tiles for played word
nahmisa Mar 11, 2016
f9f86ed
Added modules to Class files, updated specs for new naming (Scrabble:…
nahmisa Mar 11, 2016
5d84b79
Removed module name from constants in classes Player and Scoring.
nahmisa Mar 11, 2016
7872f06
Optional game board complete with 10 specs
nicosaki Mar 11, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -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
65 changes: 65 additions & 0 deletions lib/board.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
require 'pp'
module Scrabble
class Board
attr_accessor :board
def initialize()
@board = create_board
end

def create_board
fill = "_ " * 7
fill = fill.split
board = []
7.times do
duplicate = fill.dup
board << duplicate
end
return board
end

#Call check placement first, if return true call place tiles
def place_tiles(word, direction, row, column)
characters = word.chars
i = 0
if direction.downcase == "across"
characters.each do |letter|
@board[row][column+i] = letter
i += 1
end
else
characters.each do |letter|
@board[row+i][column] = letter
i += 1
end
end
return @board
end

def check_placement(word, direction, row, column) # [row, row]
characters = word.chars
i = 0
if direction.downcase == "across"
characters.each do |letter|
if (@board[row][column+ i] == "_") || (@board[row][column + i] == letter)
i += 1
else
puts "Invalid placement"
return false
end
end
else
characters.each do |letter|
if (@board[row+i][column] == "_") || (@board[row+i][column] == letter)
i += 1
else
puts "Invalid placement"
return false
end
end
end
pp @board
return true
end
end

end
Empty file added lib/dictionary.rb
Empty file.
53 changes: 53 additions & 0 deletions lib/player.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
module Scrabble
class Player
attr_reader :name
attr_accessor :plays, :tiles, :tile_bag
def initialize(name)
@name = name
@plays = []
@tile_bag = TileBag.new()
@tiles = tile_bag.draw_tiles(MAXIMUM_NUMBER_OF_LETTERS)
end


def draw_tiles(tile_bag_arg = tile_bag)
tiles_drawn = tile_bag_arg.draw_tiles(MAXIMUM_NUMBER_OF_LETTERS - tiles.length)
tiles.concat(tiles_drawn)
end

def play(word) #everytime we play we also have to call remove tiles. Not part of this method because it breaks tests (we don't know what random array is generated for tests, so there are lots of nil errors)
if won?
return false
else
plays << word
this = Scoring.score(word)
return this
end
end

def remove_tiles(word) #would have to remove letters from player's tiles when word is played.
played_tiles = word.chars
played_tiles.each do |tile|
tiles.delete_at(tiles.find_index(tile))
end
end

def total_score
return 0 if plays.empty?
score_array = plays.collect { |word| Scoring.score(word) }
score_array.reduce(:+)
end

def won?
total_score > 100 ? true : false
end

def highest_scoring_word
Scoring.highest_score_from(plays)
end

def highest_word_score
Scoring.score(highest_scoring_word)
end
end
end
82 changes: 82 additions & 0 deletions lib/scoring.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
module Scrabble
class Scoring
LETTER_SCORES = {"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}


def self.score(word) # takes a string
return 0 if word.empty? # empty string/pass

score = 0

#Add bonus for word_length corner case.
score = 50 if word.length == Scrabble::MAXIMUM_NUMBER_OF_LETTERS

split_word = word.downcase.split('') # downcase for comparing

split_word.each do |letter|
score += LETTER_SCORES[letter]
end

return score
end

def self.highest_score_from(array_of_words)

score_array = array_of_words.collect { |word| self.score(word) }

number_of_highest_scores = self.get_number_of_duplicates(score_array.sort.reverse)
# sort gives ascending
# reverse for descending to compare HIGHEST scores

highest_scoring_words = array_of_words.max_by(number_of_highest_scores) { |word| self.score(word) }

return highest_scoring_words[0].to_s if highest_scoring_words.length == 1

words_by_length = highest_scoring_words.min_by(number_of_highest_scores) { |word| word.length }
#shortest first - sorting WORDS by length (to analyze ties)

lengths_of_words = words_by_length.collect { |word| word.length }

if lengths_of_words.last == MAXIMUM_NUMBER_OF_LETTERS
if self.has_duplicates?(lengths_of_words.reverse) # reverse to change ascending to descending because WORD_LENGTH_MAXIMUM is the longest we expect
winning_word = self.get_first_word_for_length_and_score(lengths_of_words.reverse, words_by_length, array_of_words)
return winning_word
end

return words_by_length.last

elsif self.has_duplicates?(lengths_of_words) # we do want this in ascending order because normally smaller words win (based on rules)
winning_word = self.get_first_word_for_length_and_score(lengths_of_words, words_by_length, array_of_words)
return winning_word
else
words_by_length.first
end
end

def self.has_duplicates?(array_of_words)
self.get_number_of_duplicates(array_of_words) > 1 ? true : false
end

def self.get_first_word_for_length_and_score(array_of_equal_lengths, high_scores_array, original_array)

number_of_ties_same_length = self.get_number_of_duplicates(array_of_equal_lengths)
potential_winners = high_scores_array.first(number_of_ties_same_length)
winning_word = original_array.find { |word| potential_winners.include? word }
return winning_word
end

def self.get_number_of_duplicates(array_of_words)
i = 1
array_of_words_x = array_of_words.dup # prevents mutation of array_of_words from shift
while (array_of_words_x[0] == array_of_words_x[1]) && (array_of_words_x.length > 1)
array_of_words_x.shift
i +=1
end
return i
end

end
end
38 changes: 38 additions & 0 deletions lib/tilebag.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
module Scrabble
class TileBag

attr_accessor :default_tiles

def initialize
@default_tiles = ["a", "a", "a", "a", "a", "a", "a", "a",
"a", "n", "n", "n", "n", "n", "n", "b", "b", "o", "o", "o", "o", "o",
"o", "o", "o", "c", "c", "p", "p", "d", "d", "d", "d", "q", "e", "e",
"e", "e", "e", "e", "e", "e", "e", "e", "e", "e", "r", "r", "r", "r",
"r", "r", "f", "f", "s", "s", "s", "s", "g", "g", "g", "t", "t", "t",
"t", "t", "t", "h", "h", "u", "u", "u", "u", "i", "i", "i", "i", "i",
"i", "i", "i", "i", "v", "v", "j", "w", "w", "k", "x", "l", "l", "l",
"l", "y", "y", "m", "m", "z"]

end

def draw_tiles(num)
# num number of random tiles
random_tiles = default_tiles.sample(num)


# remove these tiles from the default set
random_tiles.each do |tile|
default_tiles.delete_at(default_tiles.find_index(tile))
# delete_at mutates array like slice
end

return random_tiles

end

def tiles_remaining
default_tiles.length
end

end
end
8 changes: 8 additions & 0 deletions scrabble.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
require './lib/scoring'
require './lib/player'
require './lib/tilebag'
require './lib/board'

module Scrabble
MAXIMUM_NUMBER_OF_LETTERS = 7
end
79 changes: 79 additions & 0 deletions specs/board_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
require_relative './spec_helper'

describe Scrabble::Board do
it "is an object we have access to" do
Scrabble::Board.wont_be_nil
end

describe "Board#board" do
it "has a board consisting of an array" do
game = Scrabble::Board.new
game.board.must_be_kind_of Array
end
end

describe "Board#place_tiles" do
it "places first tile in given position" do
game = Scrabble::Board.new
game.place_tiles("cat", "down", 2, 0)
game.board[2][0].must_equal "c"
end

it "places second tile in given position" do
game = Scrabble::Board.new
game.place_tiles("cat", "down", 2, 0)
game.board[3][0].must_equal "a"
end

it "places third tile in given position" do
game = Scrabble::Board.new
game.place_tiles("cat", "down", 2, 0)
game.board[4][0].must_equal "t"
end

it "returns true if 'trogdor' placed accurately, 'r' in expected position" do
game = Scrabble::Board.new
game.place_tiles("cat", "down", 2, 0)
game.check_placement("cold", "across", 2, 0)
game.place_tiles("cold", "across", 2, 0)
game.check_placement("dog", "down", 2, 3)
game.place_tiles("dog", "down", 2, 3)
game.check_placement("trogdor", "across", 4, 0)
game.place_tiles("trogdor", "across", 4, 0)
game.board[4][6].must_equal "r"
end
end

describe "Board#check_placement" do
it "returns false if invalid tile placement given" do
game = Scrabble::Board.new
game.place_tiles("cat", "down", 2, 0)
game.check_placement("dog", "across", 2, 0).must_equal false
end

it "returns true if valid placement" do
game = Scrabble::Board.new
game.place_tiles("cat", "down", 2, 0)
game.check_placement("cold", "across", 2, 0).must_equal true
end

it "returns true if valid placement on third word play" do
game = Scrabble::Board.new
game.place_tiles("cat", "down", 2, 0)
game.check_placement("cold", "across", 2, 0)
game.place_tiles("cold", "across", 2, 0)
game.check_placement("dog", "down", 2, 3).must_equal true
end

it "returns true if valid placement on trogdor across, intersecting cat and dog" do
game = Scrabble::Board.new
game.place_tiles("cat", "down", 2, 0)
game.check_placement("cold", "across", 2, 0)
game.place_tiles("cold", "across", 2, 0)
game.check_placement("dog", "down", 2, 3)
game.place_tiles("dog", "down", 2, 3)
game.check_placement("trogdor", "across", 4, 0).must_equal true
end

end
end
Loading