commit 69acfd0389120b7da670d5ea4fc3afbe02d34caa Author: Auric Vente Date: Thu Jul 18 00:51:11 2024 -0600 first commit 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()