wordgrid 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/wordgrid.rb +117 -31
- metadata +1 -1
data/lib/wordgrid.rb
CHANGED
@@ -1,45 +1,38 @@
|
|
1
1
|
require 'matrix'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
if (e == letter)
|
8
|
-
cell = [row, column]
|
9
|
-
cells.push(cell)
|
10
|
-
end
|
11
|
-
end
|
12
|
-
return cells
|
13
|
-
end
|
14
|
-
|
15
|
-
# why doesn't matrix natively support this?!?
|
16
|
-
def neighbor_cells(root_cell)
|
17
|
-
row = root_cell[0]
|
18
|
-
column = root_cell[1]
|
19
|
-
cells = []
|
20
|
-
|
21
|
-
cells.push([row-1, column-1]) if row-1 >= 0 and column-1 >= 0 #NW
|
22
|
-
cells.push([row-1, column]) if row-1 >= 0 #N
|
23
|
-
cells.push([row-1, column+1]) if row-1 >= 0 and column+1 < column_size #NE
|
24
|
-
cells.push([row, column-1]) if column-1 >=0 #W
|
25
|
-
cells.push([row, column+1]) if column+1 < column_size #E
|
26
|
-
cells.push([row+1, column-1]) if row+1 < row_size and column-1 >= 0 #SW
|
27
|
-
cells.push([row+1, column]) if row+1 < row_size #S
|
28
|
-
cells.push([row+1, column+1]) if row+1 < row_size and column+1 < column_size #SE
|
29
|
-
|
30
|
-
return cells
|
31
|
-
end
|
32
|
-
end
|
3
|
+
=begin
|
4
|
+
Wordgrid is useful for sucking the life out of games like Boggle or
|
5
|
+
Scramble with Friends. Given a matrix of letters, it provides a method
|
6
|
+
named has_word? which looks in the matrix for a requested word.
|
33
7
|
|
8
|
+
Paired with a driver script that iterates over a dictionary and checks
|
9
|
+
every single word to see if it matches, then you are provided with the
|
10
|
+
full list of words in the game. That would make the game a miserable
|
11
|
+
bore, but it was fun to write.
|
12
|
+
=end
|
34
13
|
class Wordgrid
|
35
14
|
|
15
|
+
# Wordgrid.new can optionally be called with a Matrix object.
|
36
16
|
def initialize(initial_grid=Matrix[])
|
37
17
|
self.grid = initial_grid
|
38
18
|
@cell_stack = []
|
39
19
|
end
|
40
|
-
|
20
|
+
|
21
|
+
# Wordgrid.grid is the underlying matrix of letters.
|
41
22
|
attr_reader :grid
|
42
23
|
|
24
|
+
=begin
|
25
|
+
grid takes a Matrix object and validates that it is acceptable.
|
26
|
+
|
27
|
+
* *Args* :
|
28
|
+
- +new_grid+ -> the proposed new Matrix object.
|
29
|
+
* *Returns* :
|
30
|
+
- the Matrix object itself.
|
31
|
+
* *Raises* : +ArgumentError+ in the following circumstances:
|
32
|
+
- any of the cells consist of something other than single letters
|
33
|
+
- the grid is not a square
|
34
|
+
=end
|
35
|
+
|
43
36
|
def grid=(new_grid)
|
44
37
|
# make sure each cell is a single letter character
|
45
38
|
bad_cell = new_grid.find_index{|cell| cell.match(/^[^A-Za-z]$/) }
|
@@ -54,6 +47,24 @@ class Wordgrid
|
|
54
47
|
@grid = new_grid
|
55
48
|
end
|
56
49
|
|
50
|
+
=begin
|
51
|
+
has_word? is Wordgrid's raison d'être. It take a word and returns
|
52
|
+
true/false based on whether the word can be found in the grid.
|
53
|
+
|
54
|
+
has_word? makes sure not to re-trace its steps when looking for a word.
|
55
|
+
So, for example, it will find "BEAD" in the following grid, but it will
|
56
|
+
not find "BEADED":
|
57
|
+
A B C
|
58
|
+
D E F
|
59
|
+
G H I
|
60
|
+
|
61
|
+
* *Args* :
|
62
|
+
- +word+ -> the word to search the grid for
|
63
|
+
* *Returns* :
|
64
|
+
- +true+, if the word has been found, and +false+ otherwise
|
65
|
+
* *Raises* :
|
66
|
+
- Nothing
|
67
|
+
=end
|
57
68
|
def has_word?(word)
|
58
69
|
@letters = word.split('')
|
59
70
|
first_cells = @grid.find_cells_for_letter(@letters[0])
|
@@ -70,6 +81,10 @@ class Wordgrid
|
|
70
81
|
end
|
71
82
|
|
72
83
|
=begin
|
84
|
+
find_next_letter_in_neighborhood calls itself recursively to look for
|
85
|
+
each letter in the word. One it finds the word, it stop the recursive
|
86
|
+
chain returning true. It follows the following plan:
|
87
|
+
|
73
88
|
1. start with a cell
|
74
89
|
2. look at all the neighbors of the cell for the next letter.
|
75
90
|
if we don't find it, move back up to try a different path (if there were other matches a cell up)
|
@@ -107,4 +122,75 @@ a final stack for "BEAD" should be: [0,1], [1,1], [0,0], [1,0]
|
|
107
122
|
@cell_stack.pop
|
108
123
|
return false
|
109
124
|
end
|
125
|
+
private :find_next_letter_in_neighborhood
|
110
126
|
end
|
127
|
+
|
128
|
+
# Adding two helper functions to the standard Matrix class which are
|
129
|
+
# needed by the Wordgrid class.
|
130
|
+
class Matrix
|
131
|
+
|
132
|
+
=begin
|
133
|
+
Adds a method to the Matrix class which returns an array of cells
|
134
|
+
which match the string passed in. A cell is just an array with the
|
135
|
+
row and column.
|
136
|
+
|
137
|
+
* *Args* :
|
138
|
+
- +letter+ -> the character to search the matrix for.
|
139
|
+
* *Returns* :
|
140
|
+
- the cells which match the letter passed in. An array of two-value arrays.
|
141
|
+
* *Raises* :
|
142
|
+
- Nothing
|
143
|
+
=end
|
144
|
+
|
145
|
+
def find_cells_for_letter(letter)
|
146
|
+
cells = []
|
147
|
+
each_with_index do |e, row, column|
|
148
|
+
if (e == letter)
|
149
|
+
cell = [row, column]
|
150
|
+
cells.push(cell)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
return cells
|
154
|
+
end
|
155
|
+
|
156
|
+
=begin
|
157
|
+
Adds a method to the Matrix class which will find all the cells which
|
158
|
+
border the cell requested
|
159
|
+
|
160
|
+
Neighbors are defined by the cells northwest, north, northeast, west,
|
161
|
+
east, southwest, south, and southeast of the original cell. If the
|
162
|
+
original cell is on the edge of the matrix, it does not wrap. In
|
163
|
+
other words, for the following matrix:
|
164
|
+
A B C
|
165
|
+
D E F
|
166
|
+
G H I
|
167
|
+
the cell containing the letter E has the neighbors A,B,C,D,F,G,H,I.
|
168
|
+
However, the cell containing the letter A only has the neighbors
|
169
|
+
B,D,E.
|
170
|
+
|
171
|
+
* *Args* :
|
172
|
+
- +root_cell+ -> a two-element array (row, cell) identifying the cell whose neighbors we are seeking.
|
173
|
+
* *Returns* :
|
174
|
+
- an array of cells (each cell is a two-element array, containing row and cell) neighboring the original cell.
|
175
|
+
* *Raises* :
|
176
|
+
- Nothing
|
177
|
+
=end
|
178
|
+
|
179
|
+
def neighbor_cells(root_cell)
|
180
|
+
row = root_cell[0]
|
181
|
+
column = root_cell[1]
|
182
|
+
cells = []
|
183
|
+
|
184
|
+
cells.push([row-1, column-1]) if row-1 >= 0 and column-1 >= 0 #NW
|
185
|
+
cells.push([row-1, column]) if row-1 >= 0 #N
|
186
|
+
cells.push([row-1, column+1]) if row-1 >= 0 and column+1 < column_size #NE
|
187
|
+
cells.push([row, column-1]) if column-1 >=0 #W
|
188
|
+
cells.push([row, column+1]) if column+1 < column_size #E
|
189
|
+
cells.push([row+1, column-1]) if row+1 < row_size and column-1 >= 0 #SW
|
190
|
+
cells.push([row+1, column]) if row+1 < row_size #S
|
191
|
+
cells.push([row+1, column+1]) if row+1 < row_size and column+1 < column_size #SE
|
192
|
+
|
193
|
+
return cells
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|