diff --git a/cromulant/__init__.py b/cromulant/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cromulant/ants.py b/cromulant/ants.py index ce66467..a51dc95 100644 --- a/cromulant/ants.py +++ b/cromulant/ants.py @@ -1,4 +1,6 @@ from __future__ import annotations + +import random from typing import ClassVar, Any from .config import Config @@ -76,7 +78,7 @@ class Ants: ant.color = Utils.random_color() Ants.ants.append(ant) - Storage.save_ants(Ants.ants) + Ants.save() Utils.print(f"Ant hatched: {ant.name}") @staticmethod @@ -85,4 +87,17 @@ class Ants: @staticmethod def get_names() -> list[str]: - return [ant.name for ant in Ants.ants] \ No newline at end of file + return [ant.name for ant in Ants.ants] + + @staticmethod + def save() -> None: + Storage.save_ants(Ants.ants) + + @staticmethod + def get_lazy() -> Ant: + return min(Ants.ants, key=lambda ant: ant.updated) + + @staticmethod + def get_other(ant: Ant) -> Ant: + ants = [a for a in Ants.ants if a.name != ant.name] + return random.choice(ants) diff --git a/cromulant/config.py b/cromulant/config.py index decb306..a24f718 100644 --- a/cromulant/config.py +++ b/cromulant/config.py @@ -1,20 +1,21 @@ +from __future__ import annotations + from pathlib import Path import appdirs # type: ignore class Config: - title = "Cromulant" - width = 800 - height = 600 - max_ants = 100 - here: str + title: str = "Cromulant" + width: int = 800 + height: int = 600 + max_ants: int = 100 + here: Path ants_json: Path icon_path: Path image_path: Path names_json: Path - @staticmethod def prepare() -> None: Config.here = Path(__file__).parent @@ -26,4 +27,4 @@ class Config: Config.icon_path = Config.here / "img" / "icon_4.jpg" Config.image_path = Config.here / "img" / "icon_7.jpg" - Config.names_json = Config.here / "data" / "names.json" \ No newline at end of file + Config.names_json = Config.here / "data" / "names.json" diff --git a/cromulant/game.py b/cromulant/game.py index 153939e..9a7f06f 100644 --- a/cromulant/game.py +++ b/cromulant/game.py @@ -1,21 +1,30 @@ -from PySide6.QtWidgets import QWidget -from PySide6.QtGui import QColor +from __future__ import annotations + +import random + +from PySide6.QtWidgets import QWidget # type: ignore +from PySide6.QtGui import QColor # type: ignore from PySide6.QtGui import QPainter -from PySide6.QtCore import Qt +from PySide6.QtCore import Qt # type: ignore from PySide6.QtWidgets import QHBoxLayout from PySide6.QtWidgets import QLabel +from PySide6.QtGui import QPaintEvent +from wonderwords import RandomSentence # type: ignore + +from .ants import Ant from .ants import Ants from .window import Window -class CircleWidget(QWidget): - def __init__(self, color, parent=None): - super().__init__(parent) +class CircleWidget(QWidget): # type: ignore + def __init__(self, color: tuple[int, int, int]) -> None: + super().__init__(None) self.color = QColor(*color) self.setFixedSize(20, 20) - def paintEvent(self, event): + def paintEvent(self, event: QPaintEvent) -> None: + print(type(event)) painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing) painter.setBrush(self.color) @@ -25,16 +34,38 @@ class CircleWidget(QWidget): class Game: @staticmethod - def update_view() -> None: - for ant in Ants.ants: - container = QHBoxLayout() - circle = CircleWidget(ant.color) - text = QLabel(ant.status) - container.addWidget(circle) - container.addWidget(text) - Window.view.addLayout(container) - + def add_status(ant: Ant) -> None: + container = QHBoxLayout() + circle = CircleWidget(ant.color) + text = QLabel(ant.status) + container.addWidget(circle) + container.addWidget(text) + Window.view.addLayout(container) @staticmethod def log(message: str) -> None: - Window.log.append(message) \ No newline at end of file + Window.log.append(message) + + @staticmethod + def get_status() -> None: + ant = Ants.get_lazy() + num = random.randint(1, 10) + + if num == 1: + ant.hits += 1 + ant.status = f"Took a hit ({ant.hits} total)" + elif num == 2: + ant.triumph += 1 + ant.status = f"Scored a triumph ({ant.triumph} total)" + elif num == 3: + s = RandomSentence() + ant.status = s.simple_sentence() + elif (num == 4) and (len(Ants.ants) > 1): + other = Ants.get_other(ant) + ant.status = f"Is thinking about {other.name}" + else: + s = RandomSentence() + ant.status = s.bare_bone_with_adjective() + + Game.add_status(ant) + Ants.save() diff --git a/cromulant/ruff.toml b/cromulant/ruff.toml index b2ec399..2c3416d 100644 --- a/cromulant/ruff.toml +++ b/cromulant/ruff.toml @@ -35,6 +35,11 @@ select = [ "PLR1711", ] +ignore = [ + "W292", + "N802", +] + exclude = [ "pyperclip.py", "tests.py", diff --git a/cromulant/storage.py b/cromulant/storage.py index 231ca46..d3fc064 100644 --- a/cromulant/storage.py +++ b/cromulant/storage.py @@ -1,5 +1,7 @@ +from __future__ import annotations + import json -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any from .config import Config @@ -9,18 +11,18 @@ if TYPE_CHECKING: class Storage: @staticmethod - def get_ants() -> None: + def get_ants() -> Any: with Config.ants_json.open() as file: return json.load(file) @staticmethod - def save_ants(ants: list["Ant"]) -> None: + def save_ants(ants: list[Ant]) -> None: objs = [ant.to_dict() for ant in ants] with Config.ants_json.open("w") as file: json.dump(objs, file) @staticmethod - def get_names() -> None: + def get_names() -> Any: with Config.names_json.open() as file: - return json.load(file) \ No newline at end of file + return json.load(file) diff --git a/cromulant/utils.py b/cromulant/utils.py index db9ea87..e33a444 100644 --- a/cromulant/utils.py +++ b/cromulant/utils.py @@ -1,11 +1,15 @@ +from __future__ import annotations + import random import colorsys import time +from typing import ClassVar from .storage import Storage + class Utils: - names: list[str] = [] + names: ClassVar[list[str]] = [] @staticmethod def prepare() -> None: @@ -64,9 +68,14 @@ class Utils: print(text) # noqa: T201 @staticmethod - def random_color() -> str: - h,s,l = random.random(), 0.5 + random.random()/2.0, 0.4 + random.random()/5.0 - r, g, b = [int(256*i) for i in colorsys.hls_to_rgb(h,l,s)] + def random_color() -> tuple[int, int, int]: + h, s, l = ( + random.random(), + 0.5 + random.random() / 2.0, + 0.4 + random.random() / 5.0, + ) + + r, g, b = (int(256 * i) for i in colorsys.hls_to_rgb(h, l, s)) return r, g, b @staticmethod @@ -75,4 +84,4 @@ class Utils: used = Ants.get_names() filtered = [name for name in Utils.names if name not in used] - return random.choice(filtered) \ No newline at end of file + return random.choice(filtered) diff --git a/cromulant/window.py b/cromulant/window.py index 48e0e49..659b01e 100644 --- a/cromulant/window.py +++ b/cromulant/window.py @@ -10,9 +10,10 @@ from PySide6.QtWidgets import QPushButton from PySide6.QtWidgets import QHBoxLayout from PySide6.QtWidgets import QTextEdit from PySide6.QtWidgets import QLabel -from PySide6.QtGui import QPixmap +from PySide6.QtGui import QPixmap # type: ignore from PySide6.QtGui import QIcon -from PySide6.QtCore import Qt +from PySide6.QtCore import Qt # type: ignore +from PySide6.QtCore import QTimer from .config import Config @@ -24,6 +25,7 @@ class Window: view: QGraphicsView view_scene: QGraphicsScene log: QTextEdit + timer: QTimer @staticmethod def prepare() -> None: @@ -31,6 +33,7 @@ class Window: Window.add_buttons() Window.add_view() Window.add_log() + Window.start_timer() Window.start() @staticmethod @@ -51,18 +54,15 @@ class Window: def add_buttons() -> None: btn_hatch = QPushButton("Hatch") btn_terminate = QPushButton("Terminate") - btn_update = QPushButton("Update") btn_close = QPushButton("Close") btn_hatch.clicked.connect(Window.hatch) btn_terminate.clicked.connect(Window.terminate) - btn_update.clicked.connect(Window.update_view) btn_close.clicked.connect(Window.close) layout = QHBoxLayout() layout.addWidget(btn_hatch) layout.addWidget(btn_terminate) - layout.addWidget(btn_update) layout.addWidget(btn_close) Window.root.addLayout(layout) @@ -78,7 +78,9 @@ class Window: image_label = QLabel() pixmap = QPixmap(str(Config.image_path)) - scaled_pixmap = pixmap.scaled(100, pixmap.height(), Qt.KeepAspectRatio, Qt.SmoothTransformation) + scaled_pixmap = pixmap.scaled( + 100, pixmap.height(), Qt.KeepAspectRatio, Qt.SmoothTransformation + ) image_label.setPixmap(scaled_pixmap) image_label.setFixedWidth(100) container.addWidget(image_label) @@ -90,21 +92,27 @@ class Window: Window.root.addLayout(container) - @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_timer() -> None: + from .game import Game + + interval_ms = 3_000 + Window.timer = QTimer() + Window.timer.timeout.connect(Game.get_status) + Window.timer.start(interval_ms) + @staticmethod def start() -> None: Window.window.show() diff --git a/requirements.txt b/requirements.txt index 35345fd..06ad559 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ PySide6 == 6.7.2 -appdirs == 1.4.4 \ No newline at end of file +appdirs == 1.4.4 +wonderwords == 2.2.0 \ No newline at end of file