# This implementation is heavily optimized to be as fast to
# implement as possible. Please read the above sentence very
# carefull ;-) I have tried to find an implementation
# that is as simple to understand as possible, but does work.
require 'net/smtp'
Person = Struct.new("Person", :firstName, :familyName, :email)
# extract people from input stream
def readSantas(io)
santas = Array.new
io.read.scan(/(\S*)\s(\S*)\s\<(\S*)\>/) do |first, family, email|
santas.push Person.new(first, family, email)
end
santas
end
# get an ordering where each santa gets a person who is
# outside his family. This implementation is extremely simple,
# as it assumes it is always possible to find a correct solution.
# Actally it is so simple that it hurts. I would never use this
# in production-level code.
def orderPeople(santas)
isCorrectlyOrdered = false
while !isCorrectlyOrdered
# get a random order
people = santas.sort_by { rand }
# check if the random order does meet the requirements
i = 0
i += 1 while i<santas.size &&
santas[i].familyName==people[i].familyName
isCorrectlyOrdered = i<santas.size
end
people
end
# send santa a mail that he/she is responsible for person's presents
def sendMail(santa, person)
msg = ["Subject: Santa news", "\n",
"You are santa for #{person.firstName} #{person.familyName}" ]
Net::SMTP.start("localhost") do |smtp|
smtp.sendmail(msg, "santa delegator", santa.email)
end
end
if __FILE__ == $0
santas = readSantas(STDIN)
people = orderPeople(santas)
santas.each_index do |i|
santa = santas[i]
person = people[i]
puts "'#{santa.firstName} #{santa.familyName}' is santa for
'#{person.firstName} #{person.familyName}'"
# if you really want to send mails, uncomment the following
line.
#sendMail(santa, person)
end
end