Not very elegant, but it's a minimal fix to my original solution so  
that each ticket has at least a single value in each column.


/C


class Housie

   def initialize
     @colset = Array.new(9) { [] }
     @numbers = 0
   end

   # Push a number to this ticket.
   #
   # If this number can't fit with the numbers already in this  
housie, we return
   # one of the old numbers in the housie that we removed to make  
this number fit.
   #
   def push(number)
     raise "Tried to push to generated housie ticket" if @housie
     column = number == 90 ? 8 : number / 10
     @colset[column] << number
     if @colset[column].size == 4
       @colset[column].shift
     elsif @numbers == 15
       random_col = rand(9) while random_col.nil? || @colset 
[random_col].size < 2
       @colset[random_col].shift
     else
       @numbers += 1
       nil
     end
   end

   # Generates a ticket from added data
   # Since we have 15 numbers, not more than 3 of each column type we  
know we
   # can create a ticket, but we want a randomized look to it.
   def generate
     raise "Not enough data to generate ticket" unless complete?
     @housie = Array.new(3) { Array.new(9) }
     (0..8).sort_by { rand }.each do |column|
       @colset[column].size.times do
         rows = @housie.sort_by { rand }.sort { |row1, row2|  
row1.compact.size <=> row2.compact.size }
         rows.shift until rows.first[column].nil?
         rows.first[column] = true
       end
     end
     9.times do |column|
       @colset[column].sort!
       @housie.each { |row| row[column] = @colset[column].shift if row 
[column] }
     end
     self
   end

   # Ugly code to display a ticket.
   def to_s
     return "Not valid" unless @housie
     @housie.inject("") do |sum, row|
       sum + "+----" * 9 + "+\n" +
       row.inject("|") { | sum, entry | sum + " #{"%2s" % entry} |" }  
+ "\n"
     end +
     "+----" * 9 + "+"
   end

   def complete?
     @numbers == 15
   end

   def Housie.new_book
     housies = Array.new(6) { Housie.new }
     numbers = Array.new(9) { |col| Array.new(10) { |i| i + col * 10 } }
     numbers[0].delete 0
     numbers[8] << 90
     # First make sure every book has at least one entry
     numbers.each do |col|
       col.replace col.sort_by { rand }
       housies.each { |housie| housie.push(col.shift) }
     end
     # That done, distribute the rest of the numbers
     numbers.flatten!
     while numbers.size > 0 do
       pushed_out = housies[rand(6)].push(numbers.shift)
       numbers << pushed_out if pushed_out
     end
     housies.collect { |housie| housie.generate }
   end

   def Housie.new_ticket
     housie = Housie.new
     numbers = Array.new(9) { |col| Array.new(10) { |i| i + col * 10 } }
     numbers[0].delete 0
     numbers[8] << 90
     # First make sure this ticket has at least one entry
     numbers.each do |col|
       col.replace col.sort_by { rand }
       housie.push(col.shift)
     end
     # Distribute the rest of the numbers
     numbers = numbers.flatten!.sort_by { rand }
     until housie.complete?
       returned = housie.push numbers.shift
       numbers << returned if returned
     end
     housie.generate
   end

end


puts "A book of tickets:"
Housie.new_book.each_with_index { |housie, index| puts "Ticket # 
{index + 1}"; puts housie.to_s }

puts "A single ticket:"
puts Housie.new_ticket.to_s