parent
7c46e612f4
commit
c53ace7eba
@ -1,4 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings" defaultProject="true" />
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
|
@ -0,0 +1,168 @@
|
||||
import csv
|
||||
import smtplib
|
||||
from email.mime.text import MIMEText
|
||||
from random import shuffle
|
||||
|
||||
# 1. Load participants from CSV, now including id and last_match_id
|
||||
def load_participants(filename):
|
||||
participants = []
|
||||
with open(filename, 'r') as file:
|
||||
reader = csv.DictReader(file)
|
||||
for row in reader:
|
||||
participants.append({
|
||||
'id': int(row['id']),
|
||||
'name': row['name'],
|
||||
'household': row['household'],
|
||||
'email': row['email'],
|
||||
'last_match_id': int(row['last_match_id']) if row['last_match_id'] else None
|
||||
})
|
||||
return participants
|
||||
|
||||
# 2. Backtracking algorithm to find valid matches
|
||||
def find_matches(givers, receivers, matches, used_receivers):
|
||||
if len(matches) == len(givers):
|
||||
return True # Found a complete set of matches
|
||||
|
||||
giver = givers[len(matches)] # Process the next giver
|
||||
|
||||
for receiver in receivers:
|
||||
# Check constraints: different person, different household, no last-year match, no reciprocal match
|
||||
if receiver['id'] not in used_receivers and \
|
||||
giver['id'] != receiver['id'] and \
|
||||
giver['household'] != receiver['household'] and \
|
||||
giver['last_match_id'] != receiver['id'] and \
|
||||
matches.get(receiver['id']) != giver['id']:
|
||||
|
||||
# Assign receiver to giver
|
||||
matches[giver['id']] = receiver
|
||||
used_receivers.add(receiver['id'])
|
||||
|
||||
# Recurse with the next giver
|
||||
if find_matches(givers, receivers, matches, used_receivers):
|
||||
return True # Solution found
|
||||
|
||||
# Backtrack: remove the match and try another receiver
|
||||
del matches[giver['id']]
|
||||
used_receivers.remove(receiver['id'])
|
||||
|
||||
return False # No valid match found, backtrack
|
||||
|
||||
# 3. Wrapper function to initialize and run the backtracking
|
||||
def generate_complete_matches(participants):
|
||||
givers = participants.copy()
|
||||
receivers = participants.copy()
|
||||
shuffle(givers) # Shuffle for variety
|
||||
shuffle(receivers) # Shuffle for variety
|
||||
|
||||
matches = {}
|
||||
used_receivers = set()
|
||||
|
||||
# Start backtracking
|
||||
if find_matches(givers, receivers, matches, used_receivers):
|
||||
return matches
|
||||
else:
|
||||
print("Could not find a complete set of matches.")
|
||||
return None
|
||||
|
||||
# 4. Confirm matches interactively
|
||||
def confirm_matches(participants, matches):
|
||||
print("Proposed Matches:")
|
||||
for giver_id, receiver in matches.items():
|
||||
giver = next(p for p in participants if p['id'] == giver_id)
|
||||
print(f"{giver['name']} ({giver['email']}) will give a gift to {receiver['name']} ({receiver['email']})")
|
||||
response = input("Approve this match? (yes/no): ").strip().lower()
|
||||
if response != 'yes':
|
||||
print("Match not approved. Restarting the matching process...\n")
|
||||
return False # Signal to restart if any match is disapproved
|
||||
return True
|
||||
|
||||
# 5. Final confirmation to save matches
|
||||
def final_confirmation(participants, matches):
|
||||
print("\nFinal Match List:")
|
||||
for giver_id, receiver in matches.items():
|
||||
giver = next(p for p in participants if p['id'] == giver_id)
|
||||
print(f"{giver['name']} will give a gift to {receiver['name']}")
|
||||
|
||||
# Final save prompt
|
||||
response = input("\nDo you want to save this match list? (yes to save, no to restart): ").strip().lower()
|
||||
return response == 'yes'
|
||||
|
||||
# 6. Update last matches in the CSV file
|
||||
def update_last_match_in_file(participants, matches, filename):
|
||||
for giver_id, receiver in matches.items():
|
||||
for participant in participants:
|
||||
if participant['id'] == giver_id:
|
||||
participant['last_match_id'] = receiver['id']
|
||||
|
||||
with open(filename, 'w', newline='') as file:
|
||||
fieldnames = ['id', 'name', 'household', 'email', 'last_match_id']
|
||||
writer = csv.DictWriter(file, fieldnames=fieldnames)
|
||||
writer.writeheader()
|
||||
for participant in participants:
|
||||
writer.writerow({
|
||||
'id': participant['id'],
|
||||
'name': participant['name'],
|
||||
'household': participant['household'],
|
||||
'email': participant['email'],
|
||||
'last_match_id': participant['last_match_id']
|
||||
})
|
||||
print("Matches saved to 'participants.csv'.")
|
||||
|
||||
# 7. Email sending function
|
||||
# 7. Email sending function with improved formatting
|
||||
def send_emails(matches, participants, sender_email, smtp_server, smtp_port, login, password):
|
||||
for giver_id, receiver in matches.items():
|
||||
giver = next(p for p in participants if p['id'] == giver_id)
|
||||
|
||||
# Compose email
|
||||
subject = "Dein Wichtel-Match für dieses Jahr"
|
||||
message = (
|
||||
f"Hallo liebe/r {giver['name']},\n\n"
|
||||
f"Dein Match für das diesjährige Wichteln ist {receiver['name']}.\n\n"
|
||||
"Mit freundlichen Grüßen,\n"
|
||||
"Dein Wichtelsystem\n\n"
|
||||
"--Bitte beachtet, dass ungefähr für 25€ gewichtelt wird--"
|
||||
)
|
||||
|
||||
# Prepare email
|
||||
msg = MIMEText(message, 'plain')
|
||||
msg['Subject'] = subject
|
||||
msg['From'] = sender_email
|
||||
msg['To'] = giver['email']
|
||||
|
||||
# Send email
|
||||
try:
|
||||
with smtplib.SMTP(smtp_server, smtp_port) as server:
|
||||
server.starttls() # Secure the connection
|
||||
server.login(login, password)
|
||||
server.sendmail(sender_email, giver['email'], msg.as_string())
|
||||
print(f"Email sent to {giver['name']} at {giver['email']}")
|
||||
except Exception as e:
|
||||
print(f"Error sending email to {giver['name']} ({giver['email']}): {e}")
|
||||
|
||||
|
||||
# 8. Main function to run the match process
|
||||
def main():
|
||||
participants = load_participants('participants.csv')
|
||||
while True:
|
||||
matches = generate_complete_matches(participants)
|
||||
if matches and confirm_matches(participants, matches):
|
||||
if final_confirmation(participants, matches):
|
||||
update_last_match_in_file(participants, matches, 'participants.csv')
|
||||
|
||||
# Send emails after saving the matches
|
||||
sender_email = "weihnachtswichteln0@gmail.com" # Update to your email
|
||||
smtp_server = "smtp.gmail.com" # Update to your SMTP server
|
||||
smtp_port = 587 # Typically 587 for TLS
|
||||
login = "weihnachtswichteln0@gmail.com" # SMTP login
|
||||
password = "" # SMTP password
|
||||
|
||||
send_emails(matches, participants, sender_email, smtp_server, smtp_port, login, password)
|
||||
break
|
||||
else:
|
||||
print("\nRestarting the matching process...\n")
|
||||
else:
|
||||
print("No complete match found, restarting...\n")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Loading…
Reference in new issue