From 41022d7a5f0f61ce8b2b2ce41dbea42b5b4a6f01 Mon Sep 17 00:00:00 2001
From: RPINerd <RPINerd@gmail.com>
Date: Mon, 9 Dec 2024 19:47:28 -0500
Subject: [PATCH] Documentation and formatting update, upgrading to Ruff and
 stricter rules

---
 spacetrader.py             |   3 +-
 src/commander.py           |  13 ++-
 src/constants.py           | 208 +++++++++++++++++++++++++------------
 src/screens/char_create.py |  28 ++---
 src/screens/gamescreens.py |   3 +-
 src/ui_actions.py          |   6 +-
 src/universe.py            |  22 ++--
 src/utils.py               |   4 +-
 8 files changed, 175 insertions(+), 112 deletions(-)

diff --git a/spacetrader.py b/spacetrader.py
index b9cc933..b7543d3 100644
--- a/spacetrader.py
+++ b/spacetrader.py
@@ -40,13 +40,12 @@ def _center_window(self, screen_x: int, screen_y: int) -> str:
         x_adj = int((screen_x / 2) - (res / 2))
         y_adj = int((screen_y / 2) - (res / 2))
 
-        return f"{str(res)}x{str(res)}+{x_adj}+{y_adj}"
+        return f"{res!s}x{res!s}+{x_adj}+{y_adj}"
 
     def _load_assets(self):
         """
         Loads all game assets, currently just pointers to directories
         """
-
         # Load the configuration file
         # self.config = configparser.ConfigParser()
         # self.config.read(os.path.join("src/config", "config.ini"))
diff --git a/src/commander.py b/src/commander.py
index 14a2380..972978a 100644
--- a/src/commander.py
+++ b/src/commander.py
@@ -1,5 +1,6 @@
 """
     Space Trader | RPINerd, 2024
+
     An elite-inspired space trading RPG originally on PalmOS
 
     Commander Module
@@ -67,7 +68,7 @@ def pay_interest(self):
         self.debt = self.debt * 1.1
 
     def pay_insurance(self):
-        #! AI generated placeholder
+        # ! AI generated placeholder
         insurance = self.ship.get_value() * INSURANCE_RATE
         if self.credits > insurance:
             self.credits -= insurance
@@ -145,16 +146,14 @@ def mod_random_skill(self, amount: int):
 
         param amount: The amount to modify the skill by.
         """
-
         # Create a sublist of skills that will be within the bounds
         skills = [skill for skill in self.get_skills() if 1 <= skill + amount <= MAXSKILL]
 
         # If there are no skills that can be modified, return
         if not skills:
             return
-        else:
-            # Choose a random skill from the sublist
-            skill = random.choice(skills)
+        # Choose a random skill from the sublist
+        skill = random.choice(skills)
 
-            # Modify the skill by the given amount
-            skill += amount
+        # Modify the skill by the given amount
+        skill += amount
diff --git a/src/constants.py b/src/constants.py
index ca9e5df..38f04ad 100644
--- a/src/constants.py
+++ b/src/constants.py
@@ -1,5 +1,6 @@
 """
     Space Trader | RPINerd, 2024
+
     An elite-inspired space trading RPG originally on PalmOS
 
     Constants Module
@@ -86,9 +87,8 @@
 
 
 class Activity:
-    """
-    General class to associate an int with a level of activity
-    """
+
+    """Enum-esque class to associate an int with an activity level"""
 
     ABSENT = 0
     MINIMAL = 1
@@ -100,7 +100,7 @@ class Activity:
     SWARMS = 7
     UNAVAILABLE = 100
 
-    NAMES = [
+    NAMES = (
         "Absent",
         "Minimal",
         "Few",
@@ -110,16 +110,25 @@ class Activity:
         "Abundant",
         "Swarms",
         "Unavailable",
-    ]
+    )
 
     @classmethod
     def name(cls, activity: int) -> str:
+        """
+        Provides the name of the activity level
+
+        Raises:
+            ValueError on invalid index given
+        """
         if activity < 0 or activity >= len(cls.NAMES):
             raise ValueError(f"Invalid activity: {activity}")
         return cls.NAMES[activity]
 
 
 class TechLevel:
+
+    """Enum-esque class to associate an int with a tech level"""
+
     PRE_AGRICULTURAL = 0
     AGRICULTURAL = 1
     MEDIEVAL = 2
@@ -130,7 +139,7 @@ class TechLevel:
     HI_TECH = 7
     UNAVAILABLE = 8
 
-    NAMES = [
+    NAMES = (
         "Pre-Agricultural",
         "Agricultural",
         "Medieval",
@@ -140,19 +149,24 @@ class TechLevel:
         "Post-Industrial",
         "Hi-Tech",
         "Unavailable",
-    ]
+    )
 
     @classmethod
     def name(cls, tech: int) -> str:
+        """
+        Provides the name of the tech level
+
+        Raises:
+            ValueError on invalid index given
+        """
         if tech < 0 or tech >= len(cls.NAMES):
             raise ValueError(f"Invalid tech level: {tech}")
         return cls.NAMES[tech]
 
 
 class Size:
-    """
-    General class to associate an int with the size of a planet
-    """
+
+    """Enum-esque class to associate an int with a size"""
 
     TINY = 0
     SMALL = 1
@@ -161,16 +175,25 @@ class Size:
     HUGE = 4
     GARGANTUAN = 5
 
-    NAMES = ["Tiny", "Small", "Medium", "Large", "Huge", "Gargantuan"]
+    NAMES = ("Tiny", "Small", "Medium", "Large", "Huge", "Gargantuan")
 
     @classmethod
     def name(cls, size: int) -> str:
+        """
+        Provides the name of the size
+
+        Raises:
+            ValueError on invalid index given
+        """
         if size < 0 or size >= len(cls.NAMES):
             raise ValueError(f"Invalid size: {size}")
         return cls.NAMES[size]
 
 
 class SpecialResource:
+
+    """Enum-esque class to associate an int with a special resource"""
+
     NOTHING = 0
     MINERAL_RICH = 1
     MINERAL_POOR = 2
@@ -185,7 +208,7 @@ class SpecialResource:
     ARTISTIC = 11
     WARLIKE = 12
 
-    NAMES = [
+    NAMES = (
         "Nothing special",  # Uneventful
         "Mineral rich",  # produce Ore
         "Mineral poor",  # Ore in demand
@@ -199,20 +222,30 @@ class SpecialResource:
         "Special herbs",  # produce Narcotics
         "Artistic populace",  # Narcotics in demand
         "Warlike populace",  # Weapons in demand
-    ]
+    )
 
     @classmethod
     def name(cls, resource: int) -> str:
+        """
+        Provides the name of the special resource
+
+        Raises:
+            ValueError on invalid index given
+        """
         if resource < 0 or resource >= len(cls.NAMES):
             raise ValueError(f"Invalid resource: {resource}")
         return cls.NAMES[resource]
 
     @staticmethod
     def random() -> int:
+        """Gives the index value of a random special resource"""
         return randint(1, 12)
 
 
 class SocietalPressure:
+
+    """Enum-esque class to associate an int with a societal pressure"""
+
     NONE = 0
     WAR = 1
     PLAGUE = 2
@@ -222,7 +255,7 @@ class SocietalPressure:
     CROPFAILURE = 6
     EMPLOYMENT = 7
 
-    NAMES = [
+    NAMES = (
         "under no particular pressure",  # Uneventful
         "at war",  # Ore and Weapons in demand
         "ravaged by a plague",  # Medicine in demand
@@ -231,21 +264,37 @@ class SocietalPressure:
         "suffering from a cold spell",  # Furs in demand
         "suffering from a crop failure",  # Food in demand
         "lacking enough workers",  # Machinery and Robots in demand
-    ]
+    )
 
     @classmethod
     def name(cls, pressure: int) -> str:
+        """
+        Provides the flavor text of the societal pressure
+
+        Args:
+            pressure: int
+
+        Raises:
+            ValueError on invalid index given
+
+        Returns:
+            str: Flavor text for the corresponding societal pressure
+        """
         if pressure < 0 or pressure >= len(cls.NAMES):
             raise ValueError(f"Invalid pressure: {pressure}")
         return cls.NAMES[pressure]
 
     @staticmethod
     def random() -> int:
+        """Gives the index value of a random societal pressure"""
         return randint(1, 7)
 
 
 # Character
 class Skills:
+
+    """Enum-esque class to associate an int with a skill"""
+
     NONE = 0
     PILOT = 1
     FIGHTER = 2
@@ -254,22 +303,40 @@ class Skills:
 
 
 class Difficulty:
+
+    """Enum-esque class to associate an int with a difficulty level"""
+
     BEGINNER = 0
     EASY = 1
     NORMAL = 2
     HARD = 3
     IMPOSSIBLE = 4
 
-    NAMES = ["Beginner", "Easy", "Normal", "Hard", "Impossible"]
+    NAMES = ("Beginner", "Easy", "Normal", "Hard", "Impossible")
 
     @classmethod
     def name(cls, difficulty: int) -> str:
+        """
+        Provides the name of the difficulty level
+
+        Args:
+            difficulty: int
+
+        Raises:
+            ValueError on invalid index given
+
+        Returns:
+            str: Name of the difficulty level
+        """
         if difficulty < 0 or difficulty >= len(cls.NAMES):
             raise ValueError(f"Invalid difficulty: {difficulty}")
         return cls.NAMES[difficulty]
 
 
 class CriminalRecord:
+
+    """Enum-esque class to associate an int with a criminal record"""
+
     PSYCHOPATH = 0
     VILLAIN = 1
     CRIMINAL = 2
@@ -282,40 +349,44 @@ class CriminalRecord:
     HERO = 9
     ERRNO = 10
 
-    NAMES = {
-        PSYCHOPATH: "Psychopath",
-        VILLAIN: "Villain",
-        CRIMINAL: "Criminal",
-        CROOK: "Crook",
-        DUBIOUS: "Dubious",
-        CLEAN: "Clean",
-        LAWFUL: "Lawful",
-        TRUSTED: "Trusted",
-        LIKED: "Liked",
-        HERO: "Hero",
-        ERRNO: "ERRNO",
-    }
-
-    SCORES = {
-        PSYCHOPATH: -100,
-        VILLAIN: -70,
-        CRIMINAL: -30,
-        CROOK: -10,
-        DUBIOUS: -5,
-        CLEAN: 0,
-        LAWFUL: 5,
-        TRUSTED: 10,
-        LIKED: 25,
-        HERO: 75,
-        ERRNO: 100,
-    }
+    NAMES = (
+        "Psychopath",
+        "Villain",
+        "Criminal",
+        "Crook",
+        "Dubious",
+        "Clean",
+        "Lawful",
+        "Trusted",
+        "Liked",
+        "Hero",
+        "ERRNO",
+    )
+
+    SCORES = (
+        -100,
+        -70,
+        -30,
+        -10,
+        -5,
+        0,
+        5,
+        10,
+        25,
+        75,
+        100,
+    )
 
     @staticmethod
     def get_record_string(record: int) -> str:
+        """Provides the name of the criminal record"""
         return CriminalRecord.NAMES[record]
 
 
 class CombatReputation:
+
+    """Enum-esque class to associate an int with a combat reputation"""
+
     HARMLESS = 0
     MOSTLY_HARMLESS = 1
     POOR = 2
@@ -327,34 +398,35 @@ class CombatReputation:
     ELITE = 8
     BORG = 9
 
-    NAMES = {
-        HARMLESS: "Harmless",
-        MOSTLY_HARMLESS: "Mostly Harmless",
-        POOR: "Poor",
-        AVERAGE: "Average",
-        ABOVE_AVERAGE: "Above Average",
-        COMPETENT: "Competent",
-        DANGEROUS: "Dangerous",
-        DEADLY: "Deadly",
-        ELITE: "Elite",
-        BORG: "Borg",
-    }
-
-    SCORES = {
-        HARMLESS: 0,
-        MOSTLY_HARMLESS: 10,
-        POOR: 20,
-        AVERAGE: 40,
-        ABOVE_AVERAGE: 80,
-        COMPETENT: 150,
-        DANGEROUS: 300,
-        DEADLY: 600,
-        ELITE: 1500,
-        BORG: 3000,
-    }
+    NAMES = (
+        "Harmless",
+        "Mostly Harmless",
+        "Poor",
+        "Average",
+        "Above Average",
+        "Competent",
+        "Dangerous",
+        "Deadly",
+        "Elite",
+        "Borg",
+    )
+
+    SCORES = (
+        0,
+        10,
+        20,
+        40,
+        80,
+        150,
+        300,
+        600,
+        1500,
+        3000,
+    )
 
     @staticmethod
     def get_reputation_string(reputation: int) -> str:
+        """Provides the name of the combat reputation"""
         return CombatReputation.NAMES[reputation]
 
 
diff --git a/src/screens/char_create.py b/src/screens/char_create.py
index e85f67c..1bd5228 100644
--- a/src/screens/char_create.py
+++ b/src/screens/char_create.py
@@ -12,6 +12,7 @@
 
 
 class StatAdjuster(ttk.Frame):
+
     """
     A frame that contains a label, a decrement button, a value label, and an increment button.
     """
@@ -148,19 +149,18 @@ def cmdr_create(self) -> None:
         if points_pool.get() != 0:
             print("You have unspent skill points!")
             return
-        elif self.cmdr_name.get() == "":
+        if self.cmdr_name.get() == "":
             print("You must enter a name!")
             return
-        else:
-            cmdr = Commander(
-                self.cmdr_name.get(),
-                self.pilot_skill.get_value(),
-                self.fighter_skill.get_value(),
-                self.trader_skill.get_value(),
-                self.engineer_skill.get_value(),
-            )
-            GAME["commander"] = cmdr
-            GAME["difficulty"] = self.diff_current_value
-            print(cmdr.pprint())
-            self.destroy()
-            self.parent.manager.build_screens()
+        cmdr = Commander(
+            self.cmdr_name.get(),
+            self.pilot_skill.get_value(),
+            self.fighter_skill.get_value(),
+            self.trader_skill.get_value(),
+            self.engineer_skill.get_value(),
+        )
+        GAME["commander"] = cmdr
+        GAME["difficulty"] = self.diff_current_value
+        print(cmdr.pprint())
+        self.destroy()
+        self.parent.manager.build_screens()
diff --git a/src/screens/gamescreens.py b/src/screens/gamescreens.py
index 77b3c45..a8de9be 100644
--- a/src/screens/gamescreens.py
+++ b/src/screens/gamescreens.py
@@ -1,4 +1,3 @@
-import tkinter as tk
 from random import randint
 from tkinter import ttk
 
@@ -34,7 +33,7 @@ def create_widgets(self):
             ttk.Label(self.info_frame, text=heading, style="Heading.TLabel", justify="left").grid(
                 row=i, column=0, sticky="ew"
             )
-        #! Placeholder content
+        # ! Placeholder content
         for i, stat in enumerate(system_info):
             ttk.Label(self.info_frame, text=stat, justify="left").grid(row=i, column=1, sticky="ew")
         self.info_frame.pack(fill="x", expand=True)
diff --git a/src/ui_actions.py b/src/ui_actions.py
index 8f86277..1537cd2 100644
--- a/src/ui_actions.py
+++ b/src/ui_actions.py
@@ -98,7 +98,7 @@ def get_ware_list() -> list[str]:
 
 def get_bays() -> str:
     # TODO placeholder value, not currently tracked
-    #return f"{c.GAME["commander"].ship.bays} bays"
+    # return f"{c.GAME["commander"].ship.bays} bays"
     return "Bays: 3/25"
 
 
@@ -122,7 +122,7 @@ def get_equip_sold() -> list[str]:
         for _, equip in equips.items():
             if equip.tech_level == e.TechLevel.UNAVAILABLE:
                 continue
-            elif equip.tech_level <= current_system_tech:
+            if equip.tech_level <= current_system_tech:
                 sold_equipment.append(("", equip.name, f"{equip.price} cr."))
             else:
                 sold_equipment.append(("x", equip.name, "not sold"))
@@ -157,7 +157,7 @@ def get_ship_value() -> str:
 
 def get_no_claim() -> str:
     # TODO placeholder until I figure out how this is calculated in source
-    return f"0%"
+    return "0%"
 
 
 def get_insurance_rate() -> str:
diff --git a/src/universe.py b/src/universe.py
index 3f73537..20323cf 100644
--- a/src/universe.py
+++ b/src/universe.py
@@ -1,5 +1,6 @@
 """
     Space Trader | RPINerd, 2024
+
     An elite-inspired space trading RPG originally on PalmOS
 
     Universe Module
@@ -526,6 +527,7 @@
 
 
 class Planet:
+
     """
     Object representing a single planet in the game world.
 
@@ -704,15 +706,13 @@ def get_special_resource(self) -> int:
         if self.visited:
             return self.special_resource
         # TODO maybe not random here?
-        else:
-            self.special_resource = SpecialResource.random()
-            return self.special_resource
+        self.special_resource = SpecialResource.random()
+        return self.special_resource
 
     def initialize_trade_items(self):
         """
         Set the starting quantity of each trade good for the planet
         """
-
         for item_id in Ware.enum():
 
             # Make sure the item is allowed to be traded
@@ -743,8 +743,7 @@ def initialize_trade_items(self):
             self.trade_items[item_id] = self.trade_items[item_id] - randint(1, 10) + randint(1, 10)
 
             # Finally just make sure it's not negative
-            if self.trade_items[item_id] < 0:
-                self.trade_items[item_id] = 0
+            self.trade_items[item_id] = max(self.trade_items[item_id], 0)
 
     def is_item_traded(self, item) -> bool:
         """
@@ -754,18 +753,16 @@ def is_item_traded(self, item) -> bool:
 
         return: bool - whether the item can be traded
         """
-
         if item not in [Ware.FIREARMS, Ware.NARCOTICS]:
             return True
 
         if item == Ware.FIREARMS:
             return self.government.firearms_ok()
 
-        elif item == Ware.NARCOTICS:
+        if item == Ware.NARCOTICS:
             return self.government.drugs_ok()
 
-        else:
-            raise ValueError(f"Item ID {item} not valid!")
+        raise ValueError(f"Item ID {item} not valid!")
 
     def item_used(self, item):
         raise NotImplementedError("Planet.item_used not implemented")
@@ -951,6 +948,7 @@ def show_quest_button(self):
 
 
 class Universe:
+
     """
     Responsible for managing the game world, including
     planets locations and attributes.
@@ -966,7 +964,6 @@ def generate_planets(self):
         """
         Generate the planets for the game world.
         """
-
         for id, planet_name in PLANET_NAMES.items():
 
             planet_size = randint(0, 5)
@@ -1005,7 +1002,6 @@ def pick_valid_xy(self, id: int) -> tuple[int, int]:
         there is likely a good way to refactor this, if nothing else as a
         good exercise in algorithm design!
         """
-
         x: int = 0
         y: int = 0
 
@@ -1047,7 +1043,6 @@ def extra_planet_shuffle(self):
         Apparently without this extra step, the planets with names at the beginning
         of the alphabet are all clustered in the center of the galaxy.
         """
-
         for planet in self.planets.values():
             i = randint(0, len(self.planets) - 1)
             if not wormhole_exists(self.wormholes, i, -1):
@@ -1100,7 +1095,6 @@ def wormhole_exists(wormholes: list[int], a: int, b: int) -> bool:
 
     returns: True if wormhole exists, False otherwise
     """
-
     # TODO bit of a mess, probably should have small separate functions for each check
     if a in wormholes:
 
diff --git a/src/utils.py b/src/utils.py
index e4fd911..3c23487 100644
--- a/src/utils.py
+++ b/src/utils.py
@@ -1,5 +1,6 @@
 """
     Space Trader | RPINerd, 2024
+
     An elite-inspired space trading RPG originally on PalmOS
 
     Utils Module
@@ -39,7 +40,6 @@ def windows_load_font(cls, font_path: Union[str, bytes], private: bool = True, e
         Function taken from:
         https://stackoverflow.com/questions/11993290/truly-custom-font-in-tkinter/30631309#30631309
         """
-
         from ctypes import byref, create_string_buffer, create_unicode_buffer, windll
 
         FR_PRIVATE = 0x10
@@ -65,7 +65,7 @@ def load_font(cls, font_path: str) -> bool:
             return cls.windows_load_font(font_path, private=True, enumerable=False)
 
         # Linux
-        elif sys.platform.startswith("linux"):
+        if sys.platform.startswith("linux"):
             try:
                 shutil.copy(font_path, os.path.expanduser(cls.linux_font_path))
                 return True