···11# Secret Santa CLI
2233-This is a Secret Santa game CLI tool. It takes a `.yaml` file to configure the game, setting up the participants and the exclusions.
33+This is a Secret Santa gane CLI tool. It takes a `.yaml` file to configure the game, setting up the participants and the exclusions.
4455Then, uses [Mailgun API](https://documentation.mailgun.com/docs/mailgun/user-manual/get-started/) to send the results of the draw via email.
66···54545555- `--dry`:
5656 Optional argument, to simulate the draw and not sending the results via
5757- email.5757+ email.
5858+5959+- `--seed`:
6060+ Optional argument, to define a string as the seed for the random module.
+11-1
src/secretsanta/cli.py
···2323 action="store_true",
2424 help="Simulates the game, and doesn't sends the result.",
2525 )
2626+ parser.add_argument(
2727+ "--seed",
2828+ type=str,
2929+ help="Explicit the seed for the random choices.",
3030+ default=None,
3131+ )
2632 args = parser.parse_args()
2733 config_file = Path(args.config)
2834 if not config_file.is_file():
···3137 # creates the game
3238 game = Game.create(config_file=config_file)
3339 # runs the draw
3434- draw = Draw(participants=game.participants(), exclusions=game.exclusions)
4040+ draw = Draw(
4141+ participants=game.participants(),
4242+ exclusions=game.exclusions,
4343+ seed=args.seed,
4444+ )
3545 draw.run()
3646 # notify the results
3747 notify(game=game, draw=draw, dry=args.dry)
+10-7
src/secretsanta/draws.py
···2020 solution: list[tuple[str, str]]
21212222 # available participants
2323- available: set[str]
2323+ available: list[str]
24242525 # list of pair of participants that can't be assigned
2626 exclusions: list[tuple[str, str]]
···2929 self,
3030 participants: list[str],
3131 exclusions: list[tuple[str, str]] | None = None,
3232+ seed: str | None = None,
3233 ):
3334 """Initializes the draw."""
3435 self.participants = participants
3536 self.solution = []
3636- self.available = set(participants)
3737+ self.available = participants[:]
3738 self.exclusions = exclusions or []
3939+ if seed:
4040+ random.seed(seed)
38413942 def __len__(self) -> int:
4043 """The len of the draw is the len of the current solution."""
···5962 def pick(self) -> str:
6063 """Selects the next possible participant."""
6164 if not self.solution:
6262- selected = random.choice(list(self.available))
6565+ selected = random.choice(self.available)
6366 self.available.remove(selected)
6467 else:
6568 selected = self.solution[-1][1] # select the last node in the solution
···7477 def rollback(self, candidate: tuple[str, str]) -> None:
7578 """Undoes the candidate."""
7679 self.solution.remove(candidate)
7777- if self.available:
7878- self.available.add(candidate[1])
8080+ if self.available and candidate[1] not in self.available:
8181+ self.available.append(candidate[1])
79828083 def choices(self) -> list[str]:
8184 """Shuffle list of choices."""
8282- choices = list(self.available)
8585+ choices = self.available[:]
8386 random.shuffle(choices)
8487 return choices
8588···122125 def reset(self) -> None:
123126 """Restores the draw to the initial status."""
124127 self.solution = []
125125- self.available = set(self.participants)
128128+ self.available = self.participants[:]
126129127130 def run(self) -> None:
128131 """Executes the backtrack algorithm until gets a result."""
+4-1
src/secretsanta/templates/notification.html
···2233<p>Tienes que regalar a: <strong>{{ to_name }}</strong>.</p>
4455-<p>π El Amigo Invisible π</p>
55+<p>Recuerda que hemos establecido un presupuesto de entre 20 y 25 euros.</p>
66+77+<p><strong>π Β‘Feliz Navidad! π</strong></p>
6899+<p>π El Amigo Invisible π </p>