From: Andre Nathan Date: 2004-10-04T00:27:59+09:00 Subject: Re: [SOLUTION] Secret Santas (#2) Here goes mine... it has a method for sending mail which I haven't really tested, so I left the call commented and printed the information instead. Regards, Andre #!/usr/bin/env ruby require 'net/smtp' class Oops < Exception; end def split_line(line) name, surname, email = line.scan(/^(\w+)\s(\w+)\s+<(.+)>$/).flatten return name, surname, email end def choose_person(name, surname, list) person = list.find_all { |n, sn| sn != surname and n != name }.pop raise Oops if person.nil? list.delete(person) return person end def split_list(list) newlist = [] list.each { |line| newlist << split_line(line) } return newlist end def send_mail(to, name, conf) msg = <<__EOM__ From: Secret Santa Robot <#{conf[:from]}> To: #{to} Subject: Your chosen person Your chosen person is #{name}. Best regards, The Secret Santa Robot __EOM__ Net::SMTP.start(conf[:server], 25, conf[:domain], conf[:user], conf[:password], conf[:auth].intern) do |smtp| smtp.send_message msg, conf[:from], to end end # # Main # mailconf = { :server => 'smtp.secretsanta.com', :domain => 'secretsanta.com', :from => 'robot@secretsanta.com', :user => 'robot', :password => 'tobor', :auth => 'plain', } tries = 1 santas = split_list(ARGF.to_a) families = {} santas.each { |name, surname, email| families[surname] = families[surname] ? families[surname] + 1 : 1 if families[surname] > santas.length / 2 raise "Too many people from the same family." end } hash = {} begin people = santas.sort_by { rand } santas.each { |name, surname, email| pname, psname = choose_person(name, surname, people) hash[email] = "#{pname} #{psname}" } rescue Oops tries += 1 retry end #hash.each { |email, dest| send_mail(email, dest, mailconf) } hash.each { |email, dest| puts "#{email} -> #{dest}" } puts "Finished in #{tries} tries."