В этом году друзья поручили мне организовать Тайного Санты в этом году. Обычно это не моя роль. Но человек, который обычно его организовывает, уехал в Англию, чтобы выпить чаю и встретиться с королевой. Вы можете спросить, а почему бы просто не написать имена на листах бумаги, скомкать их и засунуть в шапку? Почему ты не делаешь это так, как поступили бы нормальные люди? Однако вы могли заметить или не заметить, но в настоящее время мы находимся в пандемии. Нет нормального способа что-то сделать, если только вы не имеете в виду новую нормальность. Поэтому мне нужно было сделать его бесконтактным и простым в выполнении - я ОЧЕНЬ ленивый.
Мы могли бы наклеить имена в шляпу и выбирать имена одно за другим. Однако а) в нашей группе более 5 человек, и это было бы незаконно, и б) это требует времени, и если я выберу свое имя, и нам придется перезапустить, я, вероятно, заплачу от боли. Я мог бы просто присваивать имена, но это означает, что меня не интересуют. Ни подарков для меня, ни выяснения того, кто кого достал с моими супер-детективными способностями. Я не мог этого сделать. Нет, я знал, что мне нужно создать алгоритм для этого на Python!
Итак, я подошел к чертежной доске и составил список функций программы:
- Получите имена и адреса электронной почты всех участников и сохраните их.
- Назначьте каждому участнику Тайного Санты, убедившись, что у каждого есть чужое имя.
- Отправляйте всем их распределения по электронной почте для поистине бесконтактного опыта!
Во-первых, мне нужно было найти библиотеки Python, необходимые для работы. Их было довольно много:
import re import random import smtplib from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText
Библиотека random была предназначена для того, чтобы я мог использовать функцию randint для рандомизации распределения секретного Санты. Остальные библиотеки были необходимы для раздела электронной почты моей программы. Библиотека re была так, чтобы я мог проверить электронную почту!
Я также инициализировал несколько переменных:
sender_address = 'email' sender_pass = 'password' names = [] emails = [] recipient = [] budget = 50 count = 0
Затем мне нужно было решить, как мне добавить имена и адреса электронной почты в программу. Я решил использовать два метода ввода данных:
- Через текстовый файл (.txt): пользователь создает текстовый файл с определенным форматом имени, электронной почты. В каждой новой строке появляется новый участник, и программа обработает текстовый файл и сохранит всех участников в списках.
- Ввод вручную: пользователь вручную вводит имя и адрес электронной почты каждого участника, и программа будет предлагать ему («Введите имя участника 1:», «Введите адрес электронной почты участника 1:» и т. д.) .
Вот как выглядит код ввода данных (включая проверку!):
# asks the for data entry method print("""Welcome to the secret santa decision-maker! How would you like to enter the information? 1. give a text (.txt) file with format of: name, email address 2. manually enter information""") x = 0 while(x == 0): try: option = int(input("Info entry method (1 or 2): ")) if(option > 2 or option < 1): print("ERROR: You can only input 1 or 2!") print("""How would you like to enter the information? 1. give a text (.txt) file 2. manually enter information""") else: x = 1 except ValueError: print("ERROR: Please input 1 or 2!") print("""How would you like to enter the information? 1. give a text (.txt) file 2. manually enter information""") # gets the number of participants x = 0 while(x == 0): try: count = int(input("Enter number of participants: ")) if(count < 2): print("ERROR: Number of participants must be 2 or more!") else: x = 1 except ValueError: print("ERROR: Please input a valid integer number!") # option 1: read the file (assumes file format is correct) if(option == 1): x = 0 while(x == 0): filename = str(input("Name of text file (must end in .txt): ")) if (filename[-4:] == '.txt'): x = 1 else: print("ERROR: Please input a file name which ends with .txt") text = open(filename, "r") for i in range(0, count): info = text.readline().split(', ') names.append(info[0]) emails.append(info[1]) # option 2: manually get info (assumes email is correct) elif(option == 2):# for validating an Email regex =
'^[a-z0-9]+[\._]?[a-z0-9]+[@]\w+[.]\w{2,3}$'
print("Ok! It's time for you to input the participants' information!") for i in range(1, count + 1): name = str(input(f'Enter participant the name of participant {i}: ')) names.append(name) x = 0 while(x == 0): email = str(input(f'Enter the email of participant {i}: '))if(re.search(regex, email)):
emails.append(email) x = 1 else: print("ERROR: invalid email!")
Пришло время для основного направления программы: раздачи подарков Тайному Санту. Сначала я продублировал список имен - из этого списка я бы выбрал распределения и удалил имя после того, как оно было выделено. Затем я использовал цикл for, чтобы просмотреть каждое имя в списке имена и определить, кого они могли бы назвать Тайным Санта-Клаусом. Чтобы решить это, я бы использовал функцию randint из встроенной библиотеки Python random. Это случайное число представляет индекс получателя. Затем я добавляю имя получателя в список получателей. Однако было несколько случаев, на которые мне пришлось обратить внимание:
- Если имя получателя совпадает с именем Тайного Санты. Это невозможно, потому что ты не можешь быть самим собой секретный Санта! Поэтому я устанавливаю аргумент if, else. Если имена совпадают, программа снова запустит функцию randint, чтобы выбрать другой индекс.
- Если единственное оставшееся имя получателя совпадает с именем Тайного Санты. Если я продолжу использовать функцию randint, я застряну в бесконечном цикле, поскольку другого выхода нет! Поэтому у меня есть еще один оператор if, проверяющий, равна ли длина списка possible_santa 1 (что означает, что программа должна быть запущена снова). Это устанавливает для логического значения повтора значение Истина, позволяя программе запускаться снова.
possible_santa = names.copy() cont = 0 while(cont == 0): redo = False possible_santa = names.copy() for i in range(0, len(names)): recip = random.randint(0, len(possible_santa) - 1) x = 0 while(x == 0): if(names[i] == possible_santa[recip]): if(len(possible_santa) == 1): redo = True x = 1 else: recip = random.randint(0, len(possible_santa) - 1) else: x = 1 if(redo != True): recipient.append(possible_santa[recip]) possible_santa.pop(recip) cont = 1 else: cont = 0
Теперь, когда распределения были установлены, мне нужно было отправить их участникам по электронной почте! Для этого я использовал SMTP - в Python есть встроенная библиотека для отправки электронной почты smtplib. Я также использовал email.mime.multipart и email.mime.text - другие библиотеки Python. Я использовал этот веб-сайт: https://www.freecodecamp.org/news/send-emails-using-code-4fcea9df63f/ для справки, и это было действительно полезно!
Вот фрагмент кода с некоторыми комментариями, которые, я надеюсь, все объяснят!
# this code must run for each name for i in range(0, count): # the message which will be sent in the email mail_content = f'''Hello {names[i]}, You are the secret santa of {recipient[i]}! Remember the budget is ${budget} ''' # sets the email address the email will be sent to receiver_address = emails[i] # sets up the MIME message = MIMEMultipart() message['From'] = sender_address # your email address message['To'] = receiver_address # Secret Santa's email address message['Subject'] = 'Secret Santa' # subject of the # sets the body of the mail message.attach(MIMEText(mail_content, 'plain')) # creates the SMTP session for sending the mail session = smtplib.SMTP('smtp.gmail.com', 587) session.connect("smtp.gmail.com", 587) session.ehlo() session.starttls() session.login(sender_address, sender_pass) text = message.as_string() session.sendmail(sender_address, receiver_address, text) session.quit()
Я также хотел создать текстовый файл, в котором будут сохранены распределения на случай, если что-то пойдет не так! Это гарантирует, что я могу все перепроверить и у нас есть резервный список.
Для этого все, что я сделал, - это создал новый текстовый файл, используя функцию открытия. Затем я использовал цикл for, чтобы перебрать каждого Secret Santa и получателя и записать каждое выделение в новую строку файла! Убедитесь, что вы также закрыли текстовый файл!
allocations = open("SantaAllocations.txt", "w+") for i in range(0, len(names)): allocations.write(f'{names[i]} is the secret santa of {recipient[i]}\n') allocations.close()
Это не единственный способ создать этот генератор, и если вы можете придумать другие способы, дайте мне знать!
Мне не терпится использовать эту программу и получить все подарки, и я надеюсь, что вам понравится ее кодирование и использование! Счастливого Рождества, и если вам это понравилось, загляните в мой блог https://itsliterallymonique.wordpress.com/, чтобы узнать больше об этом!
Если вы хотите загрузить этот код, он находится в этом репозитории github: https://github.com/moniquethemuffin/Secret-Santa-Generator