mirror of https://github.com/stijndcl/didier
				
				
				
			Various small fixes all around
							parent
							
								
									c4ef5cd619
								
							
						
					
					
						commit
						000fa93180
					
				|  | @ -9,6 +9,7 @@ from database.schemas import WordleGuess, WordleWord | |||
| 
 | ||||
| __all__ = [ | ||||
|     "get_active_wordle_game", | ||||
|     "get_wordle_guesses", | ||||
|     "make_wordle_guess", | ||||
|     "set_daily_word", | ||||
|     "reset_wordle_games", | ||||
|  | @ -23,6 +24,12 @@ async def get_active_wordle_game(session: AsyncSession, user_id: int) -> list[Wo | |||
|     return guesses | ||||
| 
 | ||||
| 
 | ||||
| async def get_wordle_guesses(session: AsyncSession, user_id: int) -> list[str]: | ||||
|     """Get the strings of a player's guesses""" | ||||
|     active_game = await get_active_wordle_game(session, user_id) | ||||
|     return list(map(lambda g: g.guess.lower(), active_game)) | ||||
| 
 | ||||
| 
 | ||||
| async def make_wordle_guess(session: AsyncSession, user_id: int, guess: str): | ||||
|     """Make a guess in your current game""" | ||||
|     guess_instance = WordleGuess(user_id=user_id, guess=guess) | ||||
|  | @ -62,7 +69,6 @@ async def set_daily_word(session: AsyncSession, word: str, *, forced: bool = Fal | |||
|         await reset_wordle_games(session) | ||||
|     elif forced: | ||||
|         current_word.word = word | ||||
|         current_word.day = datetime.date.today() | ||||
|         session.add(current_word) | ||||
|         await session.commit() | ||||
| 
 | ||||
|  | @ -76,3 +82,4 @@ async def reset_wordle_games(session: AsyncSession): | |||
|     """Reset all active games""" | ||||
|     statement = delete(WordleGuess) | ||||
|     await session.execute(statement) | ||||
|     await session.commit() | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ from datetime import date | |||
| from sqlalchemy import select | ||||
| from sqlalchemy.ext.asyncio import AsyncSession | ||||
| 
 | ||||
| from database.crud.users import get_or_add_user | ||||
| from database.schemas import WordleStats | ||||
| 
 | ||||
| __all__ = ["get_wordle_stats", "complete_wordle_game"] | ||||
|  | @ -13,6 +14,8 @@ async def get_wordle_stats(session: AsyncSession, user_id: int) -> WordleStats: | |||
| 
 | ||||
|     If no entry is found, it is first created | ||||
|     """ | ||||
|     await get_or_add_user(session, user_id) | ||||
| 
 | ||||
|     statement = select(WordleStats).where(WordleStats.user_id == user_id) | ||||
|     stats = (await session.execute(statement)).scalar_one_or_none() | ||||
|     if stats is not None: | ||||
|  |  | |||
|  | @ -8,6 +8,8 @@ from database.crud import links, memes, ufora_courses, wordle | |||
| 
 | ||||
| __all__ = ["CacheManager", "LinkCache", "UforaCourseCache"] | ||||
| 
 | ||||
| from database.schemas import WordleWord | ||||
| 
 | ||||
| 
 | ||||
| class DatabaseCache(ABC): | ||||
|     """Base class for a simple cache-like structure | ||||
|  | @ -118,10 +120,12 @@ class UforaCourseCache(DatabaseCache): | |||
| class WordleCache(DatabaseCache): | ||||
|     """Cache to store the current daily Wordle word""" | ||||
| 
 | ||||
|     word: WordleWord | ||||
| 
 | ||||
|     async def invalidate(self, database_session: AsyncSession): | ||||
|         word = await wordle.get_daily_word(database_session) | ||||
|         if word is not None: | ||||
|             self.data = [word.word] | ||||
|             self.word = word | ||||
| 
 | ||||
| 
 | ||||
| class CacheManager: | ||||
|  |  | |||
|  | @ -4,10 +4,11 @@ import discord | |||
| from discord import app_commands | ||||
| from discord.ext import commands | ||||
| 
 | ||||
| from database.constants import WORDLE_GUESS_COUNT, WORDLE_WORD_LENGTH | ||||
| from database.crud.wordle import get_active_wordle_game, make_wordle_guess | ||||
| from database.constants import WORDLE_WORD_LENGTH | ||||
| from database.crud.wordle import get_wordle_guesses, make_wordle_guess | ||||
| from database.crud.wordle_stats import complete_wordle_game | ||||
| from didier import Didier | ||||
| from didier.data.embeds.wordle import WordleEmbed, WordleErrorEmbed | ||||
| from didier.data.embeds.wordle import WordleEmbed, WordleErrorEmbed, is_wordle_game_over | ||||
| 
 | ||||
| 
 | ||||
| class Games(commands.Cog): | ||||
|  | @ -31,14 +32,13 @@ class Games(commands.Cog): | |||
|             embed = WordleErrorEmbed(message=f"Guess must be 5 characters, but `{guess}` is {len(guess)}.").to_embed() | ||||
|             return await interaction.followup.send(embed=embed) | ||||
| 
 | ||||
|         word = self.client.database_caches.wordle_word.data[0].lower() | ||||
|         word_instance = self.client.database_caches.wordle_word.word | ||||
| 
 | ||||
|         async with self.client.postgres_session as session: | ||||
|             guesses_instances = await get_active_wordle_game(session, interaction.user.id) | ||||
|             guesses = list(map(lambda g: g.guess, guesses_instances)) | ||||
|             guesses = await get_wordle_guesses(session, interaction.user.id) | ||||
| 
 | ||||
|             # Trying to guess with a complete game | ||||
|             if (len(guesses) == WORDLE_GUESS_COUNT and guess) or word in guesses: | ||||
|             if is_wordle_game_over(guesses, word_instance.word): | ||||
|                 embed = WordleErrorEmbed( | ||||
|                     message="You've already completed today's Wordle.\nTry again tomorrow!" | ||||
|                 ).to_embed() | ||||
|  | @ -58,9 +58,14 @@ class Games(commands.Cog): | |||
|                 # just append locally | ||||
|                 guesses.append(guess) | ||||
| 
 | ||||
|             embed = WordleEmbed(guesses=guesses, word=word).to_embed() | ||||
|             embed = WordleEmbed(guesses=guesses, word=word_instance).to_embed() | ||||
|             await interaction.followup.send(embed=embed) | ||||
| 
 | ||||
|             # After responding to the interaction: update stats in the background | ||||
|             game_over = is_wordle_game_over(guesses, word_instance.word) | ||||
|             if game_over: | ||||
|                 await complete_wordle_game(session, interaction.user.id, word_instance.word in guesses) | ||||
| 
 | ||||
| 
 | ||||
| async def setup(client: Didier): | ||||
|     """Load the cog""" | ||||
|  |  | |||
|  | @ -141,8 +141,8 @@ class Tasks(commands.Cog): | |||
|     async def reset_wordle_word(self, forced: bool = False): | ||||
|         """Reset the daily Wordle word""" | ||||
|         async with self.client.postgres_session as session: | ||||
|             word = await set_daily_word(session, random.choice(tuple(self.client.wordle_words)), forced=forced) | ||||
|             self.client.database_caches.wordle_word.data = [word] | ||||
|             await set_daily_word(session, random.choice(tuple(self.client.wordle_words)), forced=forced) | ||||
|             await self.client.database_caches.wordle_word.invalidate(session) | ||||
| 
 | ||||
|     @reset_wordle_word.before_loop | ||||
|     async def _before_reset_wordle_word(self): | ||||
|  |  | |||
|  | @ -5,10 +5,22 @@ import discord | |||
| from overrides import overrides | ||||
| 
 | ||||
| from database.constants import WORDLE_GUESS_COUNT, WORDLE_WORD_LENGTH | ||||
| from database.schemas import WordleWord | ||||
| from didier.data.embeds.base import EmbedBaseModel | ||||
| from didier.utils.types.datetime import int_to_weekday, tz_aware_now | ||||
| 
 | ||||
| __all__ = ["WordleEmbed", "WordleErrorEmbed"] | ||||
| __all__ = ["is_wordle_game_over", "WordleEmbed", "WordleErrorEmbed"] | ||||
| 
 | ||||
| 
 | ||||
| def is_wordle_game_over(guesses: list[str], word: str) -> bool: | ||||
|     """Check if the current game is over or not""" | ||||
|     if not guesses: | ||||
|         return False | ||||
| 
 | ||||
|     if len(guesses) == WORDLE_GUESS_COUNT: | ||||
|         return True | ||||
| 
 | ||||
|     return word.lower() in guesses | ||||
| 
 | ||||
| 
 | ||||
| def footer() -> str: | ||||
|  | @ -31,17 +43,17 @@ class WordleEmbed(EmbedBaseModel): | |||
|     """Embed for a Wordle game""" | ||||
| 
 | ||||
|     guesses: list[str] | ||||
|     word: str | ||||
|     word: WordleWord | ||||
| 
 | ||||
|     def _letter_colour(self, guess: str, index: int) -> WordleColour: | ||||
|         """Get the colour for a guess at a given position""" | ||||
|         if guess[index] == self.word[index]: | ||||
|         if guess[index] == self.word.word[index]: | ||||
|             return WordleColour.CORRECT | ||||
| 
 | ||||
|         wrong_letter = 0 | ||||
|         wrong_position = 0 | ||||
| 
 | ||||
|         for i, letter in enumerate(self.word): | ||||
|         for i, letter in enumerate(self.word.word): | ||||
|             if letter == guess[index] and guess[i] != guess[index]: | ||||
|                 wrong_letter += 1 | ||||
| 
 | ||||
|  | @ -90,23 +102,13 @@ class WordleEmbed(EmbedBaseModel): | |||
| 
 | ||||
|         return emojis | ||||
| 
 | ||||
|     def _is_game_over(self) -> bool: | ||||
|         """Check if the current game is over or not""" | ||||
|         if not self.guesses: | ||||
|             return False | ||||
| 
 | ||||
|         if len(self.guesses) == WORDLE_GUESS_COUNT: | ||||
|             return True | ||||
| 
 | ||||
|         return self.word.lower() in self.guesses | ||||
| 
 | ||||
|     @overrides | ||||
|     def to_embed(self, **kwargs) -> discord.Embed: | ||||
|         only_colours = kwargs.get("only_colours", False) | ||||
| 
 | ||||
|         colours = self.colour_code_game() | ||||
| 
 | ||||
|         embed = discord.Embed(colour=discord.Colour.blue(), title="Wordle") | ||||
|         embed = discord.Embed(colour=discord.Colour.blue(), title=f"Wordle #{self.word.word_id + 1}") | ||||
|         emojis = self._colours_to_emojis(colours) | ||||
| 
 | ||||
|         rows = [" ".join(row) for row in emojis] | ||||
|  | @ -117,8 +119,8 @@ class WordleEmbed(EmbedBaseModel): | |||
|                 rows[i] += f"   ||{guess.upper()}||" | ||||
| 
 | ||||
|             # If the game is over, reveal the word | ||||
|             if self._is_game_over(): | ||||
|                 rows.append(f"\n\nThe word was **{self.word.upper()}**!") | ||||
|             if is_wordle_game_over(self.guesses, self.word.word): | ||||
|                 rows.append(f"\n\nThe word was **{self.word.word.upper()}**!") | ||||
| 
 | ||||
|         embed.description = "\n\n".join(rows) | ||||
|         embed.set_footer(text=footer()) | ||||
|  |  | |||
|  | @ -121,13 +121,12 @@ async def test_make_wordle_guess(postgres: AsyncSession, user: User): | |||
| 
 | ||||
|     guess = "guess" | ||||
|     await crud.make_wordle_guess(postgres, test_user_id, guess) | ||||
|     wordle_guesses = await crud.get_active_wordle_game(postgres, test_user_id) | ||||
|     assert list(map(lambda x: x.guess, wordle_guesses)) == [guess] | ||||
|     assert crud.get_wordle_guesses(postgres, test_user_id) == [guess] | ||||
| 
 | ||||
|     other_guess = "otherguess" | ||||
|     await crud.make_wordle_guess(postgres, test_user_id, other_guess) | ||||
|     wordle_guesses = await crud.get_active_wordle_game(postgres, test_user_id) | ||||
|     assert list(map(lambda x: x.guess, wordle_guesses)) == [guess, other_guess] | ||||
|     await crud.get_active_wordle_game(postgres, test_user_id) | ||||
|     assert crud.get_wordle_guesses(postgres, test_user_id) == [guess, other_guess] | ||||
| 
 | ||||
| 
 | ||||
| @pytest.mark.postgres | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue