boggle 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.md +43 -0
- data/Rakefile +2 -0
- data/bin/boggle +20 -0
- data/boggle.gemspec +27 -0
- data/dicts/default.dict +0 -0
- data/dicts/scrabble.dict +0 -0
- data/dicts/system.dict +0 -0
- data/dicts/wls.tar.gz +0 -0
- data/lib/boggle.rb +7 -0
- data/lib/boggle/board.rb +121 -0
- data/lib/boggle/game.rb +165 -0
- data/lib/boggle/solver.rb +83 -0
- data/lib/boggle/trie.rb +36 -0
- data/lib/boggle/version.rb +3 -0
- metadata +96 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2011 Kirk Scheibelhut <kjs@scheibo.com>
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person ob-
|
4
|
+
taining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without restric-
|
6
|
+
tion, including without limitation the rights to use, copy, modi-
|
7
|
+
fy, merge, publish, distribute, sublicense, and/or sell copies of
|
8
|
+
the Software, and to permit persons to whom the Software is fur-
|
9
|
+
nished to do so, subject to the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
16
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONIN-
|
17
|
+
FRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
19
|
+
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# Boggle
|
2
|
+
|
3
|
+
Very dirty program to let you play 4x4 boggle and learn new words. Has the following options:
|
4
|
+
|
5
|
+
opts = Trollop::options do
|
6
|
+
opt :define, "Show a definition dump at the end", :short => 'd'
|
7
|
+
opt :interactive, "Continue printing games", :short => 'i'
|
8
|
+
opt :dictionary, "Change the default dictionary", :default => 'dicts/just_words.dict'
|
9
|
+
opt :board, "Give a string as input to be the board", :default => ""
|
10
|
+
end
|
11
|
+
|
12
|
+
Where `--interactive` has yet to be implemented, but the idea behind if would be that instead of loading up a dict each time you could continue to play with the same dictionary. Has no timer going on right now, just use a watch to time the three minutes. Use 'XYZZY' to exit any prompt (TODO: should be control-D or something as well).
|
13
|
+
|
14
|
+
As it stands, with a full scrabble dictionary load (dicts/osw.txt) it takes about 2.6 seconds to load up on
|
15
|
+
|
16
|
+
Darwin mac.local 10.6.0 Darwin Kernel Version 10.6.0: Wed Nov 10 18:13:17 PST 2010; root:xnu-1504.9.26~3/RELEASE_I386 i386
|
17
|
+
|
18
|
+
with intel core 2 duo 2.4ghz. It takes about 200MB of ram to load the dictionary into memory. With this dictionary a given board takes around 0.14 seconds to solve (same specs). 'just_words' only has around 40k words as opposed to 260k, so it ends up being considerably faster. There are some ways to optimize the solving, but at 0.14 seconds thats not really the problem, the problem is the loading which even then isn't *horrid*.
|
19
|
+
|
20
|
+
## Usage
|
21
|
+
|
22
|
+
Not actually a gem, just
|
23
|
+
|
24
|
+
git clone git://github.com/scheibo/boggle.git
|
25
|
+
cd boggle
|
26
|
+
./boggle
|
27
|
+
|
28
|
+
## Future
|
29
|
+
|
30
|
+
- timer (3 min countdown)
|
31
|
+
- interactive mode (save loading the dict)
|
32
|
+
- Ctrl+D to exit
|
33
|
+
|
34
|
+
## Copyright
|
35
|
+
|
36
|
+
Hopefully Parker Brothers (Hasbro) isn't going to get mad I've recreated their game. All copyright, trademarks, etc belong to them.
|
37
|
+
|
38
|
+
All the dictionaries are property of whoever compiled them, and hopefully I'm not breaking any copyright by including them in this program (I just took most of them off of [wordlists.sourceforge.com](http://wordlists.sourceforge.com)).
|
39
|
+
|
40
|
+
As for the code to the game itself:
|
41
|
+
|
42
|
+
`boggle` is Copyright (c) 2011 [Kirk Scheibelhut](http://scheibo.com/about) and distributed under the MIT license.<br />
|
43
|
+
See the `LICENSE` file for further details regarding licensing and distribution.
|
data/Rakefile
ADDED
data/bin/boggle
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
lib = File.expand_path('../../lib', __FILE__)
|
3
|
+
$:.unshift(lib) if File.directory?(lib) && !$:.include?(lib)
|
4
|
+
|
5
|
+
require 'boggle'
|
6
|
+
require 'optparse'
|
7
|
+
|
8
|
+
opts = {}
|
9
|
+
ARGV.options do |argv|
|
10
|
+
argv.banner = "Usage: boggle [options]"
|
11
|
+
argv.on("-d", "--define", "Show a definition dump at the end") { |d| opts[:define] = d }
|
12
|
+
argv.on("--dictionary", String, "Change the default dictionary") { |dict| opts[:dictionary] = dict }
|
13
|
+
argv.on("-b", "--board", String, "Give a string as input to be the board") { |b| opts[:board] = b }
|
14
|
+
argv.on("-v", "--variant", Integer, "Give the board variant") { |v| opts[:variant] = v }
|
15
|
+
argv.on("-s", "--size", Integer, "Give the size of the board to use") { |s| opts[:size] = s }
|
16
|
+
end
|
17
|
+
|
18
|
+
opts = {:dictionary => "system.dict", :board => "", :variant => 0, :size => 4}.merge opts
|
19
|
+
opts[:size] = Math.sqrt(opts[:board].size).to_i if !opts[:board].empty?
|
20
|
+
Boggle::Game.new(Boggle::Board.new(opts), opts).start
|
data/boggle.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "boggle/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "boggle"
|
7
|
+
s.version = Boggle::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Kirk Scheibelhut"]
|
10
|
+
s.email = ["kjs@scheibo.com"]
|
11
|
+
s.homepage = "https://github.com/scheibo/boggle"
|
12
|
+
s.summary = "Boggle CLI app which helps improve your game"
|
13
|
+
s.description = s.summary
|
14
|
+
|
15
|
+
s.rubyforge_project = "boggle"
|
16
|
+
|
17
|
+
s.add_dependency "algorithms"
|
18
|
+
|
19
|
+
s.add_development_dependency "rake"
|
20
|
+
s.add_development_dependency "bundler", "~> 1.0.0"
|
21
|
+
|
22
|
+
s.files = `git ls-files`.split("\n")
|
23
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
24
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
25
|
+
s.default_executable = 'boggle'
|
26
|
+
s.require_paths = ["lib"]
|
27
|
+
end
|
data/dicts/default.dict
ADDED
Binary file
|
data/dicts/scrabble.dict
ADDED
Binary file
|
data/dicts/system.dict
ADDED
Binary file
|
data/dicts/wls.tar.gz
ADDED
Binary file
|
data/lib/boggle.rb
ADDED
data/lib/boggle/board.rb
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
class Boggle::Board
|
2
|
+
attr_reader :size
|
3
|
+
|
4
|
+
def initialize(opts={})
|
5
|
+
@size = opts[:size]
|
6
|
+
if opts[:board].empty?
|
7
|
+
letters = Boggle::Board.distributions(@size, opts[:variant]).sort_by{ rand }.map { |d| d.sample }
|
8
|
+
else
|
9
|
+
letters = letters_from_string opts[:board]
|
10
|
+
end
|
11
|
+
|
12
|
+
@board = []
|
13
|
+
@size.times do
|
14
|
+
@board << letters.pop(@size)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
s = ""
|
20
|
+
@size.times { s<<"+"; s<<"-"*3 }; s<<"+\n"
|
21
|
+
@size .times do |row|
|
22
|
+
s << "|"
|
23
|
+
@size.times do |col|
|
24
|
+
(l=@board[row][col]) == "Qu" ? s << " #{l}|" : s << " #{l} |"
|
25
|
+
end
|
26
|
+
s<<"\n"; @size.times { s<<"+"; s<<"-"*3 }; s<<"+\n"
|
27
|
+
end
|
28
|
+
s
|
29
|
+
end
|
30
|
+
|
31
|
+
def [](row, col)
|
32
|
+
( (row < 0) || (col < 0) || (row >= @size) || (col >= @size) ) ? nil : @board[row][col]
|
33
|
+
end
|
34
|
+
|
35
|
+
# deepcopy first
|
36
|
+
def []=(row, col, val)
|
37
|
+
@board[row][col]=val
|
38
|
+
end
|
39
|
+
|
40
|
+
def deepcopy
|
41
|
+
Marshal.load( Marshal.dump(self) )
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.distributions( size, variant ) # 4,0 gives standard distrubtion
|
45
|
+
|
46
|
+
distros = [[
|
47
|
+
# http://everything2.com/title/Boggle
|
48
|
+
%w{
|
49
|
+
ASPFFK NUIHMQ OBJOAB LNHNRZ
|
50
|
+
AHSPCO RYVDEL IOTMUC LREIXD
|
51
|
+
TERWHV TSTIYD WNGEEH ERTTYL
|
52
|
+
OWTOAT AEANEG EIUNES TOESSI
|
53
|
+
},
|
54
|
+
|
55
|
+
# http://www.boardgamegeek.com/thread/300565/review-from-a-boggle-veteran-and-beware-differen
|
56
|
+
%w{
|
57
|
+
AAEEGN ELRTTY AOOTTW ABBJOO
|
58
|
+
EHRTVW CIMOTV DISTTY EIOSST
|
59
|
+
DELRVY ACHOPS HIMNQU EEINSU
|
60
|
+
EEGHNW AFFKPS HLNNRZ DEILRX
|
61
|
+
},
|
62
|
+
|
63
|
+
%w{
|
64
|
+
AACIOT AHMORS EGKLUY ABILTY
|
65
|
+
ACDEMP EGINTV GILRUW ELPSTU
|
66
|
+
DENOSW ACELRS ABJMOQ EEFHIY
|
67
|
+
EHINPS DKNOTU ADENVZ BIFORX
|
68
|
+
}
|
69
|
+
],[
|
70
|
+
|
71
|
+
# http://boardgamegeek.com/thread/300883/letter-distribution
|
72
|
+
%w{
|
73
|
+
aaafrs aaeeee aafirs adennn aeeeem
|
74
|
+
aeegmu aegmnn afirsy bjkqxz ccenst
|
75
|
+
ceiilt ceilpt ceipst ddhnot dhhlor
|
76
|
+
dhlnor dhlnor eiiitt emottt ensssu
|
77
|
+
fiprsy gorrvw iprrry nootuw ooottu
|
78
|
+
}.map(&:upcase),
|
79
|
+
|
80
|
+
%w{
|
81
|
+
AAAFRS AAEEEE AAFIRS ADENNN AEEEEM
|
82
|
+
AEEGMU AEGMNN AFIRSY BJKQXZ CCNSTW
|
83
|
+
CEIILT CEILPT CEIPST DHHNOT DHHLOR
|
84
|
+
DHLNOR DDLNOR EIIITT EMOTTT ENSSSU
|
85
|
+
FIPRSY GORRVW HIPRRY NOOTUW OOOTTU
|
86
|
+
}
|
87
|
+
]]
|
88
|
+
|
89
|
+
min_size = 4
|
90
|
+
distros[size-min_size].map { |dist|
|
91
|
+
dist.map { |die|
|
92
|
+
die.split(//).map { |letter|
|
93
|
+
# our distrubutions return Qu, not Q's
|
94
|
+
letter == 'Q' ? 'Qu' : letter
|
95
|
+
}
|
96
|
+
}
|
97
|
+
}[variant]
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
def letters_from_string(string)
|
103
|
+
letters = []
|
104
|
+
row = []
|
105
|
+
string.each_char do |c|
|
106
|
+
if c == "Q"
|
107
|
+
row << "Qu"
|
108
|
+
elsif c == "u"
|
109
|
+
row
|
110
|
+
else
|
111
|
+
row << c
|
112
|
+
end
|
113
|
+
if row.size == @size
|
114
|
+
letters << row
|
115
|
+
row = []
|
116
|
+
end
|
117
|
+
end
|
118
|
+
letters.reverse.flatten
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
data/lib/boggle/game.rb
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__) + '/../boggle')
|
2
|
+
|
3
|
+
require 'zlib'
|
4
|
+
require 'trie'
|
5
|
+
|
6
|
+
class Boggle::Game
|
7
|
+
|
8
|
+
def self.create_dictionary(file_name)
|
9
|
+
trie = Boggle::Trie.new
|
10
|
+
File.open(file_name).each_line do |line|
|
11
|
+
idx = line.index " " # get first space
|
12
|
+
if idx.nil? # no definition
|
13
|
+
word, defn = line, "no definition available"
|
14
|
+
else
|
15
|
+
word, defn = line[0..idx-1], line[idx+1..line.size]
|
16
|
+
end
|
17
|
+
#word.chomp! # case where we had just words on the line
|
18
|
+
|
19
|
+
# skip words that are too small for boggle
|
20
|
+
if word.size > 2
|
21
|
+
trie[word.upcase] = defn
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
dump = Marshal.dump(trie)
|
26
|
+
dict_file = File.new(File.expand_path("../../../dicts/#{file_name.chomp('.txt')}.dict", __FILE__), "w")
|
27
|
+
dict_file = Zlib::GzipWriter.new(dict_file)
|
28
|
+
dict_file.write dump
|
29
|
+
dict_file.close
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize(board=nil, opts=nil)
|
33
|
+
if ! board.nil?
|
34
|
+
@board = board
|
35
|
+
else
|
36
|
+
@board = Boggle::Board.new
|
37
|
+
end
|
38
|
+
@opts = opts
|
39
|
+
@words = []
|
40
|
+
@trie = Boggle::Trie.new
|
41
|
+
end
|
42
|
+
|
43
|
+
def start
|
44
|
+
dict = @opts[:dictionary]
|
45
|
+
fill_trie(dict) # need to only load this once
|
46
|
+
s = Boggle::Solver.new(@trie)
|
47
|
+
@found_pairs = s.start(@board)
|
48
|
+
|
49
|
+
display
|
50
|
+
|
51
|
+
good = []
|
52
|
+
bad = []
|
53
|
+
@words.uniq.each do |w|
|
54
|
+
if @found_pairs.delete w
|
55
|
+
good << w
|
56
|
+
else
|
57
|
+
bad << w
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
finish good, bad
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def score(words)
|
67
|
+
words.reduce(0) { |a,w| a+score_word(w) }
|
68
|
+
end
|
69
|
+
|
70
|
+
def finish(good, bad)
|
71
|
+
puts "Your score was: #{score(good)}"
|
72
|
+
puts "The following words were bad:"
|
73
|
+
bad.each { |b| print "#{b} " }
|
74
|
+
puts
|
75
|
+
|
76
|
+
puts "You missed the following words"
|
77
|
+
dump_words
|
78
|
+
end
|
79
|
+
|
80
|
+
def dump_words
|
81
|
+
already_done = []
|
82
|
+
words = []
|
83
|
+
@found_pairs.keys.sort.each do |word|
|
84
|
+
if @found_pairs.include? word+"S"
|
85
|
+
words << [word, "#{word}(S)"]
|
86
|
+
already_done << word+"S"
|
87
|
+
else
|
88
|
+
words << [word, word] unless already_done.include? word
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# now we need to make our groups
|
93
|
+
groups =[[],[],[],[],[],[]] # 3, 4, 5, 6, 7, 8+
|
94
|
+
words.sort_by { |e| e.first.size }.each do |pk|
|
95
|
+
case pk[0].size
|
96
|
+
when 3 then groups[0] << pk[1]
|
97
|
+
when 4 then groups[1] << pk[1]
|
98
|
+
when 5 then groups[2] << pk[1]
|
99
|
+
when 6 then groups[3] << pk[1]
|
100
|
+
when 7 then groups[4] << pk[1]
|
101
|
+
else groups[5] << pk[1]
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
puts
|
106
|
+
groups.each do |group|
|
107
|
+
break_after = 0
|
108
|
+
group.each do |rep|
|
109
|
+
print "#{rep} "
|
110
|
+
break_after+=rep.size
|
111
|
+
if break_after > 80
|
112
|
+
print "\n"
|
113
|
+
break_after = 0
|
114
|
+
end
|
115
|
+
end
|
116
|
+
print "\n\n" unless group.empty?
|
117
|
+
end
|
118
|
+
|
119
|
+
if @opts[:define]
|
120
|
+
@found_pairs.keys.sort.each { |word| puts "#{word}: #{@found_pairs[word]}" }
|
121
|
+
else
|
122
|
+
|
123
|
+
while true
|
124
|
+
print "Define: "
|
125
|
+
word = STDIN.gets.chomp.upcase
|
126
|
+
if word == "XYZZY"
|
127
|
+
break
|
128
|
+
else
|
129
|
+
puts "#{word}: #{@trie[word]}"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def display
|
137
|
+
puts @board
|
138
|
+
while true
|
139
|
+
word = STDIN.gets.chomp.upcase
|
140
|
+
if word == "XYZZY"
|
141
|
+
break
|
142
|
+
else
|
143
|
+
@words << word
|
144
|
+
end
|
145
|
+
end
|
146
|
+
puts "Finished, you put down #{@words.size} words"
|
147
|
+
end
|
148
|
+
|
149
|
+
def fill_trie(file_name)
|
150
|
+
file = Zlib::GzipReader.open(File.expand_path("../../../dicts/#{file_name}", __FILE__))
|
151
|
+
@trie = Marshal.load file.read
|
152
|
+
file.close
|
153
|
+
end
|
154
|
+
|
155
|
+
def score_word(word)
|
156
|
+
case word.size
|
157
|
+
when 0,1,2 then 0
|
158
|
+
when 3,4 then 1
|
159
|
+
when 5 then 2
|
160
|
+
when 6 then 3
|
161
|
+
when 7 then 5
|
162
|
+
else 11
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__) + '/../boggle')
|
2
|
+
require 'trie'
|
3
|
+
require 'game'
|
4
|
+
|
5
|
+
class Boggle::Solver
|
6
|
+
|
7
|
+
def initialize(trie)
|
8
|
+
@found_words = {} # going to use it like a set
|
9
|
+
@trie = trie
|
10
|
+
end
|
11
|
+
|
12
|
+
def in_trie?(prefix)
|
13
|
+
if (d = @trie.match(prefix.upcase)) # not nil = okay
|
14
|
+
if d.class == String
|
15
|
+
@found_words[prefix] = d
|
16
|
+
end
|
17
|
+
true
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def start(board)
|
22
|
+
solve board
|
23
|
+
@found_words
|
24
|
+
end
|
25
|
+
|
26
|
+
def solve(board)
|
27
|
+
board.size.times do |row|
|
28
|
+
board.size.times do |col|
|
29
|
+
solve_frame(make_frame("", board, row, col))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def make_frame(prefix, board, row, col)
|
37
|
+
frame = []
|
38
|
+
frame << (prefix + board[row,col])
|
39
|
+
new_board = board.deepcopy
|
40
|
+
new_board[row,col] = nil
|
41
|
+
frame << new_board
|
42
|
+
frame << row << col
|
43
|
+
frame
|
44
|
+
end
|
45
|
+
|
46
|
+
def solve_frame(frame)
|
47
|
+
next_frames(frame).each do |f|
|
48
|
+
prefix, b, r, c = f
|
49
|
+
|
50
|
+
if in_trie? prefix
|
51
|
+
# continue
|
52
|
+
solve_frame(f)
|
53
|
+
end
|
54
|
+
# otherwise we're at a dead end!, ignore the frame
|
55
|
+
# and continue to the other ones
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def next_frames(frame)
|
60
|
+
# unpack
|
61
|
+
pre, board, row, col = frame
|
62
|
+
|
63
|
+
frames = []
|
64
|
+
# row before
|
65
|
+
frames << (board[row-1, col-1] && make_frame(pre, board, row-1, col-1))
|
66
|
+
frames << (board[row-1, col ] && make_frame(pre, board, row-1, col ))
|
67
|
+
frames << (board[row-1, col+1] && make_frame(pre, board, row-1, col+1))
|
68
|
+
|
69
|
+
# same row
|
70
|
+
frames << (board[row , col-1] && make_frame(pre, board, row , col-1))
|
71
|
+
# frames << (board[row , col ] && make_frame(pre, board, row, col ))
|
72
|
+
# is guaranteed to be nil, since at row,col we are empty
|
73
|
+
frames << (board[row , col+1] && make_frame(pre, board, row , col+1))
|
74
|
+
|
75
|
+
# row after
|
76
|
+
frames << (board[row+1, col-1] && make_frame(pre, board, row+1, col-1))
|
77
|
+
frames << (board[row+1, col ] && make_frame(pre, board, row+1, col ))
|
78
|
+
frames << (board[row+1, col+1] && make_frame(pre, board, row+1, col+1))
|
79
|
+
|
80
|
+
frames.compact
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
data/lib/boggle/trie.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'algorithms'
|
2
|
+
|
3
|
+
class Boggle::Trie < Containers::Trie
|
4
|
+
|
5
|
+
# returns either nil if there is nothing along that path, true
|
6
|
+
# if that path exists in the tree and the word itself if it is an endpoint
|
7
|
+
|
8
|
+
def match(string)
|
9
|
+
string = string.to_s
|
10
|
+
return nil if string.empty?
|
11
|
+
match_recursive(@root, string, 0)
|
12
|
+
end
|
13
|
+
|
14
|
+
def match_recursive(node, string, index)
|
15
|
+
return nil if node.nil?
|
16
|
+
|
17
|
+
char = string[index]
|
18
|
+
|
19
|
+
if (char < node.char)
|
20
|
+
match_recursive(node.left, string, index)
|
21
|
+
elsif (char > node.char)
|
22
|
+
match_recursive(node.right, string, index)
|
23
|
+
else
|
24
|
+
return nil if node.nil?
|
25
|
+
if index == (string.length - 1)
|
26
|
+
if node.last?
|
27
|
+
return node.value
|
28
|
+
else
|
29
|
+
return true
|
30
|
+
end
|
31
|
+
end
|
32
|
+
match_recursive(node.mid, string, index+1)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
metadata
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: boggle
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Kirk Scheibelhut
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-01-22 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: algorithms
|
16
|
+
requirement: &70186838444600 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70186838444600
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rake
|
27
|
+
requirement: &70186838475640 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70186838475640
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: bundler
|
38
|
+
requirement: &70186838475140 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.0.0
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70186838475140
|
47
|
+
description: Boggle CLI app which helps improve your game
|
48
|
+
email:
|
49
|
+
- kjs@scheibo.com
|
50
|
+
executables:
|
51
|
+
- boggle
|
52
|
+
extensions: []
|
53
|
+
extra_rdoc_files: []
|
54
|
+
files:
|
55
|
+
- .gitignore
|
56
|
+
- Gemfile
|
57
|
+
- LICENSE
|
58
|
+
- README.md
|
59
|
+
- Rakefile
|
60
|
+
- bin/boggle
|
61
|
+
- boggle.gemspec
|
62
|
+
- dicts/default.dict
|
63
|
+
- dicts/scrabble.dict
|
64
|
+
- dicts/system.dict
|
65
|
+
- dicts/wls.tar.gz
|
66
|
+
- lib/boggle.rb
|
67
|
+
- lib/boggle/board.rb
|
68
|
+
- lib/boggle/game.rb
|
69
|
+
- lib/boggle/solver.rb
|
70
|
+
- lib/boggle/trie.rb
|
71
|
+
- lib/boggle/version.rb
|
72
|
+
homepage: https://github.com/scheibo/boggle
|
73
|
+
licenses: []
|
74
|
+
post_install_message:
|
75
|
+
rdoc_options: []
|
76
|
+
require_paths:
|
77
|
+
- lib
|
78
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
79
|
+
none: false
|
80
|
+
requirements:
|
81
|
+
- - ! '>='
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
|
+
none: false
|
86
|
+
requirements:
|
87
|
+
- - ! '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
requirements: []
|
91
|
+
rubyforge_project: boggle
|
92
|
+
rubygems_version: 1.8.6
|
93
|
+
signing_key:
|
94
|
+
specification_version: 3
|
95
|
+
summary: Boggle CLI app which helps improve your game
|
96
|
+
test_files: []
|