boggler 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 86259e476a7f531b684261ce5062509d9500c37e
4
+ data.tar.gz: 7da27f1ea047c7fad9a7fa8690980435b2368b13
5
+ SHA512:
6
+ metadata.gz: b1b71f7431211d276e4a96283ab96c674e363ccb1a37eb14a6670aaa9e95ef4cc0186a0f664b1c2d3d213da2a1b04cb55a3eafc9b64f19e38d06acf3cbd5cd9b
7
+ data.tar.gz: 5653dfac6b0ba0daec843046192aa99b8accaf37b8039766cd2495c03e5367e0d7a01883de09cd380e8e6aafc49ecf9a5341876db7fd3c09baa7785c66e557b5
@@ -0,0 +1,4 @@
1
+ ��Z�A���s9Q�`��ڸ�߳�vNU:2��CW���n�-�a/��>73���j�8��B��9�\��J+Rq����V<�dZ���Z_�%'NO�zk�m
2
+ �(W��ΆƎ���m �oU��
3
+  �;�*�4�tX���;lƠe��9�-]A��.�V��v�H86��
4
+ r��‘dd��7K�<�ӓ[iA��I_5MS�S��l�j
@@ -0,0 +1,3 @@
1
+ ����V�����L���غ�(�J�²��e��Û�I��W���H!A�I���ڠ��o�p�2�
2
+ ��g�4���յم1k�,g�ac=�-Q��(g|]�W�w�6s�f����wN��J�c�:�e㺄�K]���I*(焉�T�=Z_�N똥�h@5��E=|w{+Z��� o��9
3
+ ��l�T��u�yZnRHr��Gt����݀x�D;�m��u���7/�`4��F[`H�,�>�n<
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../lib/boggler', __FILE__)
3
+ Boggler::Core.game
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../lib/boggler', __FILE__)
3
+ Boggler::Core.run
@@ -0,0 +1,24 @@
1
+ require 'set'
2
+
3
+ module Boggler
4
+ extend self
5
+
6
+ def load
7
+ require File.join(load_path, 'core')
8
+ require File.join(load_path, 'die')
9
+ require File.join(load_path, 'dice')
10
+ require File.join(load_path, 'grid')
11
+ require File.join(load_path, 'cell')
12
+ require File.join(load_path, 'dictionary')
13
+ require File.join(load_path, 'benchmarking')
14
+ require File.join(load_path, 'solver')
15
+ end
16
+
17
+ private
18
+
19
+ def load_path
20
+ @load_path ||= File.expand_path('../boggler', __FILE__)
21
+ end
22
+ end
23
+
24
+ Boggler.load
@@ -0,0 +1,15 @@
1
+ require 'benchmark'
2
+
3
+ module Boggler
4
+ module Benchmarking
5
+ extend self
6
+
7
+ def measure(description, &block)
8
+ benchmark_format = "%n\t#{Benchmark::FORMAT}"
9
+
10
+ puts Benchmark.measure(description) {
11
+ yield if block_given?
12
+ }.format(benchmark_format)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,95 @@
1
+ module Boggler
2
+ class Cell
3
+ attr_reader :row, :column, :letter, :word, :previous
4
+
5
+ MOVES = [
6
+ [-1, -1],
7
+ [-1, 0],
8
+ [-1, 1],
9
+ [ 0, -1],
10
+ [ 0, 1],
11
+ [ 1, -1],
12
+ [ 1, 0],
13
+ [ 1, 1],
14
+ ]
15
+
16
+ def initialize(
17
+ grid, row, column, dictionary = nil, used = nil, previous = nil)
18
+ @row = row
19
+ @column = column
20
+ @letter = grid[row - 1][column - 1]
21
+ @grid = grid
22
+ @previous = previous
23
+ @dictionary = dictionary || Dictionary.words
24
+
25
+ set_used used
26
+ @used[row][column] = true
27
+
28
+ @word = ((previous && previous.word) || '') + @letter
29
+ set_dictionary
30
+ end
31
+
32
+ def next_cell
33
+ begin
34
+ iterator.next
35
+ rescue StopIteration
36
+ nil
37
+ end
38
+ end
39
+
40
+ def valid_word?
41
+ !!@dictionary['']
42
+ end
43
+
44
+ def possible_word?
45
+ !!@dictionary
46
+ end
47
+
48
+ private
49
+
50
+ def set_dictionary
51
+ case word.length
52
+ when 1, 2
53
+ @dictionary = {}
54
+ when 3
55
+ @dictionary = Dictionary.words[@word]
56
+ else
57
+ @dictionary = @dictionary[@word[-1]]
58
+ end
59
+ end
60
+
61
+ def set_used(used)
62
+ @used = used && used.dup
63
+ @used ||= {}
64
+
65
+ @grid.size.times do |i|
66
+ row = used && used[i + 1] && used[i + 1].dup
67
+ @used[i + 1] = row || {}
68
+ end
69
+ end
70
+
71
+ def iterator
72
+ @iterator ||= neighbors.each
73
+ end
74
+
75
+ def neighbors
76
+ return @neighbors if @neighbors
77
+
78
+ @neighbors = []
79
+
80
+ MOVES.each do |move|
81
+ next_row = row + move.first
82
+ next_column = column + move.last
83
+
84
+ if next_row > 0 && next_row <= @grid.size &&
85
+ next_column > 0 && next_column <= @grid.size &&
86
+ !@used[next_row][next_column]
87
+ @neighbors << Cell.new(
88
+ @grid, next_row, next_column, @dictionary, @used, self)
89
+ end
90
+ end
91
+
92
+ @neighbors
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,41 @@
1
+ module Boggler
2
+ module Core
3
+ extend self
4
+
5
+ def run
6
+ start
7
+ Solver.solve @grid
8
+ end
9
+
10
+ def game
11
+ start
12
+
13
+ time = Time.now
14
+ Dictionary.words
15
+ while Time.now - time < 3 * 60 do
16
+ end
17
+
18
+ puts "\n" * 100
19
+
20
+ Solver.solve @grid
21
+ end
22
+
23
+ def seed
24
+ return @seed if defined?(@seed)
25
+ #@seed = 7567 # postdated appears
26
+ #@seed = 532183 # used for construction of grid word construction
27
+ @seed = rand(999_999)
28
+ srand @seed
29
+ @seed
30
+ end
31
+
32
+ private
33
+
34
+ def start
35
+ seed
36
+ puts "Randomized with seed #{seed}"
37
+ @grid = Grid.new
38
+ puts @grid.to_s
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,83 @@
1
+ module Boggler
2
+ module Dice
3
+ extend self
4
+
5
+ BOGGLE_DICE = [
6
+ Die.new(%W{a a c i o t}),
7
+ Die.new(%W{a h m o r s}),
8
+ Die.new(%W{e g k l u y}),
9
+ Die.new(%W{a b i l t y}),
10
+ Die.new(%W{a c d e m p}),
11
+ Die.new(%W{e g i n t v}),
12
+ Die.new(%W{g i l r u w}),
13
+ Die.new(%W{e l p s t u}),
14
+ Die.new(%W{d e n o s w}),
15
+ Die.new(%W{a c e l r s}),
16
+ Die.new(%W{a b j m o q}),
17
+ Die.new(%W{e e f h i y}),
18
+ Die.new(%W{e h i n p s}),
19
+ Die.new(%W{d k n o t u}),
20
+ Die.new(%W{a d e n v z}),
21
+ Die.new(%W{b i f o r x}),
22
+ ]
23
+
24
+ STATIC_BOGGLE = [
25
+ Die.new(%W{e g i n t v}),
26
+ Die.new(%W{e l p s t u}),
27
+ Die.new(%W{a b j m o q}),
28
+ Die.new(%W{e h i n p s}),
29
+ Die.new(%W{d k n o t u}),
30
+ Die.new(%W{a d e n v z}),
31
+ Die.new(%W{b i f o r x}),
32
+ ].shuffle
33
+
34
+ STATIC_DICE = [
35
+ Die.new(['h']),
36
+ Die.new(['e']),
37
+ Die.new(['a']),
38
+ Die.new(['r']),
39
+ STATIC_BOGGLE[0],
40
+ Die.new(['o']),
41
+ Die.new(['r']),
42
+ STATIC_BOGGLE[1],
43
+ STATIC_BOGGLE[2],
44
+ STATIC_BOGGLE[3],
45
+ Die.new(['m']),
46
+ STATIC_BOGGLE[4],
47
+ STATIC_BOGGLE[5],
48
+ STATIC_BOGGLE[6],
49
+ Die.new(['y']),
50
+ Die.new(['e']),
51
+ ]
52
+
53
+ def get(opts = {})
54
+ opts ||= {}
55
+
56
+ case opts[:method]
57
+ when :random
58
+ random_dice
59
+ when :boggle
60
+ BOGGLE_DICE.shuffle
61
+ when :big_boggle
62
+ [
63
+ BOGGLE_DICE.shuffle,
64
+ BOGGLE_DICE.shuffle,
65
+ BOGGLE_DICE.shuffle,
66
+ BOGGLE_DICE.shuffle,
67
+ ].flatten
68
+ when :static
69
+ STATIC_DICE
70
+ else
71
+ BOGGLE_DICE.shuffle
72
+ end
73
+ end
74
+
75
+ private
76
+
77
+ def random_dice
78
+ 16.times.map do
79
+ Die.new
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,76 @@
1
+ module Boggler
2
+ module Dictionary
3
+ extend self
4
+
5
+ def words
6
+ return @words if defined?(@words)
7
+
8
+ content = nil
9
+
10
+ Benchmarking.measure('dictionary') do
11
+ path = File.expand_path('../../../vendor/dictionary.txt', __FILE__)
12
+ content = File.read(path)
13
+ content = content.split("\n")
14
+ @words = words_to_hash(content)
15
+ end
16
+
17
+ @words
18
+ end
19
+
20
+ def words_to_hash(words)
21
+ hash = {}
22
+
23
+ words.each do |word|
24
+ word = word.split('')
25
+
26
+ key = word[0..2].join
27
+ letters = word[3..-1]
28
+
29
+ merge_word hash, key, word_to_hash(letters)
30
+ end
31
+
32
+ hash
33
+ end
34
+
35
+ private
36
+
37
+ def merge_word(hash, key, word_hash)
38
+ if hash[key]
39
+ merge_word_hash hash[key], word_hash
40
+ else
41
+ hash[key] = word_hash
42
+ end
43
+ end
44
+
45
+ def merge_word_hash(hash, word_hash)
46
+ hash.merge!(word_hash) do |key, old_value, new_value|
47
+ if old_value.is_a?(Hash) && new_value.is_a?(Hash)
48
+ merge_word_hash(old_value, new_value)
49
+ else
50
+ old_value || new_value
51
+ end
52
+ end
53
+ end
54
+
55
+ def word_to_hash(letters)
56
+ if letters.empty?
57
+ {'' => true}
58
+ else
59
+ letters_to_hash({}, letters)
60
+ end
61
+ end
62
+
63
+ def letters_to_hash(hash = {}, letters = [])
64
+ hash ||= {}
65
+ letters.each_with_index do |letter, i|
66
+ if letters.length > 1
67
+ hash[letter] = letters_to_hash(hash[letter], letters[(i + 1)..-1])
68
+ return hash
69
+ else
70
+ hash[letter] = {'' => true}
71
+ return hash
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,18 @@
1
+ module Boggler
2
+ class Die
3
+ def initialize(sides = [])
4
+ @sides = sides || []
5
+ @sides << random_letter if sides.empty?
6
+ end
7
+
8
+ def roll
9
+ @sides.sample
10
+ end
11
+
12
+ private
13
+
14
+ def random_letter
15
+ rand(10...36).to_s 36
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,94 @@
1
+ module Boggler
2
+ class Grid
3
+ def initialize
4
+ @grid = []
5
+
6
+ @dice = Dice.get
7
+ @size = Math.sqrt(@dice.length).to_i
8
+
9
+ build_grid
10
+ end
11
+
12
+ def to_s
13
+ row_strings = []
14
+
15
+ @grid.each do |row|
16
+ row_strings << row_string_for(row)
17
+ end
18
+
19
+ grid_string = separator
20
+ row_strings.each do |row|
21
+ grid_string += row
22
+ grid_string += separator
23
+ end
24
+
25
+ grid_string
26
+ end
27
+
28
+ def words
29
+ return @words if defined?(@words)
30
+
31
+ @words = []
32
+
33
+ @size.times do |i|
34
+ @size.times do |j|
35
+ words_starting_at(i + 1, j + 1)
36
+ end
37
+ end
38
+
39
+ @words
40
+ end
41
+
42
+ private
43
+
44
+ def words_starting_at(row, column)
45
+ start_cell = Cell.new(@grid, row, column)
46
+ words_from_cell start_cell
47
+ end
48
+
49
+ def words_from_cell(cell)
50
+ @words << cell.word if cell.valid_word?
51
+ next_cell = next_possible_cell(cell)
52
+ words_from_cell(next_cell) if next_cell
53
+ end
54
+
55
+ def next_possible_cell(cell)
56
+ return unless cell
57
+ candidate = cell && cell.next_cell
58
+ while candidate && !candidate.possible_word?
59
+ candidate = cell.next_cell
60
+ end
61
+
62
+ return candidate if candidate
63
+
64
+ next_possible_cell cell.previous
65
+ end
66
+
67
+ def build_grid
68
+ letters = []
69
+
70
+ @dice.each_with_index do |die, i|
71
+ if i % @size == 0
72
+ @grid << letters unless letters.empty?
73
+ letters = []
74
+ end
75
+
76
+ letters << die.roll
77
+ end
78
+
79
+ @grid << letters
80
+ end
81
+
82
+ def row_string_for(row)
83
+ row_string = '|'
84
+ row.each do |cell|
85
+ row_string += " #{cell.upcase} |"
86
+ end
87
+ row_string + "\n"
88
+ end
89
+
90
+ def separator
91
+ @sep ||= '-' + ('-' * (4 * @size)) + "\n"
92
+ end
93
+ end
94
+ end