```--Boundary-00hysBH18e8PRhdV
Content-Type: Multipart/Mixed;
boundaryoundary-00hysBH18e8PRhdV"

--Boundary-00hysBH18e8PRhdV
Content-Type: text/plain;
charsettf-8"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

Hi --

I must say that I'm impressed that someone wrote a solution in 20 minutes. My
first pass took about an hour, but was never quite complete b/c I felt it was
too hackish. I don't usually do these quizes, but I decided to take a good
portion of a day out of my regular routine to try to write a nice version. It
was fun, and I needed the break :)

I looked at the problem from the point of view of a cellular automata. The
main point of interest is the way in which I passively build the puzzle. As a
"cell" is queried its "type" is determined on the fly. To determine the type,
a cell must check to see what the type of its neighbors are, thus recursing
the process. The results of each cell query are cached, short-circuiting the
recursion.

T.

# crossit.rb --------------------------------------------------------

module CrossWord

CELL_WIDTH
CELL_HEIGHT

def self.build( str )
Board.new( str ).build
end

class Board
def initialize( layout )
b  ayout.upcase  # upcase and duplicate input layout
lines  .split(/\n/)  # split into array of lines of tokens
@board  ines.collect{ |line| line.scan(/[_X]/) }
@cnt # set cell counter (for numbering)
end

def height ; @height || board.length ; end
def width ; @width || board[0].length ; end

# the board builds itself as it is called upon
def board(y,x)
return nil if @board[y][x] 'P' # pending resolution
# resolution complete
return @board[y][x] if @board[y][x] ! _' and  @board[y][x] ! X'
return @board[y][x]  u' if @board[y][x] '_'
# on edge
return @board[y][x]  e' if y or x or yeight-1 or xidth-1
if @board[y][x] 'X'  # could be edge or solid
@board[y][x]  P' # mark as pending (prevents infinite recursion)
return @board[y][x]  e' if  # edge if neighbor is edge
board(y-1,x) 'e' or board(y,x+1) 'e' or
board(y+1,x) 'e' or board(y,x-1) 'e'
end
return @board[y][x]  s'  # else solid
end

# build the puzzle
def build
puzzle  uzzle.new( height, width ) # new puzzle
# edges must be done first since they clear spaces
@board.each_with_index{ |line,y|
line.each_with_index{ |cell,x|
type  oard(y,x)
puzzle.push(type,y,x,nil) if type 'e'
}
}
# buildup all the solid and fill'in pieces
@board.each_with_index{ |line,y|
line.each_with_index{ |cell,x|
type  oard(y,x)
cnt  pper_left?(type,y,x) ? (@cnt + ) : ''
puzzle.push(type,y,x,cnt) if type ! e'
} }
puzzle.to_s  # return the final product
end

# determines if a cell should be numbered
def upper_left?(type,y,x)
return false if type ! u'
return true if y 0 and board(y+1,x) 'u'
return true if x 0 and board(y,x+1) 'u'
if x ! idth-1 and board(y,x+1) 'u'
return true if board(y,x-1) 'e'
return true if board(y,x-1) 's'
end
if y ! eight-1 and board(y+1,x) 'u'
return true if board(y-1,x) 'e'
return true if board(y-1,x) 's'
end
return false
end
end

# Puzzle is a simple matrix
class Puzzle
def initialize(height, width)
@puzzle  '']  # build a blank to work on
(height*(CELL_HEIGHT-1)+1).times{ |y|
(width*(CELL_WIDTH-1)+1).times{ |x| @puzzle.last << '.' }
@puzzle << ''
}
end
def push(type,y,x,cnt)
c  pace(type,cnt)
ny   * CELL_HEIGHT - (y 0 ? 0 : y) # adjust for first line
nx   * CELL_WIDTH - (x 0 ? 0 : x)  # adjust for first column
@puzzle[ny+0][nx,CELL_WIDTH]  [0]
@puzzle[ny+1][nx,CELL_WIDTH]  [1]
@puzzle[ny+2][nx,CELL_WIDTH]  [2]
@puzzle[ny+3][nx,CELL_WIDTH]  [3]
end
def space(type,cnt)
case type
when "u"
[ "######",
"#%s#" % "#{cnt}    "[0,4],
"#    #",
"######" ]
when "s"
[ "######" ] * 4
when "e"
[ "      " ] * 4
end
end
def to_s ; @puzzle.join("\n") ; end
end
end

# ruby crossit.rb <layoutfile.cit>
if \$0 __FILE__
cwstr  il
if FileTest.file?( ARGV[0] )
File.open( ARGV[0] ) { cwstr  ets(nil) }
end
\$stdout << CrossWord.build( cwstr )
end

--Boundary-00hysBH18e8PRhdV
Content-Type: application/x-ruby;
namerossit.rb"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filenamerossit.rb"

module CrossWord

CELL_WIDTH
CELL_HEIGHT

def self.build( str )
Board.new( str ).build
end

class Board
def initialize( layout )
b  ayout.upcase  # upcase and duplicate input layout
lines  .split(/\n/)  # split into array of lines
@board  ines.collect{ |line| line.scan(/[_X]/) }  # split line into array of tokens
@cnt # set cell counter (for numbering)
end

def height ; @height || board.length ; end
def width ; @width || board[0].length ; end

# the board builds itself as it is called upon
def board(y,x)
return nil if @board[y][x] 'P' # pending resolution
return @board[y][x] if @board[y][x] ! _' and  @board[y][x] ! X' # resolution complete
return @board[y][x]  u' if @board[y][x] '_'
return @board[y][x]  e' if y or x or yeight-1 or xidth-1  # on edge
if @board[y][x] 'X'  # could be edge or solid
@board[y][x]  P' # mark as pending (prevents infinite recursion)
return @board[y][x]  e' if  # edge if neighbor is edge
board(y-1,x) 'e' or board(y,x+1) 'e' or
board(y+1,x) 'e' or board(y,x-1) 'e'
end
return @board[y][x]  s'  # else solid
end

# build the puzzle
def build
puzzle  uzzle.new( height, width ) # new puzzle
# edges must be done first since they clear spaces
@board.each_with_index{ |line,y|
line.each_with_index{ |cell,x|
type  oard(y,x)
puzzle.push(type,y,x,nil) if type 'e'
}
}
# buildup all the solid and fill'in pieces
@board.each_with_index{ |line,y|
line.each_with_index{ |cell,x|
type  oard(y,x)
cnt  pper_left?(type,y,x) ? (@cnt + ) : ''
puzzle.push(type,y,x,cnt) if type ! e'
} }
puzzle.to_s  # return the final product
end

# determines if a cell should be numbered
def upper_left?(type,y,x)
return false if type ! u'
return true if y 0 and board(y+1,x) 'u'
return true if x 0 and board(y,x+1) 'u'
if x ! idth-1 and board(y,x+1) 'u'
return true if board(y,x-1) 'e'
return true if board(y,x-1) 's'
end
if y ! eight-1 and board(y+1,x) 'u'
return true if board(y-1,x) 'e'
return true if board(y-1,x) 's'
end
return false
end

end

# Puzzle is a simple matrix
class Puzzle
def initialize(height, width)
@puzzle  '']  # build a blank to work on
(height*(CELL_HEIGHT-1)+1).times{ |y|
(width*(CELL_WIDTH-1)+1).times{ |x| @puzzle.last << '.' }
@puzzle << ''
}
end
def push(type,y,x,cnt)
c  pace(type,cnt)
ny   * CELL_HEIGHT - (y 0 ? 0 : y) # adjust for first line
nx   * CELL_WIDTH - (x 0 ? 0 : x)  # adjust for first column
@puzzle[ny+0][nx,CELL_WIDTH]  [0]
@puzzle[ny+1][nx,CELL_WIDTH]  [1]
@puzzle[ny+2][nx,CELL_WIDTH]  [2]
@puzzle[ny+3][nx,CELL_WIDTH]  [3]
end
def space(type,cnt)
case type
when "u"
[ "######",
"#%s#" % "#{cnt}    "[0,4],
"#    #",
"######" ]
when "s"
[ "######" ] * 4
when "e"
[ "      " ] * 4
end
end
def to_s ; @puzzle.join("\n") ; end
end

end

if \$0 __FILE__
cwstr  il
if FileTest.file?( ARGV[0] )
File.open( ARGV[0] ) { cwstr  ets(nil) }
end
\$stdout << CrossWord.build( cwstr )
end

--Boundary-00hysBH18e8PRhdV
Content-Type: text/plain;
charsettf-8";
nameest1.cit"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filenameest1.cit"

X _ _ _ _ X X
_ _ X _ _ _ _
_ _ _ _ X _ _
_ X _ _ X X X
_ _ _ X _ _ _
X _ _ _ _ _ X

--Boundary-00hysBH18e8PRhdV--
--Boundary-00hysBH18e8PRhdV--

```