Class: Crucigrama::CrosswordBuilder
- Inherits:
-
Object
- Object
- Crucigrama::CrosswordBuilder
show all
- Includes:
- Positionable
- Defined in:
- lib/crucigrama/crossword_builder.rb
Constant Summary
collapse
- NOT_REPEATABLE_WORD_MINIMUM_LENGTH =
3
Instance Attribute Summary collapse
Class Method Summary
collapse
Instance Method Summary
collapse
#direction_other_than, #position
Constructor Details
Returns a new instance of CrosswordBuilder.
9
10
11
12
13
|
# File 'lib/crucigrama/crossword_builder.rb', line 9
def initialize(opts = {})
@valid_words = opts[:valid_words] || []
@crossword_class = opts[:crossword_class] || Crucigrama::Crossword
@crossword = @crossword_class.new(opts[:dimensions]||{})
end
|
Instance Attribute Details
#crossword ⇒ Object
Returns the value of attribute crossword.
8
9
10
|
# File 'lib/crucigrama/crossword_builder.rb', line 8
def crossword
@crossword
end
|
#crossword_class ⇒ Object
Returns the value of attribute crossword_class.
8
9
10
|
# File 'lib/crucigrama/crossword_builder.rb', line 8
def crossword_class
@crossword_class
end
|
#valid_words ⇒ Object
Returns the value of attribute valid_words.
8
9
10
|
# File 'lib/crucigrama/crossword_builder.rb', line 8
def valid_words
@valid_words
end
|
Class Method Details
.build_crossword(opts = {}) ⇒ Object
16
17
18
|
# File 'lib/crucigrama/crossword_builder.rb', line 16
def self.build_crossword(opts = {})
self.new(opts).build
end
|
Instance Method Details
#adyacent_words_to_position(position, direction) ⇒ Object
56
57
58
59
|
# File 'lib/crucigrama/crossword_builder.rb', line 56
def adyacent_words_to_position(position, direction)
return nil if crossword.word_at(position, direction)
[crossword.word_at(position.merge(direction => position[direction]-1), direction), crossword.word_at(position.merge(direction => position[direction]+1), direction)]
end
|
#build ⇒ Object
20
21
22
23
24
25
26
|
# File 'lib/crucigrama/crossword_builder.rb', line 20
def build
crossword.black_positions.each do |position|
set_longest_word_at(position,:horizontal) unless crossword.word_at(position, :horizontal).to_s.length > 1
set_longest_word_at(position,:vertical) unless crossword.word_at(position, :vertical).to_s.length > 1
end
crossword
end
|
#can_be_set_condition(position, direction) ⇒ Object
92
93
94
95
96
97
98
99
100
101
102
103
104
|
# File 'lib/crucigrama/crossword_builder.rb', line 92
def can_be_set_condition(position, direction)
other_direction = direction_other_than(direction)
line = crossword.line(position[other_direction], direction)
regexp_str = line[position[direction]..line.length].gsub(crossword_class::BLACK, '.')
length_regexps = regexp_str.length.times.collect {|t| Regexp.new(regexp_str[0..t])}
lambda do |word|
if word.length > length_regexps.length
false
else
word.empty? ? true : length_regexps[word.length - 1].match(word)
end
end
end
|
#not_word_destructive_condition(coordinates, direction) ⇒ Object
83
84
85
86
87
88
89
90
|
# File 'lib/crucigrama/crossword_builder.rb', line 83
def not_word_destructive_condition(coordinates, direction)
other_direction = direction_other_than(direction)
line = crossword.line(coordinates[other_direction], direction)
lambda do |word|
words_at_line = line.dup.tap{|line| line[coordinates[direction]..coordinates[direction]+word.length-1]=word}.split(crossword_class::BLACK)
words_at_line.detect{|word| valid_word?(word)==false}.nil?
end
end
|
#set_longest_word_at(word_position, direction) ⇒ Object
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
# File 'lib/crucigrama/crossword_builder.rb', line 38
def set_longest_word_at(word_position, direction)
transversal_conditions = transversal_conditions_for(word_position, direction)
not_word_destructive_condition = not_word_destructive_condition(word_position, direction)
can_be_set_condition = can_be_set_condition(word_position, direction)
already_used_words = used_words
(2..crossword.dimensions[direction]-word_position[direction]).to_a.reverse.each do |length|
restricting_word_conditions = [can_be_set_condition, *transversal_conditions[0..length-1], not_word_destructive_condition]
eligible_words = restricting_word_conditions.inject(valid_words_by_length(length) - already_used_words) do |word_list, restricting_condition|
word_list.select(&restricting_condition)
end
if word = eligible_words.sample
raise "Could not add selected #{word} to crossword:\n#{crossword}" unless crossword.add(word, word_position, direction)
return word
end
end
nil
end
|
#transversal_conditions_for(position, direction) ⇒ Object
61
62
63
64
65
66
67
68
|
# File 'lib/crucigrama/crossword_builder.rb', line 61
def transversal_conditions_for(position, direction)
(crossword.dimensions[direction] - position[direction]).times.collect do |word_index|
adyacent_words = adyacent_words_to_position(position.merge(direction => position[direction]+word_index), direction_other_than(direction))
lambda do |word|
adyacent_words.nil? || valid_word?("#{adyacent_words[0]}#{word[word_index]}#{adyacent_words[1]}")
end
end
end
|
#used_words ⇒ Object
106
107
108
|
# File 'lib/crucigrama/crossword_builder.rb', line 106
def used_words
crossword.words.reject{|word| word.length < NOT_REPEATABLE_WORD_MINIMUM_LENGTH}
end
|
#valid_word?(word) ⇒ Boolean
28
29
30
|
# File 'lib/crucigrama/crossword_builder.rb', line 28
def valid_word?(word)
word == crossword_class::BLACK || word.length == 1 || valid_words.include?(word)
end
|
#valid_words_by_length(length) ⇒ Object
def word_length_condition(length)
lambda do |word|
word.length == length
end
end
77
78
79
80
|
# File 'lib/crucigrama/crossword_builder.rb', line 77
def valid_words_by_length(length)
@valid_words_by_length ||={}
@valid_words_by_length[length] ||= valid_words.select{|word| word.length == length}
end
|
#validate ⇒ Object
33
34
35
|
# File 'lib/crucigrama/crossword_builder.rb', line 33
def validate
crossword.words.collect{|word| valid_word?(word)}.include?(false) ? false : true
end
|