Created
December 6, 2012 20:08
-
-
Save jlipps/4227872 to your computer and use it in GitHub Desktop.
Randomized "Secret Santa" gift exchange generator with advanced behaviors, enables complete anonymity, allowing organizer to participate
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from collections import OrderedDict | |
from random import randint | |
import smtplib | |
FROM = "Santa Claus <[email protected]>" | |
PARTICIPANTS = OrderedDict([ | |
('Dasher', '[email protected]'), | |
('Dancer', '[email protected]'), | |
('Prancer', '[email protected]'), | |
('Vixen', '[email protected]'), | |
('Comet', '[email protected]'), | |
('Cupid', '[email protected]'), | |
]) | |
# if you want certain people to avoid giving gifts to others, say to prevent | |
# significant others from getting each other | |
AVOIDS = [ | |
('Prancer', 'Vixen'), | |
('Dasher', 'Dancer'), | |
('Comet', 'Cupid') | |
] | |
def get_participant_by_index(i): | |
j = 0 | |
for (name, email) in PARTICIPANTS.iteritems(): | |
if j == i: | |
return (name, email) | |
j += 1 | |
raise IndexError("Couldn't find participant at index %s" % i) | |
def get_participant_index_by_name(name): | |
i = 0 | |
for (s_name, email) in PARTICIPANTS.iteritems(): | |
if name == s_name: | |
return i | |
i += 1 | |
raise KeyError("Couldn't find participant with name %s" % name) | |
def build_avoid_pairs(): | |
pairs = [] | |
for (a1, a2) in AVOIDS: | |
pairs.append((get_participant_index_by_name(a1), | |
get_participant_index_by_name(a2))) | |
return pairs | |
def get_index_map(): | |
num_parts = len(PARTICIPANTS) | |
found_map = False | |
avoids = build_avoid_pairs() | |
# This is pretty ugly, and not guaranteed to find a solution in every case. | |
# Could run forever. Seems to work well in cases I've tried. | |
while not found_map: | |
print "Looking for giving map" | |
avail_froms = [x for x in xrange(0, num_parts)] | |
avail_tos = [x for x in xrange(0, num_parts)] | |
pairs = [] | |
while len(avail_froms): | |
rand_from_index = randint(0, len(avail_froms) - 1) | |
rand_from = avail_froms[rand_from_index] | |
del avail_froms[rand_from_index] | |
found_match = False | |
while not found_match: | |
rand_to_index = randint(0, len(avail_tos) - 1) | |
rand_to = avail_tos[rand_to_index] | |
if rand_to != rand_from or len(avail_tos) == 1: | |
pairs.append((rand_from, rand_to)) | |
del avail_tos[rand_to_index] | |
found_match = True | |
found_map = True | |
for pair in pairs: | |
if pair[1] == pair[0]: | |
print "\tFound self-giving, retrying..." | |
found_map = False | |
break | |
else: | |
rev_pair = (pair[1], pair[0]) | |
for other_pair in [p for p in pairs if p != pair]: | |
if other_pair == rev_pair: | |
found_map = False | |
print "\tFound mutual giving, retrying..." | |
break | |
if not found_map: | |
break | |
for avoid_pair in avoids: | |
if pair[0] in avoid_pair and pair[1] in avoid_pair: | |
found_map = False | |
print "\tFound giving we should avoid, retrying..." | |
break | |
print "Found good map!" | |
return pairs | |
def email(pairs): | |
print "Emailing participants..." | |
subject = "Your Secret Santa gift exchange recipient" | |
text = ("Hi, %s!\n\nThe person you have for the gift exchange is: %s\n\n" | |
"Best Regards,\nSanta Claus") | |
server = smtplib.SMTP('localhost') | |
for pair in pairs: | |
(giver_name, email) = get_participant_by_index(pair[0]) | |
(givee_name, _) = get_participant_by_index(pair[1]) | |
to_email = "%s <%s>" % (giver_name, email) | |
body = "\r\n".join(( | |
"From: %s" % FROM, | |
"To: %s" % to_email, | |
"Subject: %s" % subject, | |
"", | |
text % (giver_name, givee_name) | |
)) | |
server.sendmail(FROM, [to_email], body) | |
print "\tE-mailed %s" % to_email | |
server.quit() | |
def print_map(pairs): | |
print "Giving map is:" | |
for pair in pairs: | |
(giver_name, _) = get_participant_by_index(pair[0]) | |
(givee_name, _) = get_participant_by_index(pair[1]) | |
print "\t%s -> %s" % (giver_name, givee_name) | |
def ensure_uniqueness(): | |
names = [p for p in PARTICIPANTS.keys()] | |
if len(names) != len(set(names)): | |
raise Exception("There is a duplicate name in the participants, this " | |
"causes things to break") | |
if __name__ == "__main__": | |
ensure_uniqueness() | |
giving_pairs = get_index_map() | |
prompt = "Do you want to see the giving map [y/N]? " | |
if raw_input(prompt).strip() in ['y', 'Y']: | |
print_map(giving_pairs) | |
prompt = "Do you want to e-mail the participants [Y/n]? " | |
if raw_input(prompt).strip() in ['y', 'Y', '']: | |
email(giving_pairs) | |
print "Done. Happy holidays!" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment