Mods
This commit is contained in:
72
cromulant/ants.py
Normal file
72
cromulant/ants.py
Normal file
@@ -0,0 +1,72 @@
|
||||
from __future__ import annotations
|
||||
from typing import ClassVar
|
||||
|
||||
from .utils import Utils
|
||||
from .database import Database
|
||||
|
||||
|
||||
class Ant:
|
||||
def __init__(self) -> None:
|
||||
now = Utils.now()
|
||||
self.id: int
|
||||
self.created = now
|
||||
self.updated = now
|
||||
self.name = ""
|
||||
self.status = ""
|
||||
self.hits = 0
|
||||
self.triumph = 0
|
||||
|
||||
def get_name(self) -> str:
|
||||
return self.name or "Nameless"
|
||||
|
||||
def get_age(self) -> str:
|
||||
now = Utils.now()
|
||||
return Utils.time_ago(self.created, now)
|
||||
|
||||
def describe(self) -> None:
|
||||
Utils.print(f"Name is {self.get_name()}")
|
||||
Utils.print(f"It hatched {self.get_age()}")
|
||||
|
||||
|
||||
class Ants:
|
||||
ants: ClassVar[list[Ant]] = []
|
||||
|
||||
@staticmethod
|
||||
def get_all() -> None:
|
||||
Database.cursor.execute(
|
||||
"SELECT id, created, updated, name, status, hits, triumph FROM ants"
|
||||
)
|
||||
rows = Database.cursor.fetchall()
|
||||
|
||||
for row in rows:
|
||||
ant = Ant()
|
||||
ant.id = row[0]
|
||||
ant.created = row[1]
|
||||
ant.updated = row[2]
|
||||
ant.name = row[3]
|
||||
ant.status = row[4]
|
||||
ant.hits = row[5]
|
||||
ant.triumph = row[6]
|
||||
Ants.ants.append(ant)
|
||||
|
||||
@staticmethod
|
||||
def hatch() -> None:
|
||||
now = Utils.now()
|
||||
|
||||
Database.cursor.execute(
|
||||
"INSERT INTO ants (created, updated) VALUES (?, ?)",
|
||||
(now, now),
|
||||
)
|
||||
|
||||
Database.connection.commit()
|
||||
Database.cursor.execute("SELECT last_insert_rowid()")
|
||||
row = Database.cursor.fetchone()
|
||||
|
||||
ant = Ant()
|
||||
ant.id = row[0]
|
||||
|
||||
Utils.print(f"Ant hatched: {ant.id}")
|
||||
|
||||
@staticmethod
|
||||
def terminate() -> None:
|
||||
pass
|
17
cromulant/config.py
Normal file
17
cromulant/config.py
Normal file
@@ -0,0 +1,17 @@
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class Config:
|
||||
title = "Cromulant"
|
||||
width = 800
|
||||
height = 600
|
||||
here: str
|
||||
database_path: Path
|
||||
schema_path: Path
|
||||
|
||||
|
||||
@staticmethod
|
||||
def prepare() -> None:
|
||||
Config.here = Path(__file__).parent
|
||||
Config.database_path = Config.here / "cromulant.db"
|
||||
Config.schema_path = Config.here / "schema.sql"
|
24
cromulant/database.py
Normal file
24
cromulant/database.py
Normal file
@@ -0,0 +1,24 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import sqlite3
|
||||
from pathlib import Path
|
||||
|
||||
from .config import Config
|
||||
|
||||
|
||||
class Database:
|
||||
connection: sqlite3.Connection
|
||||
cursor: sqlite3.Cursor
|
||||
|
||||
@staticmethod
|
||||
def prepare() -> None:
|
||||
Database.connection = sqlite3.connect(Config.database_path)
|
||||
Database.cursor = Database.connection.cursor()
|
||||
|
||||
@staticmethod
|
||||
def create() -> None:
|
||||
with Config.schema_path.open("r") as file:
|
||||
schema = file.read()
|
||||
|
||||
Database.cursor.executescript(schema)
|
||||
Database.connection.commit()
|
11
cromulant/game.py
Normal file
11
cromulant/game.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from .window import Window
|
||||
|
||||
class Game:
|
||||
@staticmethod
|
||||
def update_view() -> None:
|
||||
scene = Window.view.scene()
|
||||
scene.addRect(0, 0, 10, 10)
|
||||
scene.addRect(10, 10, 10, 10)
|
||||
scene.addRect(20, 20, 10, 10)
|
||||
scene.addRect(30, 30, 10, 10)
|
||||
scene.addRect(40, 40, 10, 10)
|
24
cromulant/main.py
Normal file
24
cromulant/main.py
Normal file
@@ -0,0 +1,24 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from .config import Config
|
||||
from .database import Database
|
||||
from .window import Window
|
||||
from .ants import Ants
|
||||
|
||||
|
||||
def main() -> None:
|
||||
Config.prepare()
|
||||
Database.prepare()
|
||||
Database.create()
|
||||
|
||||
Ants.get_all()
|
||||
|
||||
Window.make()
|
||||
Window.add_buttons()
|
||||
Window.add_view()
|
||||
Window.add_log()
|
||||
Window.start()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
41
cromulant/ruff.toml
Normal file
41
cromulant/ruff.toml
Normal file
@@ -0,0 +1,41 @@
|
||||
[lint]
|
||||
|
||||
select = [
|
||||
"T",
|
||||
"Q",
|
||||
"W",
|
||||
"B",
|
||||
"N",
|
||||
"F",
|
||||
"FA",
|
||||
"RET",
|
||||
"PTH",
|
||||
"ERA",
|
||||
"PLW",
|
||||
"PERF",
|
||||
"RUF",
|
||||
"FLY",
|
||||
"PT",
|
||||
"PYI",
|
||||
"PIE",
|
||||
"ICN",
|
||||
"UP",
|
||||
"TRY",
|
||||
"C4",
|
||||
"E401",
|
||||
"E713",
|
||||
"E721",
|
||||
"S101",
|
||||
"S113",
|
||||
"SIM103",
|
||||
"SIM114",
|
||||
"SIM118",
|
||||
"SIM210",
|
||||
"PLR5501",
|
||||
"PLR1711",
|
||||
]
|
||||
|
||||
exclude = [
|
||||
"pyperclip.py",
|
||||
"tests.py",
|
||||
]
|
22
cromulant/schema.sql
Normal file
22
cromulant/schema.sql
Normal file
@@ -0,0 +1,22 @@
|
||||
CREATE TABLE IF NOT EXISTS ants (
|
||||
-- Internal ID of the ant
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
|
||||
-- The date when the ant was created
|
||||
created INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
-- The date when the ant was last changed
|
||||
updated INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
-- The public name of the ant
|
||||
name TEXT NOT NULL DEFAULT "",
|
||||
|
||||
-- The current text of the ant
|
||||
status TEXT NOT NULL DEFAULT "",
|
||||
|
||||
-- The total number of hits taken
|
||||
hits INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
-- The total number of triumph achieved
|
||||
triumph INTEGER NOT NULL DEFAULT 0
|
||||
);
|
55
cromulant/utils.py
Normal file
55
cromulant/utils.py
Normal file
@@ -0,0 +1,55 @@
|
||||
import time
|
||||
|
||||
|
||||
class Utils:
|
||||
@staticmethod
|
||||
def now() -> float:
|
||||
return int(time.time())
|
||||
|
||||
@staticmethod
|
||||
def singular_or_plural(num: float, singular: str, plural: str) -> str:
|
||||
if num == 1:
|
||||
return singular
|
||||
|
||||
return plural
|
||||
|
||||
@staticmethod
|
||||
def time_ago(start_time: float, end_time: float) -> str:
|
||||
diff = end_time - start_time
|
||||
seconds = int(diff)
|
||||
|
||||
if seconds < 60:
|
||||
word = Utils.singular_or_plural(seconds, "second", "seconds")
|
||||
return f"{seconds} {word} ago"
|
||||
|
||||
minutes = seconds // 60
|
||||
|
||||
if minutes < 60:
|
||||
word = Utils.singular_or_plural(minutes, "minute", "minutes")
|
||||
return f"{minutes} {word} ago"
|
||||
|
||||
hours = minutes / 60
|
||||
|
||||
if hours < 24:
|
||||
word = Utils.singular_or_plural(hours, "hour", "hours")
|
||||
return f"{hours:.1f} {word} ago"
|
||||
|
||||
days = hours / 24
|
||||
|
||||
if days < 30:
|
||||
word = Utils.singular_or_plural(days, "day", "days")
|
||||
return f"{days:.1f} {word} ago"
|
||||
|
||||
months = days / 30
|
||||
|
||||
if months < 12:
|
||||
word = Utils.singular_or_plural(months, "month", "months")
|
||||
return f"{months:.1f} {word} ago"
|
||||
|
||||
years = months / 12
|
||||
word = Utils.singular_or_plural(years, "year", "years")
|
||||
return f"{years:.1f} {word} ago"
|
||||
|
||||
@staticmethod
|
||||
def print(text: str) -> None:
|
||||
print(text) # noqa: T201
|
84
cromulant/window.py
Normal file
84
cromulant/window.py
Normal file
@@ -0,0 +1,84 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from PySide6.QtWidgets import QApplication # type: ignore
|
||||
from PySide6.QtWidgets import QMainWindow
|
||||
from PySide6.QtWidgets import QWidget
|
||||
from PySide6.QtWidgets import QGraphicsView
|
||||
from PySide6.QtWidgets import QGraphicsScene
|
||||
from PySide6.QtWidgets import QVBoxLayout
|
||||
from PySide6.QtWidgets import QPushButton
|
||||
from PySide6.QtWidgets import QHBoxLayout
|
||||
from PySide6.QtWidgets import QTextEdit
|
||||
|
||||
from .config import Config
|
||||
|
||||
|
||||
class Window:
|
||||
app: QApplication
|
||||
window: QMainWindow
|
||||
root: QHBoxLayout
|
||||
view: QGraphicsView
|
||||
log: QTextEdit
|
||||
|
||||
@staticmethod
|
||||
def make() -> None:
|
||||
Window.app = QApplication([])
|
||||
Window.window = QMainWindow()
|
||||
Window.window.setWindowTitle(Config.title)
|
||||
Window.window.resize(Config.width, Config.height)
|
||||
Window.root = QHBoxLayout()
|
||||
central_widget = QWidget()
|
||||
Window.root = QVBoxLayout()
|
||||
central_widget.setLayout(Window.root)
|
||||
Window.window.setCentralWidget(central_widget)
|
||||
|
||||
@staticmethod
|
||||
def add_buttons() -> None:
|
||||
btn_hatch = QPushButton("Hatch")
|
||||
btn_terminate = QPushButton("Terminate")
|
||||
btn_update = QPushButton("Update")
|
||||
|
||||
btn_hatch.clicked.connect(Window.hatch)
|
||||
btn_terminate.clicked.connect(Window.terminate)
|
||||
btn_update.clicked.connect(Window.update_view)
|
||||
|
||||
layout = QHBoxLayout()
|
||||
layout.addWidget(btn_hatch)
|
||||
layout.addWidget(btn_terminate)
|
||||
layout.addWidget(btn_update)
|
||||
|
||||
Window.root.addLayout(layout)
|
||||
|
||||
@staticmethod
|
||||
def add_view() -> None:
|
||||
Window.view = QGraphicsView()
|
||||
scene = QGraphicsScene()
|
||||
Window.view.setScene(scene)
|
||||
Window.root.addWidget(Window.view)
|
||||
|
||||
@staticmethod
|
||||
def add_log() -> None:
|
||||
Window.log = QTextEdit()
|
||||
Window.log.setReadOnly(True)
|
||||
Window.log.setFixedHeight(100)
|
||||
Window.root.addWidget(Window.log)
|
||||
|
||||
@staticmethod
|
||||
def update_view() -> None:
|
||||
from .game import Game
|
||||
Game.update_view()
|
||||
|
||||
@staticmethod
|
||||
def hatch() -> None:
|
||||
from .ants import Ants
|
||||
Ants.hatch()
|
||||
|
||||
@staticmethod
|
||||
def terminate() -> None:
|
||||
from .ants import Ants
|
||||
Ants.terminate()
|
||||
|
||||
@staticmethod
|
||||
def start() -> None:
|
||||
Window.window.show()
|
||||
Window.app.exec()
|
Reference in New Issue
Block a user