1
0
Fork 0
mirror of https://github.com/ldericher/fftcgtool synced 2025-01-15 15:02:59 +00:00

major cleanup

This commit is contained in:
Jörn-Michael Miehe 2021-08-17 17:37:28 +02:00
parent 730775a660
commit 8360eb69b2
9 changed files with 130 additions and 108 deletions

View file

@ -4,18 +4,14 @@ import yaml
from PIL import Image
from .cards import Cards
from .grid import Grid
from .imageloader import ImageLoader
from .utils import GRID, RESOLUTION, BOOK_YML_NAME
class Book:
def __init__(self, cards: Cards, grid: tuple[int, int], resolution: tuple[int, int], language: str,
num_threads: int):
def __init__(self, cards: Cards, language: str, num_threads: int):
logger = logging.getLogger(__name__)
# transform grid into Grid
grid = Grid(grid)
# sort cards by element, then alphabetically
cards.sort(key=lambda x: x.name)
cards.sort(key=lambda x: "Multi" if len(x.elements) > 1 else x.elements[0])
@ -28,22 +24,22 @@ class Book:
)
# multi-threaded download
images = ImageLoader.load(urls, resolution, language, num_threads)
images = ImageLoader.load(urls, language, num_threads)
# card back Image
back_image = images.pop(-1)
self.__pages = []
for page_images, page_cards in zip(grid.chunks(images), grid.chunks(cards)):
for page_images, page_cards in zip(GRID.chunks(images), GRID.chunks(cards)):
# create book page Image
page_image = Image.new("RGB", grid * resolution)
page_image = Image.new("RGB", GRID * RESOLUTION)
logger.info(f"New image: {page_image.size[0]}x{page_image.size[1]}")
# paste card faces onto page
for i, image in enumerate(page_images):
grid.paste(page_image, i, image)
GRID.paste(page_image, i, image)
# paste card back in last position
grid.paste(page_image, grid.capacity, back_image)
GRID.paste(page_image, GRID.capacity, back_image)
# save page
self.__pages.append({
@ -51,15 +47,12 @@ class Book:
"cards": page_cards,
})
def __getitem__(self, index: int) -> Image.Image:
return self.__pages[index]["image"]
def save(self, file_name: str, book_yml_name: str) -> None:
def save(self, file_name: str) -> None:
book: dict[str, dict[str, any]]
# load book.yml file
try:
with open(book_yml_name, "r") as file:
with open(BOOK_YML_NAME, "r") as file:
book = yaml.load(file, Loader=yaml.Loader)
except FileNotFoundError:
book = {}
@ -73,5 +66,5 @@ class Book:
book[fn] = {"cards": page["cards"]}
# update book.yml file
with open(book_yml_name, "w") as file:
with open(BOOK_YML_NAME, "w") as file:
yaml.dump(book, file, Dumper=yaml.Dumper)

View file

@ -1,33 +1,12 @@
from __future__ import annotations
import json
import re
import yaml
from .code import Code
def encircle_symbol(symbol: str, negative: bool):
symbol = symbol[0].upper()
base_symbols: tuple[str, str] = "", ""
if symbol.isalpha():
if negative:
base_symbols = "A", "🅐"
else:
base_symbols = "A", ""
elif symbol == "0":
if negative:
base_symbols = "0", "🄌"
else:
base_symbols = "0", ""
elif symbol.isnumeric():
if negative:
base_symbols = "1", ""
else:
base_symbols = "1", ""
symbol_num = ord(symbol) - ord(base_symbols[0])
return chr(ord(base_symbols[1]) + symbol_num)
from .utils import encircle_symbol
class Card(yaml.YAMLObject):
@ -53,7 +32,7 @@ class Card(yaml.YAMLObject):
self.__text = text
@classmethod
def from_data(cls, data: dict[str, any], language: str):
def from_data(cls, data: dict[str, any], language: str) -> Card:
if not data:
return cls(
code=Code(""),

View file

@ -1,45 +1,60 @@
from __future__ import annotations
import yaml
_DictOfDicts = dict[str, dict[str, any]]
from fftcg.code import Code
from fftcg.utils import BOOK_YML_NAME
class CardDB(_DictOfDicts):
def __init__(self, book_yml_name: str):
book: _DictOfDicts
class CardDB:
__instance: CardDB = None
@classmethod
def get(cls) -> CardDB:
if not CardDB.__instance:
CardDB.__instance = CardDB()
return CardDB.__instance
def __init__(self):
self.__content: dict[Code, dict[str, any]] = {}
def __getitem__(self, code: Code) -> dict[str, any]:
return self.__content[str(code)]
def load(self):
# load book.yml file
book: dict
try:
with open(book_yml_name, "r") as file:
with open(BOOK_YML_NAME, "r") as file:
book = yaml.load(file, Loader=yaml.Loader)
except FileNotFoundError:
book = {}
# "invert" book into card database:
# every card is indexable by its code
carddb: _DictOfDicts = {}
self.__content.clear()
for fn, content in book.items():
carddb |= {
for file_name, content in book.items():
self.__content |= {
str(card.code): {
"card": card,
"file": fn,
"file": file_name,
"index": i,
} for i, card in enumerate(content["cards"])
}
super().__init__(carddb)
# write carddb.yml file
with open("carddb.yml", "w") as file:
yaml.dump(self, file, Dumper=yaml.Dumper)
yaml.dump(self.__content, file, Dumper=yaml.Dumper)
def make_deck(self, filters):
# filter codes by card criteria
codes = [
content["card"].code
for content in self.values()
if all([f(content["card"]) for f in filters])
]
from .ttsdeck import TTSDeck
return TTSDeck(codes, self)
# def make_deck(self, filters):
# # filter codes by card criteria
# codes = [
# content["card"].code
# for content in self.__content.values()
# if all([f(content["card"]) for f in filters])
# ]
#
# from .ttsdeck import TTSDeck
# return TTSDeck(codes)

View file

@ -1,12 +1,13 @@
from __future__ import annotations
from PIL import Image
_Point = tuple[int, int]
class Grid(_Point):
def __mul__(self, other: _Point) -> _Point:
other = Grid(other)
return self.x * other.x, self.y * other.y
class Grid(tuple[int, int]):
def __mul__(self, other: Grid) -> Grid:
return Grid((self.x * other.x, self.y * other.y))
@property
def x(self):

View file

@ -6,6 +6,8 @@ import threading
import requests
from PIL import Image
from fftcg.utils import RESOLUTION
class ImageLoader(threading.Thread):
def __init__(self, url_queue: queue.Queue, resolution: tuple[int, int], language: str):
@ -44,14 +46,14 @@ class ImageLoader(threading.Thread):
self.__queue.task_done()
@classmethod
def load(cls, urls: list[str], resolution: tuple[int, int], language: str, num_threads: int) -> list[Image.Image]:
def load(cls, urls: list[str], language: str, num_threads: int) -> list[Image.Image]:
url_queue = queue.Queue()
for url in urls:
url_queue.put(url)
loaders = []
for _ in range(num_threads):
loader = cls(url_queue, resolution, language)
loader = cls(url_queue, RESOLUTION, language)
loaders.append(loader)
loader.start()

View file

@ -3,6 +3,7 @@ import logging
import roman
from .cards import Cards
from .ttsdeck import TTSDeck
class Opus(Cards):
@ -60,3 +61,32 @@ class Opus(Cards):
@property
def filename(self) -> str:
return self.__filename
@property
def elemental_decks(self) -> list[TTSDeck]:
if self.name in ["Promo", "Boss Deck Chaos"]:
return [TTSDeck([
card.code
for card in self
])]
else:
def element_filter(element: str):
return lambda card: card.elements == [element]
# simple cases: create lambdas for base elemental decks
base_elements = ["Fire", "Ice", "Wind", "Earth", "Lightning", "Water"]
filters = [element_filter(elem) for elem in base_elements]
filters += [
# light/darkness elemental deck
lambda card: card.elements == ["Light"] or card.elements == ["Darkness"],
# multi element deck
lambda card: len(card.elements) > 1,
]
return [TTSDeck([
card.code
for card in self
if f(card)
]) for f in filters]

View file

@ -5,8 +5,9 @@ from .code import Code
class TTSDeck(list[dict[str, any]]):
def __init__(self, codes: list[Code], carddb: CardDB):
super().__init__([carddb[str(code)] for code in codes])
def __init__(self, codes: list[Code]):
carddb = CardDB.get()
super().__init__([carddb[code] for code in codes])
def __str__(self) -> str:
face_urls = list(set([entry["file"] for entry in self]))

31
fftcg/utils.py Normal file
View file

@ -0,0 +1,31 @@
from .grid import Grid
# constants
GRID = Grid((10, 7)) # default in TTsim: 10 columns, 7 rows
RESOLUTION = Grid((429, 600)) # default in TTsim: 480x670 pixels per card
BOOK_YML_NAME = "book.yml"
# functions
def encircle_symbol(symbol: str, negative: bool):
symbol = symbol[0].upper()
base_symbols: tuple[str, str] = "", ""
if symbol.isalpha():
if negative:
base_symbols = "A", "🅐"
else:
base_symbols = "A", ""
elif symbol == "0":
if negative:
base_symbols = "0", "🄌"
else:
base_symbols = "0", ""
elif symbol.isnumeric():
if negative:
base_symbols = "1", ""
else:
base_symbols = "1", ""
symbol_num = ord(symbol) - ord(base_symbols[0])
return chr(ord(base_symbols[1]) + symbol_num)

42
main.py
View file

@ -5,11 +5,6 @@ import os
import fftcg
# constants
GRID = 10, 7 # default in TTsim: 10 columns, 7 rows
RESOLUTION = 429, 600 # default in TTsim: 480x670 pixels per card
BOOK_YML_NAME = "book.yml"
def main() -> None:
# set up CLI
@ -45,40 +40,15 @@ def main() -> None:
# main program
opus = fftcg.Opus(args.opus_id)
book = fftcg.Book(opus, GRID, RESOLUTION, "eg", args.num_threads)
book.save(opus.filename, BOOK_YML_NAME)
book = fftcg.Book(opus, "eg", args.num_threads)
book.save(opus.filename)
# create elemental decks for opus
carddb = fftcg.CardDB(BOOK_YML_NAME)
carddb = fftcg.CardDB.get()
carddb.load()
def opus_filter(card: fftcg.Card):
return card.code.opus == opus.number
filters: list
if opus.number == "PR":
filters = [[opus_filter]]
else:
def element_filter(element: str):
return lambda card: card.elements == [element]
# simple cases: create lambdas for base elemental decks
base_elements = ["Fire", "Ice", "Wind", "Earth", "Lightning", "Water"]
element_filters = [element_filter(elem) for elem in base_elements]
element_filters += [
# light/darkness elemental deck
lambda card: card.elements == ["Light"] or card.elements == ["Darkness"],
# multi element deck
lambda card: len(card.elements) > 1,
]
# add in the opus_filter for all elemental decks
filters = list(zip([opus_filter] * len(element_filters), element_filters))
# make the decks
for f in filters:
print(carddb.make_deck(f))
for deck in opus.elemental_decks:
print(deck)
# bye
logging.info("Done. Put the generated JSON files in your 'Saved Objects' Folder.")