mirror of https://github.com/stijndcl/didier
143 lines
4.3 KiB
Python
143 lines
4.3 KiB
Python
import enum
|
|
from dataclasses import dataclass
|
|
|
|
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__ = ["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:
|
|
"""Create the footer to put on the embed"""
|
|
today = tz_aware_now()
|
|
return f"{int_to_weekday(today.weekday())} {today.strftime('%d/%m/%Y')}"
|
|
|
|
|
|
class WordleColour(enum.IntEnum):
|
|
"""Colours for the Wordle embed"""
|
|
|
|
EMPTY = 0
|
|
WRONG_LETTER = 1
|
|
WRONG_POSITION = 2
|
|
CORRECT = 3
|
|
|
|
|
|
@dataclass
|
|
class WordleEmbed(EmbedBaseModel):
|
|
"""Embed for a Wordle game"""
|
|
|
|
guesses: list[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.word[index]:
|
|
return WordleColour.CORRECT
|
|
|
|
wrong_letter = 0
|
|
wrong_position = 0
|
|
|
|
for i, letter in enumerate(self.word.word):
|
|
if letter == guess[index] and guess[i] != guess[index]:
|
|
wrong_letter += 1
|
|
|
|
if i <= index and guess[i] == guess[index] and letter != guess[index]:
|
|
wrong_position += 1
|
|
|
|
if i >= index:
|
|
if wrong_position == 0:
|
|
break
|
|
|
|
if wrong_position <= wrong_letter:
|
|
return WordleColour.WRONG_POSITION
|
|
|
|
return WordleColour.WRONG_LETTER
|
|
|
|
def _guess_colours(self, guess: str) -> list[WordleColour]:
|
|
"""Create the colour codes for a specific guess"""
|
|
return [self._letter_colour(guess, i) for i in range(WORDLE_WORD_LENGTH)]
|
|
|
|
def colour_code_game(self) -> list[list[WordleColour]]:
|
|
"""Create the colour codes for an entire game"""
|
|
colours = []
|
|
|
|
# Add all the guesses
|
|
for guess in self.guesses:
|
|
colours.append(self._guess_colours(guess))
|
|
|
|
# Fill the rest with empty spots
|
|
for _ in range(WORDLE_GUESS_COUNT - len(colours)):
|
|
colours.append([WordleColour.EMPTY] * WORDLE_WORD_LENGTH)
|
|
|
|
return colours
|
|
|
|
def _colours_to_emojis(self, colours: list[list[WordleColour]]) -> list[list[str]]:
|
|
"""Turn the colours of the board into Discord emojis"""
|
|
colour_map = {
|
|
WordleColour.EMPTY: ":white_large_square:",
|
|
WordleColour.WRONG_LETTER: ":black_large_square:",
|
|
WordleColour.WRONG_POSITION: ":orange_square:",
|
|
WordleColour.CORRECT: ":green_square:",
|
|
}
|
|
|
|
emojis = []
|
|
for row in colours:
|
|
emojis.append(list(map(lambda char: colour_map[char], row)))
|
|
|
|
return emojis
|
|
|
|
@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=f"Wordle #{self.word.word_id + 1}")
|
|
emojis = self._colours_to_emojis(colours)
|
|
|
|
rows = [" ".join(row) for row in emojis]
|
|
|
|
# Don't reveal anything if we only want to show the colours
|
|
if not only_colours and self.guesses:
|
|
for i, guess in enumerate(self.guesses):
|
|
rows[i] += f" ||{guess.upper()}||"
|
|
|
|
# If the game is over, reveal the word
|
|
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())
|
|
|
|
return embed
|
|
|
|
|
|
@dataclass
|
|
class WordleErrorEmbed(EmbedBaseModel):
|
|
"""Embed to send error messages to the user"""
|
|
|
|
message: str
|
|
|
|
@overrides
|
|
def to_embed(self, **kwargs) -> discord.Embed:
|
|
embed = discord.Embed(colour=discord.Colour.red(), title="Wordle")
|
|
embed.description = self.message
|
|
embed.set_footer(text=footer())
|
|
return embed
|