Forked from dbc-challenges/0.2.1-boggle_class_from_methods.rb
Last active
August 29, 2015 13:55
-
-
Save kanhirun/8715256 to your computer and use it in GitHub Desktop.
create a boggle board class
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
=begin======================================================================== | |
EXERCISE: Create a Boggle Board Class | |
Ruby 2.1.0 | |
Kel Kanhirun | |
January 30, 2014 | |
I/O: #create_word, String => String | |
#get_row, Integer => Array | |
#get_col, Integer => Array | |
PROPOSITION | |
=============================================================================== | |
(1) BoggleBoard initializes with an argument, dice_grid, which should provide a | |
2D array (by hypothesis) | |
From (1), | |
(2) Raise ArgumentError if dice_grid does not meet the hypothesis: | |
(Criteria A) dice_grid must be a 2-dimensional array | |
(Criteria B) dice_grid must hold only string objects | |
(Criteria C) dice_grid must be squared. | |
From (1) and (2), | |
(3) Create the following objects which meet or do not meet these one or | |
more conditions that confirm the hypothesis: | |
(Test A) Meets none of the criteria | |
(Test B) ["A"]["B"]["C"] | |
(Test C) ["A", "B"]["A", "C"]["B", "C"] | |
(Test D) ["A", "B", "C"] | |
(4) Reproduce methods (#create_word, #get_row, #get_col) from the previous | |
exercise. | |
(5) #create_word accepts the "standard form", (a, b), where a and b is a "valid pair of numbers". | |
(Defn. of standard form) | |
A standard form is a string object which has the proper opening and | |
close tags. The proper opening tags are either parentheses (), curly | |
braces {}, or square brackets []. | |
(Defn. of valid pairs) | |
A valid pair are two numbers that exists in the given two-dimensional | |
array and are given as a pair. That is, the numbers a and b, must both | |
be defined. The numbers a and b, are only valid if both a and b are | |
identifiable on the Boggle board. | |
From (5), | |
(6) Create tests for all cases of standard form and nonstandard forms. | |
(Criteria A) The input is a string object. | |
# On standard forms, | |
(Criteria B) A standard form of [] is provided. | |
(Criteria C) A standard form of {} is provided. | |
(Criteria D) A standard form of () is provided. | |
(Criteria E) One and only one form is accepted. | |
# On valid pairs, | |
(Criteria F) The object a is defined as a number. | |
(Criteria G) The object b is defined as a number. | |
(Criteria H) A comma is used to separated the two numbers. | |
(Criteria I) The number pair, a and b, are valid on the given board. | |
================================================================================ | |
=end | |
# INITIAL CODE | |
class BoggleBoard | |
attr_reader :dice_grid | |
def initialize (dice_grid) | |
# see Proposition 3. | |
rows = Enumerator.new do |y| | |
dice_grid.each{ |obj| y << obj } | |
end | |
testA = (dice_grid.class != Array) | |
testB = (dice_grid.empty?) | |
testC = (dice_grid.any? { |obj| obj.class != Array }) | |
testD = (rows.each{ |letter| (letter.class == String) and letter =~ /[a-z]/ }) | |
testE = (rows.all? { |row| row.size == dice_grid.size }) | |
raise TypeError.new("Argument is not an array.") if testA | |
raise ArgumentError.new("Array is empty.") if testB | |
raise ArgumentError.new("Argument is not entirely a 2-D array.") if testC | |
raise ArgumentError.new("Array does not hold all valid objects.") unless testD | |
raise ArgumentError.new("Array is not a square; have mismatched rows and columns.") unless testE | |
@dice_grid = dice_grid | |
end | |
def create_word (*coords) | |
coords.map{ |coord| @dice_grid[coord[0]][coord[1]] }.join("") | |
end | |
def get_row (i) | |
dice_grid[i] | |
end | |
def get_col (i) | |
dice_grid.map{ |row| row[i] } | |
end | |
def get_diagonal (a, b) | |
return (0..3).map{ |n| @dice_grid[n][n] } if a[0] == a[1] and b[0] and b[1] | |
return (0..3).map{ |n| @dice_grid.reverse[n][n] } if a.reduce(:+) == 3 and b.reduce(:+) == 3 | |
end | |
end | |
# DRIVER TEST CODE | |
#=============================================================================== | |
puts "returns TypeError when argument is a string: " | |
p BoggleBoard.new("string") rescue $!.class == TypeError #=> true | |
puts "returns TypeError when argument is a number: " | |
p BoggleBoard.new(6) rescue $!.class == TypeError #=> true | |
pp "returns ArgumentError when argument is an invalid array: " | |
p BoggleBoard.new([]) rescue $!.class == ArgumentError #=> true | |
puts "returns ArgumentError when the array has columns greater than its rows: " | |
dice_grid = Array.new(3) { ["a", "v", "c", "d"] } | |
p BoggleBoard.new(dice_grid) rescue $!.class == ArgumentError #=> true | |
puts "returns ArgumentError when the array has rows greater than its columns: " | |
dice_grid = Array.new(5) { ["a", "v", "x"] } | |
p BoggleBoard.new(dice_grid) rescue $!.class == ArgumentError #=> true | |
p 'returns... "code", "rad", "cat", "boat", "taker"?', | |
new_game.create_word([2,1], [1,1], [1,2], [0,3]) == "code", # => true | |
new_game.create_word([0,1], [0,2], [1,2]) == "rad" , # => true | |
new_game.create_word([2,1], [3,1], [3,0]) == "cat" , # => true | |
new_game.create_word([0,0], [1,1],[0,2], [1,3]) == "boat" , # => true | |
new_game.create_word([3,0], [3,1], [3,2], [3,3], [2,3]) == "taker" # => true | |
p "returns rows correctly?", | |
new_game.get_row(0) == ["b", "r", "a", "e"], # => true | |
new_game.get_row(1) == ["i", "o", "d", "t"], # => true | |
new_game.get_row(2) == ["e", "c", "l", "r"], # => true | |
new_game.get_row(3) == ["t", "a", "k", "e"], # => true | |
p "returns columns correctly?", | |
new_game.get_col(0) == [ "b", "i", "e", "t" ], # => true | |
new_game.get_col(1) == [ "r", "o", "c", "a" ], # => true | |
new_game.get_col(2) == [ "a", "d", "l", "k" ], # => true | |
new_game.get_col(3) == [ "e", "t", "r", "e" ], # => true | |
dice_grid = [["b", "r", "a", "e"], | |
["i", "o", "d", "t"], | |
["e", "c", "l", "r"], | |
["t", "a", "k", "e"]] | |
boggle_board = BoggleBoard.new(dice_grid) | |
p "returns the correct array when given two coordinates to define a left-diagonal: " | |
p boggle_board.get_diagonal([0,0], [1,1]) == ["b", "o", "l", "e" ] #=> true | |
p "returns nil when given invalid coordinates: " | |
p boggle_board.get_diagonal([0,1], [2,1]) == nil #=> true | |
p "returns the correct array when given two coordinates to define a right-diagonal: " | |
p boggle_board.get_diagonal([2,1], [3,0]) == ["t", "c", "d", "e"] #=> true | |
# REFLECTIONS | |
=begin================================================================================= | |
For this exercise, I wanted to include tests for correct error types in my driver | |
test code. This is done inline, as +rescue $!.class == ArgumentError+, where $! | |
is the global variable of the current exception. | |
In these cases, the exception has been raised but not yet handled. This phenomenon | |
allows me to perform a rescue operation before it terminates the program provided | |
that the correct error was raised. | |
I had trouble making lines 91 - 101 readable at first. keyword_case was inflexible, | |
because it only allows comparisons of == to be made. Unless I change the core functionality | |
of Ruby, and I definitely didn't want to do that. On the other hand, the if-branches | |
didn't make it anymore readable either. My first attempt, then, was to do everything inline as, | |
raise <error> if <condition> | |
and I liked that the statement emphasizes that it is a raising an error, but the statement was bulky. | |
So, I decided to condense these long conditions into variables of testA, testB, ... etc. | |
I didn't have enough time to incorporate all the features I wanted, but I felt that as | |
long as I am aware of how to deal with these issues, then I'll work under the hypothesis | |
that the arguments given are valid. | |
====================================================================================== | |
=end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment