Hi!

I didn't have the time to implement a complete solution, but at least I'd  
like to show my algorithm for assigning the santas.
I start by assigning a random santa to everyone without caring about the  
constraints. Then I go through the list of people and for each one not  
having a correct santa I swap santas with someone else, so that both have  
correct santas afterwards.
As far as I can see, this will only fail when no solution is possible and  
should be reasonably unbiased.

Here is the code:

class Person
   attr_reader :first, :last, :email
   attr_accessor :santa

   def initialize(line)
     m = /(\S+)\s+(\S+)\s+<(.*)>/.match(line)
     raise unless m
     @first = m[1].capitalize
     @last = m[2].capitalize
     @email = m[3]
   end

   def can_be_santa_of?(other)
     @last != other.last
   end
end

input = $stdin.read

people = []
input.each_line do |line|
   line.strip!
   people << Person.new(line) unless line.empty?
end

santas = people.dup
people.each do |person|
   person.santa = santas.delete_at(rand(santas.size))
end

people.each do |person|
   unless person.santa.can_be_santa_of? person
     candidates = people.select {|p| p.santa.can_be_santa_of?(person) &&  
person.santa.can_be_santa_of?(p)}
     raise if candidates.empty?
     other = candidates[rand(candidates.size)]
     temp = person.santa
     person.santa = other.santa
     other.santa = temp
     finished = false
   end
end

people.each do |person|
   printf "%s %s -> %s %s\n", person.santa.first, person.santa.last,  
person.first, person.last
end

-- 
exoticorn/farbrausch