From 598bae34bafd2709af3fcbcc65bf7c67d60e0408 Mon Sep 17 00:00:00 2001 From: jeanGaston Date: Fri, 25 Oct 2024 10:44:39 +0200 Subject: [PATCH] Update draw function to take n years of history in account --- src/draw.py | 66 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/src/draw.py b/src/draw.py index bc90994..9b452a0 100644 --- a/src/draw.py +++ b/src/draw.py @@ -1,41 +1,51 @@ from random import choice -def draw_names(previous_draw, draws_per_person): +def draw_names(current_participants, history_data, draws_per_person, max_attempts=5): """ - Perform the Secret Santa draw considering past draws. - :param previous_draw: Last year's draw data (list of participants and recipients). + Perform the Secret Santa draw considering past years' draws. + :param current_participants: This year's participant list. + :param history_data: Historical draw data to avoid repeats. :param draws_per_person: Number of people each participant should give gifts to. + :param max_attempts: Maximum number of retry attempts before loosening exclusions. by default : 5. :return: The new draw results. """ - participants = [a[0] for a in previous_draw] # Get participant names + participants = [p[0] for p in current_participants] # Get participant names already_drawn = [] # Track who has been drawn new_draw = [] # Store new draw results - for i in range(len(participants)): - giver = previous_draw[i][0] - email = previous_draw[i][1] - print(email) - last_year_r1 = previous_draw[i][2] - last_year_r2 = previous_draw[i][3] + for attempt in range(max_attempts): + new_draw.clear() + already_drawn.clear() + success = True # Track if draw is successful in this attempt - available_participants = participants.copy() - try: - available_participants.remove(giver) - available_participants.remove(last_year_r1) - available_participants.remove(last_year_r2) - except ValueError: - pass + for i, giver in enumerate(participants): + email = current_participants[i][1] + # Collect previous recipients to avoid drawing the same person again + previous_recipients = {recipient for record in history_data if record[0] == giver for recipient in record[2:]} - new_recipients = [] - while len(new_recipients) < draws_per_person: - selected = choice(available_participants) - if already_drawn.count(selected) >= draws_per_person: - available_participants.remove(selected) - else: - new_recipients.append(selected) - already_drawn.append(selected) - available_participants.remove(selected) + # Create a set of available participants excluding the giver and previous recipients + available_participants = set(participants) - {giver} - previous_recipients + new_recipients = [] - new_draw.append([giver, email] + new_recipients) + # Ensure there are enough available participants for the draw + if len(available_participants) < draws_per_person: + success = False + break - return new_draw + # Select recipients for the current giver + while len(new_recipients) < draws_per_person: + selected = choice(list(available_participants)) + if already_drawn.count(selected) < draws_per_person: + new_recipients.append(selected) + already_drawn.append(selected) + available_participants.discard(selected) + + new_draw.append([giver, email] + new_recipients) + + # If the draw was successful, break out of attempts + if success: + return new_draw + print(f"Attempt {attempt + 1} failed, retrying...") + + # If all attempts fail, raise an error + raise ValueError("Unable to complete a valid draw after maximum attempts.")