🧹 cleaned up blackjack.py

This commit is contained in:
NikolajDanger
2021-08-24 22:28:05 +02:00
parent 225316ffed
commit 5330a51fe0
8 changed files with 679 additions and 977 deletions

1
.gitignore vendored
View File

@ -157,6 +157,7 @@ gwendolyn/resources/star_wars/destinyPoints.txt
gwendolyn/resources/plex/ gwendolyn/resources/plex/
gwendolyn/resources/games/hilo/ gwendolyn/resources/games/hilo/
gwendolyn/resources/games/blackjack_tables/ gwendolyn/resources/games/blackjack_tables/
gwendolyn/resources/games/images/
gwendolyn/resources/games/old_images/ gwendolyn/resources/games/old_images/
gwendolyn/resources/games/connect_four_boards/ gwendolyn/resources/games/connect_four_boards/
gwendolyn/resources/games/hex_boards/ gwendolyn/resources/games/hex_boards/

View File

@ -53,7 +53,7 @@ class BlackjackCog(commands.Cog):
await self.bot.games.blackjack.enter_game(ctx, bet) await self.bot.games.blackjack.enter_game(ctx, bet)
@cog_ext.cog_subcommand(**params["blackjack_stand"]) @cog_ext.cog_subcommand(**params["blackjack_stand"])
async def blackjack_stand(self, ctx, hand=""): async def blackjack_stand(self, ctx, hand=0):
"""Stand on your hand in blackjack.""" """Stand on your hand in blackjack."""
await self.bot.games.blackjack.stand(ctx, hand) await self.bot.games.blackjack.stand(ctx, hand)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,219 @@
"""Base class for the games."""
import random
from shutil import copyfile
from discord import File
from discord.abc import Messageable
from PIL import ImageFont, Image, ImageDraw
class GameBase():
"""The base class for the games."""
def __init__(self, bot):
"""Initialize the class."""
self.bot = bot
self.database = self.bot.database
self.long_strings = self.bot.long_strings
self.resources = "gwendolyn/resources/games/"
self.game_name = ""
self.old_images_path = f"{self.resources}old_images/{self.game_name}"
self.draw = BaseDrawer(bot, self)
def access_document(self, channel: str, collection_name: str="games"):
collection = self.bot.database[f"{self.game_name} {collection_name}"]
return collection.find_one({"_id": channel})
def _update_document(self, channel: str, updater: dict,
collection_name: str="games"):
self.database[f"{self.game_name} {collection_name}"].update_one(
{"_id": channel},
updater,
upsert=True
)
def _delete_document(self, channel: str, collection_name: str="games"):
self.database[f"{self.game_name} {collection_name}"].delete_one(
{"_id": channel}
)
def _insert_document(self, data: dict, collection_name: str="games"):
self.database[f"{self.game_name} {collection_name}"].insert_one(data)
async def _delete_old_image(self, channel: Messageable):
with open(self.old_images_path + str(channel.id), "r") as file_pointer:
old_image = await channel.fetch_message(int(file_pointer.read()))
await old_image.delete()
async def _send_image(self, channel: Messageable):
self.draw.draw(str(channel.id))
file_path = f"{self.resources}images/blackjack{channel.id}.png"
old_image = await channel.send(file=File(file_path))
with open(self.old_images_path + str(channel.id), "w") as file_pointer:
file_pointer.write(str(old_image.id))
async def _start_new(self, channel: Messageable, new_game: dict):
self._insert_document(new_game)
default_image = f"{self.resources}default_images/{self.game_name}.png"
new_image = f"{self.resources}images/{self.game_name}{channel.id}.png"
copyfile(default_image, new_image)
await self._send_image(channel)
class CardGame(GameBase):
"""The class for card games."""
def __init__(self, bot):
"""Initialize the class."""
super().__init__(bot)
self.decks_used = 1
def _shuffle_cards(self, channel: str):
self.bot.log(f"Shuffling cards for {self.game_name}")
with open(f"{self.resources}deck_of_cards.txt", "r") as file_pointer:
deck = file_pointer.read()
all_decks = deck.split("\n") * self.decks_used
random.shuffle(all_decks)
self._update_document(
channel,
{"$set": {"_id": channel, "cards": all_decks}},
"cards"
)
def _draw_card(self, channel: str):
"""
Draw a card from the stack.
*Parameters*
------------
channel: str
The id of the channel the card is drawn in.
"""
self.bot.log("drawing a card")
drawn_card = self.access_document(channel, "cards")["cards"][0]
self._update_document(channel, {"$pop": {"cards": -1}}, "cards")
return drawn_card
class BaseDrawer():
"""Class for drawing games."""
def __init__(self, bot, game: GameBase):
self.bot = bot
self.game = game
self.fonts_path = "gwendolyn/resources/fonts/"
self.font_name = "futura-bold"
self.resources = game.resources
game_name = game.game_name
self.default_image = f"{self.resources}default_images/{game_name}.png"
self.images_path = f"{self.resources}images/{game_name}"
def _draw_image(self, game: dict, table: Image.Image):
pass
def draw(self, channel: str):
game = self.game.access_document(channel)
image = Image.open(self.default_image)
self._draw_image(game, image)
self._save_image(image, channel)
def _get_font(self, size: int, font_name: str = None):
if font_name is None:
font_name = self.font_name
return ImageFont.truetype(f"{self.fonts_path}{font_name}.ttf", size)
def _adjust_font(self, max_font_size: int, text: str, max_text_size: int,
font_name: str = None):
font_size = max_font_size
font = self._get_font(font_size, font_name)
text_width = font.getsize(text)[0]
while text_width > max_text_size:
font_size -= 1
font = self._get_font(font_size, font_name)
text_width = font.getsize(text)[0]
return font, font_size
def _save_image(self, image: Image.Image, channel: str):
self.bot.log("Saving image")
image.save(f"{self.images_path}{channel}.png")
def _draw_shadow_text(self, text: str, colors: list[tuple[int, int, int]],
font_size: int):
font = self._get_font(font_size)
offset = font_size//20
shadow_offset = font_size//10
text_size = list(font.getsize(text))
text_size[0] += 1 + (offset * 2)
text_size[1] += 1 + (offset * 2) + shadow_offset
image = Image.new("RGBA", tuple(text_size), (0, 0, 0, 0))
text_image = ImageDraw.Draw(image)
for color_index, color in enumerate(colors[:-1]):
color_offset = offset//(color_index+1)
if color_index == 0:
color_shadow_offset = shadow_offset
else:
color_shadow_offset = 0
for i in range(4):
x_pos = [-1,1][i % 2] * color_offset
y_pos = [-1,1][(i//2) % 2] * color_offset + color_shadow_offset
position = (offset + x_pos, offset + y_pos)
text_image.text(position, text, fill=color, font=font)
text_image.text((offset, offset), text, fill=colors[-1], font=font)
return image
class CardDrawer(BaseDrawer):
def __init__(self, bot, game: GameBase):
super().__init__(bot, game)
self.cards_path = f"{self.resources}cards/"
# pylint: disable=invalid-name
self.CARD_WIDTH = 691
self.CARD_HEIGHT = 1065
self.CARD_BORDER = 100
self.CARD_OFFSET = 125
# pylint: enable=invalid-name
def _set_card_size(self, wanted_card_width: int):
ratio = wanted_card_width / self.CARD_WIDTH
self.CARD_WIDTH = wanted_card_width
self.CARD_HEIGHT = int(self.CARD_HEIGHT * ratio)
self.CARD_BORDER = int(self.CARD_BORDER * ratio)
self.CARD_OFFSET = int(self.CARD_OFFSET * ratio)
def _draw_cards(self, hand: list[str], hidden_cards: int = 0):
image_width = (self.CARD_BORDER * 2) + self.CARD_WIDTH
image_width += (self.CARD_OFFSET * (len(hand)-1))
image_size = (image_width, (self.CARD_BORDER * 2) + self.CARD_HEIGHT)
background = Image.new("RGBA", image_size, (0, 0, 0, 0))
for i, card in enumerate(hand):
position = (
self.CARD_BORDER + (self.CARD_OFFSET*i),
self.CARD_BORDER
)
if i + hidden_cards < len(hand):
card_image = Image.open(f"{self.cards_path}{card.upper()}.png")
else:
card_image = Image.open(f"{self.cards_path}red_back.png")
card_image = card_image.resize(
(self.CARD_WIDTH, self.CARD_HEIGHT),
resample=Image.BILINEAR
)
background.paste(card_image, position, card_image)
return background

View File

@ -94,7 +94,7 @@ class Gwendolyn(commands.Bot):
if filename.endswith(".py"): if filename.endswith(".py"):
self.load_extension(f"gwendolyn.cogs.{filename[:-3]}") self.load_extension(f"gwendolyn.cogs.{filename[:-3]}")
def log(self, messages, channel: str = "", level: int = 20): def log(self, messages, channel: str = "", level: int = 20): # pylint:disable=no-self-use
"""Log a message. Described in utils/util_functions.py.""" """Log a message. Described in utils/util_functions.py."""
log_this(messages, channel, level) log_this(messages, channel, level)

View File

Before

Width:  |  Height:  |  Size: 529 KiB

After

Width:  |  Height:  |  Size: 529 KiB

View File

Before

Width:  |  Height:  |  Size: 610 KiB

After

Width:  |  Height:  |  Size: 610 KiB

View File

@ -16,12 +16,12 @@ Contains utility functions used by parts of the bot.
new_string: str) -> str new_string: str) -> str
emoji_to_command(emoji: str) -> str emoji_to_command(emoji: str) -> str
""" """
import string
import json # Used by long_strings(), get_params() and make_files() import json # Used by long_strings(), get_params() and make_files()
import logging # Used for logging import logging # Used for logging
import os # Used by make_files() to check if files exist import os # Used by make_files() to check if files exist
import sys # Used to specify printing for logging import sys # Used to specify printing for logging
import imdb # Used to disable logging for the module import imdb # Used to disable logging for the module
import string
BASE_37 = ":" + string.digits + string.ascii_uppercase BASE_37 = ":" + string.digits + string.ascii_uppercase