diff --git a/README.md b/README.md index 810f38c..9c359c4 100644 --- a/README.md +++ b/README.md @@ -7,11 +7,7 @@ It's best to look at the `#TODO` notes inside files. No screenshots for now, because the current interface is just temporary. To-do features: -- Easy to use API -- Multiplayer -- Interface (cards etc.) displayed as ASCII art -- Cheat system based on pure Python console -- Fully customizable rooms with custom game rules +[TODO.yml](TODO.md) #### CLI switches - `--debug` or `-D` - always shows the opponent's cards diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..837f58a --- /dev/null +++ b/TODO.md @@ -0,0 +1,20 @@ +# To-do list + +Goals: +- Easy to use API +- Multiplayer +- Interface (cards etc.) displayed as ASCII art with ncurses +- Fully customizable rooms with custom game rules + +What to implement: +- A serious queue system that supports more than two players +- Try to remember what functional cards were skipped due to lack of a queue system +- Tab-completion +- More verbose `--debug` option +- A plugin system? (like `plugins/something-trigger.py`) +- A custom rules system (`Dict[str, Any]`), this includes: + - bluffing + - option to pass when drawing cards +- A menu +- Auto-save system +- Aliases like `4B`, `*` and auto-correction like `4lbue` -> `4 BLUE` diff --git a/uno/enums.py b/uno/enums.py index 8ca865a..db2370b 100644 --- a/uno/enums.py +++ b/uno/enums.py @@ -1,4 +1,8 @@ from enum import Enum, auto +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from uno.game import Card class Type(Enum): @@ -32,31 +36,35 @@ class CardType(Type): class CardVisual: - CARD_1: str = """________________ - ▌░░░░░░░░░░░░░░▌ - ▌░░░░░░░░░░░░░░▌ - ▌░░░░░░██╗░░░░░▌ - ▌░░░░░███║░░░░░▌ - ▌░░░░░╚██║░░░░░▌ - ▌░░░░░░██║░░░░░▌ - ▌░░░░░░██║░░░░░▌ - ▌░░░░░░╚═╝░░░░░▌ - ▌░░░░░░░░░░░░░░▌ - ▌░░░░░░░░░░░░░░▌ - ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯""" - CARD_2: str = """________________ - ▌░░░░░░░░░░░░░░▌ - ▌░░░░░░░░░░░░░░▌ - ▌░░░██████╗░░░░▌ - ▌░░░╚════██╗░░░▌ - ▌░░░░█████╔╝░░░▌ - ▌░░░██╔═══╝░░░░▌ - ▌░░░███████╗░░░▌ - ▌░░░╚══════╝░░░▌ - ▌░░░░░░░░░░░░░░▌ - ▌░░░░░░░░░░░░░░▌ - ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯""" - CARD_3: str = """""" # TODO + CARD_0: str = """""" + CARD_1: str = """ + ________________ + ▌░░░░░░░░░░░░░░▌ + ▌░░░░░░░░░░░░░░▌ + ▌░░░░░░██╗░░░░░▌ + ▌░░░░░███║░░░░░▌ + ▌░░░░░╚██║░░░░░▌ + ▌░░░░░░██║░░░░░▌ + ▌░░░░░░██║░░░░░▌ + ▌░░░░░░╚═╝░░░░░▌ + ▌░░░░░░░░░░░░░░▌ + ▌░░░░░░░░░░░░░░▌ + ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ + """ + CARD_2: str = """ + ________________ + ▌░░░░░░░░░░░░░░▌ + ▌░░░░░░░░░░░░░░▌ + ▌░░░██████╗░░░░▌ + ▌░░░╚════██╗░░░▌ + ▌░░░░█████╔╝░░░▌ + ▌░░░██╔═══╝░░░░▌ + ▌░░░███████╗░░░▌ + ▌░░░╚══════╝░░░▌ + ▌░░░░░░░░░░░░░░▌ + ▌░░░░░░░░░░░░░░▌ + ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯""" + CARD_3: str = """""" CARD_4: str = """""" CARD_5: str = """""" CARD_6: str = """""" @@ -69,23 +77,6 @@ class CardVisual: CARD_WILDCARD: str = """""" CARD_REVERSE: str = """""" - def __init__(self, card): - self.card = card - - @property - def art(self) -> str: # TODO: get rid of the dictionary - types = {'1': self.CARD_1, - '2': self.CARD_2, - '3': self.CARD_3, - '4': self.CARD_4, - '5': self.CARD_5, - '6': self.CARD_6, - '7': self.CARD_7, - '8': self.CARD_8, - '9': self.CARD_9, - '+2': self.CARD_PLUS_2, - '+4': self.CARD_PLUS_4, - 'SKIP': self.CARD_SKIP, - 'WILDCARD': self.CARD_WILDCARD, - 'REVERSE': self.CARD_REVERSE} - return types.get(self.card.card_type) + def __init__(self, card: 'Card'): + self.card: 'Card' = card + self.art: str = getattr(self, self.card.card_type.name) diff --git a/uno/game.py b/uno/game.py index 83cf2de..0bcef40 100644 --- a/uno/game.py +++ b/uno/game.py @@ -35,7 +35,7 @@ def __eq__(self, other: object) -> bool: @staticmethod def from_str(value: str) -> 'Card': card_type, card_color = value.upper().split(' ') - return Card(getattr(CardType, "CARD_" + card_type.replace('+ ', 'PLUS_')), getattr(CardColor, card_color)) + return Card(getattr(CardType, "CARD_" + card_type.replace('+', 'PLUS_')), getattr(CardColor, card_color)) def playable(self, comparator: 'Card') -> bool: """ @@ -53,10 +53,9 @@ def display(self, centered: bool = False): Creates a visual representation of the card. :param centered: whether to center the card on the display, or not """ + card_to_display: str = CardVisual(self).art if centered: - card_to_display: str = '\n'.join(CardVisual(self).art).center(get_terminal_size().columns) - else: - card_to_display: str = '\n'.join(CardVisual(self).art) + card_to_display = card_to_display.center(get_terminal_size().columns) print(getattr(Fore, self.color.name) + card_to_display + Fore.RESET) diff --git a/uno/main.py b/uno/main.py index cc84ae9..d51c2a7 100644 --- a/uno/main.py +++ b/uno/main.py @@ -54,6 +54,7 @@ def main(): f"{len(game.opponent.hand)}") else: print(f"Your cards: {game.turn.hand}") + # game.last_played_card.display() print(Fore.LIGHTMAGENTA_EX + f"Current card: {game.last_played_card}", Fore.RESET) card = None card_input: str = input("Card (e.g. 4 BLUE, Enter to draw): ") @@ -76,7 +77,7 @@ def main(): print(Fore.RED + "Can't draw more cards." + Fore.RESET) else: if card_input in ('WILDCARD', '+4'): - card = Card(CardType["CARD_" + card_input.upper().replace('+', "PLUS_")], None) # TODO + card = Card(CardType["CARD_" + card_input.upper().replace('+', "PLUS_")], None) else: try: card = Card.from_str(card_input)