From 8509f7eaf8812c0ccaf638550af9122a957157df Mon Sep 17 00:00:00 2001 From: Simon Junod Date: Tue, 5 Apr 2022 13:43:25 +0200 Subject: [PATCH 1/4] Normalize and clean up comments (no more superfluous empty lines) --- cambot/wordle.py | 15 +++++++-------- run.py | 12 +----------- 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/cambot/wordle.py b/cambot/wordle.py index 803b9f0..412d365 100644 --- a/cambot/wordle.py +++ b/cambot/wordle.py @@ -18,15 +18,13 @@ def validate(target, guess): copy = list(target) output = [0] * len(target) - # Look for the green squares : - + # Look for the green squares for idx in range(len(target)): if target[idx] == guess[idx]: output[idx] = 2 copy[idx] = None - # Look for the yellow squares : - + # Look for the yellow squares for idx in range(len(target)): if target[idx] == guess[idx]: continue # ignore the letters that are green @@ -60,19 +58,19 @@ class Game: async def parse(self, message): guess = unidecode(message.content.strip()).upper() - # if somebody won + # if somebody has already won, return silently if self.winner: return - # if the game was never initialized + # same if the game was never initialized if not self.target: return - # if the message is not comprised of letters (with or without accents) only + # same if the message is not comprised of letters (with or without accents) only if not re.match(r"^[A-Z]*$", guess): return - # if the guess is obviously not the same length + # same if the guess is obviously not the same length ratio = 2/3 if len(guess) <= len(self.target) * ratio or len(self.target) <= len(guess) * ratio: return @@ -87,6 +85,7 @@ class Game: await self.channel.send(f"{message.author.mention} `{guess}` n'est pas dans mon dictionnaire (ça ne compte pas comme un tour).") return + # everything is OK, validate the proposal self.tries += 1 self.last_player = message.author result = validate(self.target, guess) diff --git a/run.py b/run.py index 79f5726..1ee60cc 100755 --- a/run.py +++ b/run.py @@ -16,7 +16,6 @@ codenames_games = {} wordle_games = {} # Startup - @bot.event async def on_ready(): print(f"Connecté, nom {bot.user.name}, id {bot.user.id}") @@ -50,12 +49,10 @@ async def on_ready(): await wordle_game.reset() # Receiving a message - @bot.event async def on_message(message): # Ignore own messages - if message.author == bot.user: return @@ -63,7 +60,6 @@ async def on_message(message): content_lowercase = content.lower() # Private messages - if isinstance(message.channel, discord.channel.DMChannel): games_entered = [codenames_game for codenames_game in codenames_games.values() if codenames_game.get_player(message.author)] @@ -79,6 +75,7 @@ async def on_message(message): output += f"{wordle_game.channel.guild} > {wordle_game.channel.name} : {wordle_game.target}\n" await message.author.send(output) + # Codenames whispers if len(games_entered) == 1: await codenames.process_whisper(games_entered[0], message) elif len(games_entered) > 1: @@ -89,12 +86,10 @@ async def on_message(message): return # Help - if re.search(r"^!(aide|help|commandes)$", content_lowercase): await print_help(message.channel) # Judge something - if regex := re.search(r"^!juger (.+)$", content_lowercase): subject = regex.group(1).strip() score = int(hashlib.md5(bytes(subject.lower(), "utf-8")).hexdigest(), 16) % 2 @@ -103,7 +98,6 @@ async def on_message(message): await message.channel.send(output) # Dice - if regex := re.search(r"^!(?P\d+)?d[eé]s?(?P\d+)?$", content_lowercase): thrower = message.author.display_name maximum = 6 @@ -130,7 +124,6 @@ async def on_message(message): await message.channel.send(output) # Codenames commands - if message.channel.id in codenames_games.keys(): game = codenames_games[message.channel.id] @@ -163,12 +156,10 @@ async def on_message(message): await codenames.maybe_guess(game, message, regex.group(1)) # Wordle - if message.channel.id in wordle_games.keys(): await wordle_games[message.channel.id].parse(message) # Help - async def print_help(channel): output = """__Commandes de CamBot__ @@ -193,7 +184,6 @@ async def print_help(channel): await channel.send(output) # Let unprivileged users pin messages - async def reaction_changed(payload): emoji = payload.emoji if not emoji.is_unicode_emoji(): From 29e4b22908d002c32a41f802124054995dc43b56 Mon Sep 17 00:00:00 2001 From: Simon Junod Date: Tue, 5 Apr 2022 13:45:02 +0200 Subject: [PATCH 2/4] Don't send messages for invalid Wordle proposals; add reactions instead, and possibly multiple reactions to the same proposal if it is invalid for multiple reasons --- cambot/wordle.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/cambot/wordle.py b/cambot/wordle.py index 412d365..0c34a8e 100644 --- a/cambot/wordle.py +++ b/cambot/wordle.py @@ -75,14 +75,18 @@ class Game: if len(guess) <= len(self.target) * ratio or len(self.target) <= len(guess) * ratio: return + # check for errors and react accordingly + error = False if WORDLE_FORCE_ALTERNATION and message.author == self.last_player: - await self.channel.send(f"{message.author.mention} Laisse un peu jouer les autres !") - return + await message.add_reaction("\N{BUSTS IN SILHOUETTE}") + error = True if len(guess) != len(self.target): - await self.channel.send(f"{message.author.mention} Le mot à deviner fait {len(self.target)} lettres (ça ne compte pas comme un tour).") - return + await message.add_reaction("\N{LEFT RIGHT ARROW}") + error = True if guess not in valid_words: - await self.channel.send(f"{message.author.mention} `{guess}` n'est pas dans mon dictionnaire (ça ne compte pas comme un tour).") + await message.add_reaction("\N{EXCLAMATION QUESTION MARK}") + error = True + if error: return # everything is OK, validate the proposal From 049a343bc318eaa05020b31914949c2956a22681 Mon Sep 17 00:00:00 2001 From: Simon Junod Date: Tue, 5 Apr 2022 13:46:02 +0200 Subject: [PATCH 3/4] Put all the admin commands under one global identity test, that should be refined in the future to accept multiple admins --- run.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/run.py b/run.py index 1ee60cc..04cfa88 100755 --- a/run.py +++ b/run.py @@ -63,17 +63,22 @@ async def on_message(message): if isinstance(message.channel, discord.channel.DMChannel): games_entered = [codenames_game for codenames_game in codenames_games.values() if codenames_game.get_player(message.author)] - if content_lowercase.startswith("say ") and message.author.name == "Biganon" and message.author.discriminator == "0001": - arguments = content[4:].split(" ") - channel_id = int(arguments[0]) - to_say = " ".join(arguments[1:]) - await bot.get_channel(channel_id).send(to_say) + # Admin commands + if message.author.name == "Biganon" and message.author.discriminator == "0001": + if regex := re.search(r"^[sS]ay ([0-9]+) (.*)$", content): + channel_id = int(regex.group(1)) + to_say = regex.group(2) + await bot.get_channel(channel_id).send(to_say) - if content_lowercase == "target" and message.author.name == "Biganon" and message.author.discriminator == "0001": - output = "" - for wordle_game in wordle_games.values(): - output += f"{wordle_game.channel.guild} > {wordle_game.channel.name} : {wordle_game.target}\n" - await message.author.send(output) + if regex := re.search(r"^wordle targets?$", content_lowercase): + output = "" + for wordle_game in wordle_games.values(): + output += f"{wordle_game.channel.guild} > {wordle_game.channel.name} : {wordle_game.target}\n" + await message.author.send(output) + + if regex := re.search(r"^wordle reset ([0-9]+)$", content_lowercase): + channel_id = int(regex.group(1)) + await wordle_games[channel_id].reset() # Codenames whispers if len(games_entered) == 1: From dac2a5170f8d3d7c4d144207a32d13c1557a4e45 Mon Sep 17 00:00:00 2001 From: Simon Junod Date: Mon, 18 Apr 2022 19:26:15 +0200 Subject: [PATCH 4/4] Give away the previous target word when resetting a wordle game, if it hadn't been found. --- cambot/wordle.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cambot/wordle.py b/cambot/wordle.py index 0c34a8e..c8506fb 100644 --- a/cambot/wordle.py +++ b/cambot/wordle.py @@ -46,6 +46,9 @@ class Game: self.tried = None async def reset(self): + output = "" + if self.target and not self.winner: + output = f"Le mot précédent était : `{self.target}`\n\n" self.target = random.choice(tuple(x for x in target_words if len(x) >= WORDLE_MINLENGTH)) self.winner = None self.tries = 0 @@ -53,7 +56,8 @@ class Game: self.scores = defaultdict(int) self.tried = set() await self.channel.edit(slowmode_delay=WORDLE_SLOWMODE) - await self.channel.send(f"Il y a un nouveau mot à deviner ! Il fait {len(self.target)} lettres.") + output += f"Il y a un nouveau mot à deviner ! Il fait {len(self.target)} lettres." + await self.channel.send(output) async def parse(self, message): guess = unidecode(message.content.strip()).upper()