From: Chunyun Zhao Date: 2007-01-03T10:43:59+09:00 Subject: Re: [QUIZ] Word Search (#107) ------=_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 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--