Source code for scripts.base.cardgen

"""
PokeGambler - A Pokemon themed gambling bot for Discord.
Copyright (C) 2021 Harshith Thota

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
----------------------------------------------------------------------------

The Base Card Generation Module
"""
import os
import random
from typing import List, Optional

from PIL import Image


[docs]class CardGambler: """ The Pokecard Generator class. :param assets_path: The path to the asset folder. :type assets_path: str """ # pylint: disable=too-many-instance-attributes def __init__(self, assets_path: str = "assets"): self.asset_path = assets_path self.pokecards_path = os.path.join(self.asset_path, "pokecards") self.basecards_path = os.path.join(self.asset_path, "basecards") self.suits = os.listdir(self.pokecards_path) self.cards = os.listdir( os.path.join(self.pokecards_path, self.suits[0]) ) self.closed_card = Image.open( os.path.join(self.basecards_path, "pokecards-back.jpg") ) self.joker_card = Image.open( os.path.join(self.basecards_path, "pokecards-joker.jpg") ) self.watermark = Image.open( os.path.join(self.basecards_path, "pokecards-watermark.png") )
[docs] def get_card(self, suit: str, card: str) -> Image.Image: """Gets the image of a specific card. :param suit: The suit of the card. :type suit: str :param card: The card number. :type card: str :return: The image of the card. :rtype: :class:`PIL.Image.Image` """ if ".jpg" not in card: card = f"{card.upper()}.jpg" facecard = Image.open( os.path.join(self.pokecards_path, suit, card) ).convert('RGBA') return Image.alpha_composite(facecard, self.watermark).convert('RGB')
[docs] @staticmethod def get_deck( cards: List[Image.Image], sep: Optional[str] = "auto", reverse: Optional[bool] = False ) -> Image.Image: """Gets a deck generated from a list of cards. :param cards: The list of cards to generate the deck from. :type cards: List[:class:`PIL.Image.Image`] :param sep: The seperation width, defaults to "auto" :type sep: Optional[str] :param reverse: Stack the cards in reverse?, defaults to False :type reverse: Optional[bool] :return: The deck image. :rtype: :class:`PIL.Image.Image` """ width, height = cards[0].size if sep == "auto": sep = width // 2 deck_size = (width + sep * (len(cards) - 1), height) deck = Image.new("RGB", deck_size, (0, 0, 0)) if reverse: for i, card in enumerate(cards[::-1]): deck.paste( card, (deck_size[0] - ((i * sep) + width), 0) ) else: for i, card in enumerate(cards): deck.paste( card, ((i * sep), 0) ) return deck
[docs] def get_closed_deck( self, sep: Optional[int] = 5, num_cards: Optional[int] = 12 ) -> Image.Image: """Gets a deck of closed cards. :param sep: The seperation width, defaults to 5 :type sep: Optional[int] :param num_cards: Number of cards, defaults to 12 :type num_cards: Optional[int] :return: The closed deck image. :rtype: :class:`PIL.Image.Image` """ cards = [self.closed_card for _ in range(num_cards)] return self.get_deck(cards, sep=sep, reverse=True)
[docs] def get_random_card(self) -> Image.Image: """Alias for :func:`get_random_cards` with ``num_cards = 1``. :return: Random card. :rtype: :class:`PIL.Image.Image` """ return self.get_random_cards(num_cards=1)[0]
[docs] def get_random_cards( self, num_cards: Optional[int] = 4, joker_chance: Optional[float] = 0.05 ) -> List[Image.Image]: """Gets a list of random cards. :param num_cards: Number of cards, defaults to 4 :type num_cards: Optional[int] :param joker_chance: Chance of including a Joker, defaults to 0.05 :type joker_chance: Optional[float] :return: A list of random cards. :rtype: List[:class:`PIL.Image.Image`] """ cards = [] joker_drawn = False for _ in range(num_cards): card = random.choice(self.cards) card_num = card.split(".jpg")[0] suit = random.choice(self.suits) while (card_num, suit) in ( (card_["card_num"], card_["suit"]) for card_ in cards ): card = random.choice(self.cards) card_num = card.split(".jpg")[0] if all([ (random.randint(1, 100) / 100) <= joker_chance, not joker_drawn ]): suit = "joker" card_num = "Joker" card_img = self.joker_card.copy() joker_drawn = True else: card_img = self.get_card(suit, card) cards.append({ "card_num": card_num, "suit": suit, "card_img": card_img }) random.shuffle(cards) return cards
[docs] def get_random_deck( self, num_cards: Optional[int] = 12, **kwargs ) -> Image.Image: """Gets a deck generated from a list of random cards. :param num_cards: Number of cards, defaults to 12 :type num_cards: Optional[int] :return: The deck image consisting of random cards. :rtype: :class:`PIL.Image.Image` """ cards = [ self.get_random_card()[1] for _ in range(num_cards) ] return self.get_deck(cards, **kwargs)