Here's my submission. No extra credits.
# RubyQuiz Word Search (107)
# Bob Showalter
class WordSearch
class Board < Array
def to_s
collect {|s| s.split(//).join(' ')}.join("\n")
end
end
attr_reader :board, :solution
# creates a new, empty solver
def initialize
@board = Board.new
@solution = Board.new
end
# resets the solution
def reset
@solution.clear
@board.each {|row| @solution << row.gsub(/./, '+')}
end
# checks that the board contains only letters and that it has a uniform
# rectangular shape
def validate
@board.size > 0 or raise "Board has no rows"
@board.grep(/[^A-Z]/).empty? or raise "Board contains non-letters"
w = @board.collect {|row| row.size}.uniq
w.size == 1 or raise "Board rows are not all the same length"
w.first > 0 or raise "Board has no columns"
end
# parses the board by reading lines from io until a blank line (or EOF)
# is read.
def parse(io = ARGV)
@board.clear
while line = io.gets
line = line.strip.upcase
break if line == ''
@board << line
end
validate
reset
end
# search for word. returns number of times found. solution is updated with
# all occurences.
def search(word)
found = 0
0.upto(board.size-1) do |y|
0.upto(board[y].size-1) do |x|
[-1, 0, 1].each do |dy|
[-1, 0, 1].each do |dx|
next if dx == 0 and dy == 0
found += 1 if search_for(word.strip.upcase, x, y, dx, dy)
end
end
end
end
found
end
# search for word in board starting at position (x,y) and moving in direction
# (dx,dy). returns true if found, false if not found.
def search_for(word, x, y, dx, dy)
return false if x < 0 or x >= board.first.size or y < 0 or y >= board.size
return false if board[y][x] != word[0]
prev = solution[y][x]
solution[y][x] = board[y][x]
return true if word.length <= 1
found = search_for(word[1,word.length-1], x + dx, y + dy, dx, dy)
solution[y][x] = prev unless found
found
end
# creates a new puzzle by parsing the board from io. see WordSearch#parse
def self.parse(io = ARGF)
obj = new
obj.parse(io)
obj
end
def to_s
solution.to_s
end
end
# parse the board first
p = WordSearch.parse
# parse the words until a blank line is read
words = []
while line = ARGF.gets
line = line.strip.upcase
break if line == ''
words += line.gsub(',', ' ').split
end
# submit each word and show how many times it was found
for word in words.sort.uniq
n = p.search(word)
puts word + ' was ' + (n == 0 ? 'not found' : n == 1 ? 'found once'
: "found #{n} times")
end
# show the solution
puts p