[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Re: [QUIZ][SOLUTION] Secret Santas (#2

Warren Brown

10/4/2004 5:40:00 PM

Well, I originally was going to go down the "collect by family" road and
make the code deterministic, but for the intended data and intended use,
the nondeterministic approach seemed better. Also, this allows for more
"rules" to be added without changing the basic code. As an example, I
added a rule for "don't allow trades" (where two people are each other's
Santa).

For testing purposes, I added a "display results" flag and a "send
emails" flag. I also added an "override email" address/flag to send all
emails to a single email address (while keeping the "From" and "To"
headers correct).



# Required libraries
require 'net/smtp'


# Configuration settings
NO_FAMILIES = true
NO_TRADES = true
DISPLAY_RESULTS = true
SEND_EMAILS = true
SMTP_SERVER = 'yoursmtpserver.yourisp.com'
FROM_EMAIL = 'yourfromemail@yourisp.com'
OVERRIDE_EMAIL = 'youremail@yourisp.com' # nil to turn off
EMAIL_BODY = %{%{From: "Secret Santa Club" <\#{FROM_EMAIL}>
To: "\#{person.santa}" <\#{person.santa.email}>
Subject: Secret Santa

\#{person.santa.first_name},

You are Secret Santa for \#{person}.
You can email \#{person.first_name} at: mailto:\#{person.email}.
}}


# The Person structure
Person = Struct.new('Person',:first_name,:last_name,:email,:santa)
class Person; def to_s; "#{first_name} #{last_name}"; end; end


# Read people into array
people = []
while line = gets
first_name,last_name,email = line.scan(/(.*) (.*) <(.*)>/).flatten
people << Person.new(first_name,last_name,email,nil)
end

# Make sure a solution is possible
if people.length < (NO_TRADES ? 3 : 2)
puts "No solution possible. Not enough people."
exit(-1)
end
family = Hash.new(0)
people.each { |person| family[person.last_name] += 1 }
biggest_family = family.max { |a,b| a[1] <=> b[1] }
if biggest_family[1] > people.length / 2
puts "No solution possible. Family #{biggest_family[0]} is more than
half" +
" of the group (#{biggest_family[1]} out of #{people.length})."
exit(-1)
end

# Assign each person a random secret santa
pool = people.dup
people.each { |person| person.santa = pool.delete_at(rand(pool.length))
}

# For each person who has an illegal santa, switch with someone else
# Keep looping until no more illegal santas are found
begin
finished = true
people.each do |person|
if (person.santa == person) ||
(NO_FAMILIES && person.last_name == person.santa.last_name) ||
(NO_TRADES && person.santa.santa == person)
finished = false
new_person = people[rand(people.length)]
person.santa,new_person.santa = new_person.santa,person.santa
end
end
end until finished

# Output results
people.each do |person|
if DISPLAY_RESULTS
puts "#{person.santa} is secret santa for #{person}."
end
if SEND_EMAILS
Net::SMTP.start(SMTP_SERVER) do |smtp|
response = smtp.sendmail(
eval(EMAIL_BODY),
FROM_EMAIL,
OVERRIDE_EMAIL || person.santa.email
)
puts "Sent email to #{person.santa.email}, response =
'#{response.chomp}'"
end
end
end



- Warren Brown