Class: Crucigrama::CrosswordBuilder
- Inherits:
-
Object
- Object
- Crucigrama::CrosswordBuilder
- Includes:
- Positionable
- Defined in:
- lib/crucigrama/crossword_builder.rb
Overview
TODO:
document everything!
Direct Known Subclasses
Constant Summary collapse
- NOT_REPEATABLE_WORD_MINIMUM_LENGTH =
3
Instance Attribute Summary collapse
-
#crossword ⇒ Object
readonly
Returns the value of attribute crossword.
-
#crossword_class ⇒ Object
readonly
Returns the value of attribute crossword_class.
-
#valid_words ⇒ Object
readonly
Returns the value of attribute valid_words.
Class Method Summary collapse
Instance Method Summary collapse
- #adyacent_words_to_position(position, direction) ⇒ Object
- #build ⇒ Object
- #can_be_set_condition(position, direction) ⇒ Object
-
#initialize(opts = {}) ⇒ CrosswordBuilder
constructor
A new instance of CrosswordBuilder.
- #not_word_destructive_condition(coordinates, direction) ⇒ Object
- #set_longest_word_at(word_position, direction) ⇒ Object
- #transversal_conditions_for(position, direction) ⇒ Object
- #used_words ⇒ Object
- #valid_word?(word) ⇒ Boolean
-
#valid_words_by_length(length) ⇒ Object
def word_length_condition(length) lambda do |word| word.length == length end end.
- #validate ⇒ Object
Methods included from Positionable
#direction_other_than, #position
Constructor Details
#initialize(opts = {}) ⇒ CrosswordBuilder
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 (readonly)
Returns the value of attribute crossword.
8 9 10 |
# File 'lib/crucigrama/crossword_builder.rb', line 8 def crossword @crossword end |
#crossword_class ⇒ Object (readonly)
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 (readonly)
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
TODO:
rename to not_word_invalidating_condition ?
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
TODO:
return both the word and the position it was placed at ?
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
TODO:
Remove ?
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
TODO:
remove method ?
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 |