boggler 0.0.1

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.
@@ -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