From 69acfd0389120b7da670d5ea4fc3afbe02d34caa Mon Sep 17 00:00:00 2001 From: Auric Vente Date: Thu, 18 Jul 2024 00:51:11 -0600 Subject: [PATCH] first commit --- .gitignore | 6 +++++ ants.py | 68 ++++++++++++++++++++++++++++++++++++++++++++++++ database.py | 21 +++++++++++++++ main.py | 24 +++++++++++++++++ requirements.txt | 1 + run.sh | 1 + schema.sql | 22 ++++++++++++++++ utils.py | 49 ++++++++++++++++++++++++++++++++++ window.py | 60 ++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 252 insertions(+) create mode 100644 .gitignore create mode 100644 ants.py create mode 100644 database.py create mode 100644 main.py create mode 100644 requirements.txt create mode 100755 run.sh create mode 100644 schema.sql create mode 100644 utils.py create mode 100644 window.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..05f1c24 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +venv/* +.directory +*.pyc +__pycache__/ +.mypy_cache/ +ants.db \ No newline at end of file diff --git a/ants.py b/ants.py new file mode 100644 index 0000000..981bce1 --- /dev/null +++ b/ants.py @@ -0,0 +1,68 @@ +from __future__ import annotations + +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): + return self.name or "Nameless" + + def get_age(self): + now = utils.now() + return utils.time_ago(self.created, now) + + def describe(self): + print(f"Name is {self.get_name()}") + print(f"It hatched {self.get_age()}") + +class Ants: + ants: list[Ant] = [] + + @staticmethod + def get_all() -> None: + Database.cursor.execute("SELECT id, created, updated, name, status, hits, triumph FROM ants") + + rows = Database.cursor.fetchall() + ants = [] + + 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.append(ant) + + Database.connection.commit() + return ants + + @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] + + print(f"Ant hatched: {ant.id}") \ No newline at end of file diff --git a/database.py b/database.py new file mode 100644 index 0000000..f951c45 --- /dev/null +++ b/database.py @@ -0,0 +1,21 @@ +from __future__ import annotations + +import sqlite3 +from pathlib import Path + +class Database: + connection: sqlite3.Connection + cursor: sqlite3.Cursor + + @staticmethod + def prepare() -> None: + Database.connection = sqlite3.connect("ants.db") + Database.cursor = Database.connection.cursor() + + @staticmethod + def create() -> None: + with Path("schema.sql").open("r") as file: + schema = file.read() + + Database.cursor.executescript(schema) + Database.connection.commit() \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..4b3ac21 --- /dev/null +++ b/main.py @@ -0,0 +1,24 @@ +from __future__ import annotations + +from database import Database +from window import Window +from ants import Ants + + +def main() -> None: + Database.prepare() + Database.create() + + Ants.get_all() + + for ant in Ants.ants: + ant.describe() + + Window.make() + Window.add_buttons() + Window.add_view() + Window.start() + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..09c5122 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +PySide6 == 6.7.2 \ No newline at end of file diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..13b5227 --- /dev/null +++ b/run.sh @@ -0,0 +1 @@ +venv/bin/python main.py \ No newline at end of file diff --git a/schema.sql b/schema.sql new file mode 100644 index 0000000..c16d285 --- /dev/null +++ b/schema.sql @@ -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 +); \ No newline at end of file diff --git a/utils.py b/utils.py new file mode 100644 index 0000000..1b9f643 --- /dev/null +++ b/utils.py @@ -0,0 +1,49 @@ +import time + + +def now() -> float: + return int(time.time()) + + +def singular_or_plural(num: float, singular: str, plural: str) -> str: + if num == 1: + return singular + + return plural + + +def time_ago(start_time: float, end_time: float) -> str: + diff = end_time - start_time + seconds = int(diff) + + if seconds < 60: + word = singular_or_plural(seconds, "second", "seconds") + return f"{seconds} {word} ago" + + minutes = seconds // 60 + + if minutes < 60: + word = singular_or_plural(minutes, "minute", "minutes") + return f"{minutes} {word} ago" + + hours = minutes / 60 + + if hours < 24: + word = singular_or_plural(hours, "hour", "hours") + return f"{hours:.1f} {word} ago" + + days = hours / 24 + + if days < 30: + word = singular_or_plural(days, "day", "days") + return f"{days:.1f} {word} ago" + + months = days / 30 + + if months < 12: + word = singular_or_plural(months, "month", "months") + return f"{months:.1f} {word} ago" + + years = months / 12 + word = singular_or_plural(years, "year", "years") + return f"{years:.1f} {word} ago" \ No newline at end of file diff --git a/window.py b/window.py new file mode 100644 index 0000000..a0803c5 --- /dev/null +++ b/window.py @@ -0,0 +1,60 @@ +from __future__ import annotations + +from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton, QHBoxLayout, QWidget +from PySide6.QtWidgets import QGraphicsView, QGraphicsScene, QVBoxLayout + +from ants import Ants + + +class Window: + title = "Cromulant" + width = 800 + height = 600 + app: QApplication + window: QMainWindow + root: QWidget + + @staticmethod + def make() -> None: + Window.app = QApplication([]) + Window.window = QMainWindow() + Window.window.setWindowTitle(Window.title) + Window.window.resize(Window.width, Window.height) + Window.root = QWidget() + Window.window.setCentralWidget(Window.root) + + @staticmethod + def add_buttons() -> None: + btn_hatch = QPushButton("Hatch Ant") + btn_terminate = QPushButton("Terminate") + + btn_hatch.clicked.connect(Window.hatch) + btn_terminate.clicked.connect(Window.terminate) + + layout = QHBoxLayout() + layout.addWidget(btn_hatch) + layout.addWidget(btn_terminate) + + Window.root.setLayout(layout) + + @staticmethod + def add_view() -> None: + Window.view = QGraphicsView() + Window.scene = QGraphicsScene() + Window.view.setScene(Window.scene) + + layout = QVBoxLayout(Window.root) + layout.addWidget(Window.view) + + @staticmethod + def hatch() -> None: + Ants.hatch() + + @staticmethod + def terminate() -> None: + Ants.terminate() + + @staticmethod + def start() -> None: + Window.window.show() + Window.app.exec()