| Class | WordFind |
| In: |
lib/wordfind.rb
|
| Parent: | Object |
Class to generate word-find type puzzles
| puzzle | [R] | |
| solution | [R] | |
| words | [R] |
an array of words, and the following options are allowed:
| :size => N: | # size of NxN puzzle matrix |
| :intersect => true|false: | # can words intersect (share letters) |
| :only => ["e","se","ne"]: | # compass directions to lay words in |
| :no => ["w","n"]: | # compass directions to not lay words in |
# File lib/wordfind.rb, line 22 def initialize(words=[], options={}) @solution = [] @words = [] @puzzle = [] @intersect = options[:intersect] || nil @size = options[:size] || 10 @lim = @size - 1 words.each {|x| add_word(x)} if options[:only] @directions = @@directions.reject {|key,val| not options['only'].include?(key) } elsif options[:no] @directions = @@directions.reject{|key,val| options['no'].include?(key) } else @directions = @@directions end end
add a word to the puzzle’s word-list (before calling create), generating warning and dropping the word if it exceeds the Matrix size
# File lib/wordfind.rb, line 46 def add_word(word) if word.length > @size STDERR.puts "Word too long, dropping <#{word}>" return nil end word.upcase! @words << word unless @words.include?(word) end
create the puzzle. warnings generated if a word isn’t successfully placed within 50 attempts — word is also dropped
# File lib/wordfind.rb, line 58 def create init @words.each {|word| success = nil 50.times { dirs = @directions.keys dir = dirs[rand(dirs.length)] success = insert_word(dir, word) break if success } unless success STDERR.puts "Word can't be placed: dropping #{word}" @words.delete(word) end } @puzzle = Marshal.load(Marshal.dump(@solution)) @puzzle.each {|arr| arr.collect!{|x| x == '*' ? @@letters[rand(@@letters.length)] : x } } end
simple formatted text output of puzzle and solution
# File lib/wordfind.rb, line 82 def to_s puzz_str = "\tWords to Find:\n" puzz_str += "\t--------------\n\n" words = @words.sort until words.empty? puzz_str += "\t" + words.slice!(0,3).join("\t") + "\n" end puzz_str += "\n" @puzzle.each {|line| puzz_str += "\t" + line.join(' ') + "\n" } return puzz_str end
given a word and direction, pick a suitable starting position
# File lib/wordfind.rb, line 107 def get_start(dir, word) len = word.length case dir when 'n' then [(0..@lim).to_a,((len - 1) .. @lim).to_a] when 's' then [(0..@lim).to_a,(0 .. (@lim - len)).to_a] when 'e' then [(0..(@lim - len)).to_a,(0..@lim).to_a] when 'w' then [((len - 1)..@lim).to_a,(0..@lim).to_a] when 'ne' then [(0..(@lim - len)).to_a,((len - 1)..@lim).to_a] when 'nw' then [((len - 1)..@lim).to_a,((len - 1)..@lim).to_a] when 'se' then [(0..(@lim - len)).to_a,(0..(@lim - len)).to_a] when 'sw' then [((len - 1)..@lim).to_a,(0..(@lim - len)).to_a] end end
initialize solution matrix of "*" characters
# File lib/wordfind.rb, line 122 def init for i in (0..@lim) @solution[i] = [] for j in (0..@lim) @solution[i] << '*' end end end
insert word into puzzle
# File lib/wordfind.rb, line 132 def insert_word(dir,word) ranges = get_start(dir,word) return nil if ranges[0].empty? || ranges[1].empty? i = ranges[1] j = ranges[0] i = i[rand(i.length)] j = j[rand(j.length)] lattice = [] reject = nil word.split(//).each {|letter| if @solution[i][j] == '*' || @solution[i][j] == letter lattice << @solution[i][j] i += @directions[dir][0] j += @directions[dir][1] else reject = 1 break end } return nil if reject i = 0 word.split(//).each {|letter| lattice[i].replace(letter) i += 1 } return 1 end