From: "Christoffer Lernö" Date: 2007-02-19T08:14:27+09:00 Subject: Re: [QUIZ] Housie (#114) 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