------=_Part_165006_19573430.1167788635874
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
Here is my solution. It supports ? and * as wildcard letters.
-Chunyun
Sample input:
U E W R T R B H C D
C X U Z U W R Y E R
R O C K S B A U C U
Y F K F M T Y S G E
Y S O O U N M E I M
T C G P R T I D A N
Y Z G H Q G W T U R
H B M N D X Z B U T
N T U L A T N X C E
Y B U R P Z Y X M S
Ru?y Year ro*s DAN matZ
Output:
+ + + R + + + + + +
+ + U + U + + + + +
R O C K S B + + + +
Y + + + + + Y + + +
+ + + + + + + E + M
+ + + + + + + D A N
Y + + + + + + T + R
+ B + + + + Z + U +
+ + U + + + + X + +
Y B U R + + Y + + +
Code:
#== Synopsis
#This is the solution to Ruby Quiz #107 described on
http://www.rubyquiz.com/quiz107.html.
#
#== Usage
# ruby word_search.rb
# OR
# ruby word_search.rb input_file
#
#== Author
# Chunyun Zhao(chunyun.zhao / gmail.com)
#
class WordSearch
attr_reader :found_coords
def initialize(box)
@box = box
@height = @box.size
@width = @box[0].size
end
def search_words(words)
@found_coords=[]
regexize_words(words)
each_line do |line_coords|
line_str = get_line_str(line_coords)
words.each do |word|
if line_str=~/#{word}/i
offset = $~.offset(0)
@found_coords |= line_coords[offset[0]...offset[1]]
end
end
end
end
def display_words
for x in 0...@height
for y in 0...@width
@found_coords.include?([x,y])? print(@box[x][y]):print('+')
print ' '
end
puts
end
end
private
#Generates all possible lines(represented as arrays of coordinates) from
@box , and
#calls the block with the line coordinates.
def each_line
vertical_line_proc = lambda {|x, y| [x+1, y]}
horizonal_line_proc = lambda {|x, y| [x, y+1]}
backward_diagonal_line_proc = lambda {|x, y| [x+1, y+1]}
forward_diagonal_line_proc = lambda {|x, y| [x+1, y-1]}
lines = []
#Genernates the lines starting with the top horizonal line
for y in 0...@width
lines << get_line_coords(0, y, &vertical_line_proc)
lines << get_line_coords(0, y, &backward_diagonal_line_proc)
lines << get_line_coords(0, y, &forward_diagonal_line_proc)
end
#Genernates the lines starting with the leftmost and rightmost vertical
lines
for x in 0...@height
lines << get_line_coords(x, 0, &horizonal_line_proc)
lines << get_line_coords(x, 0, &backward_diagonal_line_proc)
lines << get_line_coords(x, @width-1, &forward_diagonal_line_proc)
end
lines.each{|line_coords|yield line_coords; yield line_coords.reverse}
end
#Generates the line starting with coordinate [x,y]. It calls the block to
find the
#next position in the line. It can be used to generate snake lines if
necessary.
def get_line_coords(x, y)
line = [[x,y]]
loop do
next_x, next_y = yield x, y
@box[next_x] && @box[next_x][next_y] ? line << [next_x, next_y] :
break
x, y = next_x, next_y
end
line
end
#Gets the string represented by an array of coordinates.
def get_line_str(coords)
line_str = ''
coords.each{|x,y| line_str << @box[x][y]}
line_str
end
#Replaces ? and * with \w? and \w* in each word so that it could be used
#as the regex to support wildcard letter matching.
def regexize_words(words)
words.each {|word|word.gsub!(/(\?|\*)/, '\w\1')}
end
end
box = []
width = nil
while line=gets
break if line.strip.empty?
row = line.split
raise "The width of all the rows must be equal!" if !width.nil? and width
!= row.size
width = row.size
box << row
end
raise "You need at least enter one row of letters!" if box.empty?
words = gets.split
raise "You need at least enter one word!" if words.empty?
ws = WordSearch.new(box)
ws.search_words(words)
ws.display_words
__END__
On 12/29/06, Ruby Quiz <james / grayproductions.net> wrote:
>
> The three rules of Ruby Quiz:
>
> 1. Please do not post any solutions or spoiler discussion for this quiz
> until
> 48 hours have passed from the time on this message.
>
> 2. Support Ruby Quiz by submitting ideas as often as you can:
>
> http://www.rubyquiz.com/
>
> 3. Enjoy!
>
> Suggestion: A [QUIZ] in the subject of emails about the problem helps
> everyone
> on Ruby Talk follow the discussion. Please reply to the original quiz
> message,
> if you can.
>
>
> -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
>
> by Daniel Finnie
>
> Today's quiz would've been most useful in elementary school, where over
> half of
> the homework assignments were word search puzzles. The concept of these
> puzzles
> is simple enough that an elementary school student could understand
> it: given a
> box of letters, find a line containing the letters of a specified word in
> order.
>
> For example, find the words ruby, dan, rocks, and matz in the following
> text:
>
> U E W R T R B H C D
> C X G Z U W R Y E R
> R O C K S B A U C U
> S F K F M T Y S G E
> Y S O O U N M Z I M
> T C G P R T I D A N
> H Z G H Q G W T U V
> H Q M N D X Z B S T
> N T C L A T N B C E
> Y B U R P Z U X M S
>
> The correct answer in the correct output format:
>
> + + + R + + + + + +
> + + + + U + + + + +
> R O C K S B + + + +
> + + + + + + Y + + +
> + + + + + + + + + M
> + + + + + + + D A N
> + + + + + + + T + +
> + + + + + + Z + + +
> + + + + + + + + + +
> + + + + + + + + + +
>
> Notice that the words can go backwards and diagonally, and can intersect
> one
> another. Searching is case insensitive.
>
> The word search solver should accept input entered by the user after
> running the
> program, i.e., not exclusively through STDIN or a file, by entering the
> puzzle
> line by line, pressing return after each line. A blank line indicates the
> end of
> the puzzle and the start of the comma separated words to find. The
> following
> example shows how a user would enter the above puzzle, with descriptive
> text
> from the program removed.
>
> $ ./wordsearch.rb
> UEWRTRBHCD
> CXGZUWRYER
> ROCKSBAUCU
> SFKFMTYSGE
> YSOOUNMZIM
> TCGPRTIDAN
> HZGHQGWTUV
> HQMNDXZBST
> NTCLATNBCE
> YBURPZUXMS
>
> Ruby, rocks, DAN, matZ
>
> Now, by itself, this quiz is fairly simple, so I offer an additional
> challenge.
> Write a beautiful, extensible, and easily-modifiable program without
> looking at
> the extra credit before starting. When you're done, try implementing extra
> credit options using less than 5 or 6 (reasonable) lines of code.
>
> * An output format superior to the one given. The output format
> given
> should remain the default unless both formats don't differ on a
> textual basis. That should sound cryptic until pondered, I can't
> give too much away!
> * Allow for "snaking" of answers, in other words, the letters
> composing a word don't have to be in a straight line.
> * An option to give a hint, i.e., "The word ruby traverses the
> bottom
> left and bottom right quadrants."
> * Decide what to do with accented letters.
> * Allow for wildcard letters.
>
>
------=_Part_165006_19573430.1167788635874--