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