From: Peter McMaster Date: 2004-10-06T08:17:30+09:00 Subject: [SOLUTION] Secret Santas (#2) Hello! I realised that my implementation is rather flawed, and rather late, so decided to not bother with the less exciting SMTP bit. Also, while testing (which failed :) I was using DATA instead of STDIN. I just left it like this; I find very useful, and am keen to spread the love. (This means that the end of the file is under the "Lindsey Brigman" line, not where it says __END__) Occasionally it freaks out and is unable to assign valid santas to either the last or second-last persons, as they've already been assigned elsewhere. A cleverer friend helpfully suggested "looks like you need some cleverer algorithm"... I think that if implementing this again I'd just build two identical lists of people, and keep swapping them around randomly until it was all good. Less efficient, but more likely to eventually come up with the goods reliably. Had lots of fun doing this! - Peter #!/usr/bin/env ruby class Person attr_reader :sname, :email attr_accessor :santa def initialize(details) @fname, @sname, @email = details.scan(/(\w+)\s+(\w+)\s+<(.*)>/)[0] end def to_s() @fname + " " + @sname end def status() if @santa then self.to_s + " is santa'd to " + @santa.to_s else self.to_s + " is santa-less!\a" end # Ooh... beeps. end end families = Hash.new {[]} unchosen = [] DATA.each do |l| someone = Person.new(l) families[someone.sname] <<= someone unchosen << someone end families.keys.each do |sname| choices = unchosen.dup.delete_if { |someone| someone.sname == sname } families[sname].each do |person| person.santa = unchosen.delete(choices.delete_at(rand(choices.length))) puts person.status end end __END__ Luke Skywalker Leia Skywalker Toula Portokalos Gus Portokalos Bruce Wayne Virgil Brigman Lindsey Brigman