From: jim@... Date: 2004-12-05T16:31:22+09:00 Subject: Re: [QUIZ][SOLUTION] Crosswords (#10) Here is my solution. This took a few more LOC than I expected. #!/usr/bin/env ruby class CrossWordPuzzle CELL_WIDTH = 6 CELL_HEIGHT = 4 attr_accessor :cell_width, :cell_height def initialize(file) @file = file @cell_width = CELL_WIDTH @cell_height = CELL_HEIGHT build_puzzle end ####### private ####### def build_puzzle parse_grid_file drop_outer_filled_boxes create_numbered_grid end def parse_grid_file @grid = File.read(@file).split(/\n/) @grid.collect! { |line| line.split } @grid_width = @grid.first.size @grid_height = @grid.size end def drop_outer_filled_boxes loop { changed = 0 changed += _drop_outer_filled_boxes(@grid) changed += _drop_outer_filled_boxes(t = @grid.transpose) @grid = t.transpose break if 0 == changed } end def _drop_outer_filled_boxes(ary) changed = 0 ary.collect! { |row| r = row.join changed += 1 unless r.gsub!(/^X|X$/, ' ').nil? changed += 1 unless r.gsub!(/X | X/, ' ').nil? r.split(//) } changed end def create_numbered_grid mark_boxes(@grid) grid_prime = @grid.transpose mark_boxes(grid_prime) count = '0' @numbered_grid = [] @grid.each_with_index { |row, i| r = [] row.each_with_index { |col, j| r << case col + grid_prime[j][i] when /#/ then count.succ!.dup else col end } @numbered_grid << r } end # place '#' in boxes to be numbered def mark_boxes(grid) grid.collect! { |row| r = row.join r.gsub!(/([X ])([\#_]{2,})/) { "#{$1}##{$2[1..-1]}" } r.gsub!(/^([\#_]{2,})/) { |m| m[0]=?#; m } r.split(//) } end def cell(data) c = [] case data when 'X' @cell_height.times { c << ['#'] * @cell_width } when ' ' @cell_height.times { c << [' '] * @cell_width } when /\d/ tb = ['#'] * @cell_width n = sprintf("\#%-*s\#", @cell_width-2, data).split(//) m = sprintf("#%-#{@cell_width-2}s#", ' ').split(//) c << tb << n (@cell_height-3).times { c << m } c << tb when '_' tb = ['#'] * @cell_width m = ['#'] + [' ']*(@cell_width-2) + ['#'] c << tb (@cell_height-2).times { c << m } c << tb end c end def overlay(sub, mstr, x, y) sub.each_with_index { |row, i| row.each_with_index { |data, j| mstr[y+i][x+j] = data unless '#' == mstr[y+i][x+j] } } end def to_s puzzle_width = (@cell_width-1) * @grid_width + 1 puzzle_height = (@cell_height-1) * @grid_height + 1 s = Array.new(puzzle_height) { Array.new(puzzle_width) << [] } @numbered_grid.each_with_index { |row, i| row.each_with_index { |data, j| overlay(cell(data), s, j*(@cell_width-1), i*(@cell_height-1)) } } s.collect! { |row| row.join }.join("\n") end public :to_s end#class CrossWordPuzzle cwp = CrossWordPuzzle.new(ARGV.shift) puts cwp.to_s -- Jim Freeze Code Red. Code Ruby