From 0f10f22345cd560a47b3a51627c8abeadf01541c Mon Sep 17 00:00:00 2001 From: cheezedoodle2 Date: Mon, 3 Apr 2023 23:19:16 -0700 Subject: [PATCH] Added simulation files. --- .vscode/launch.json | 12 ++++++++++ simulation/HotdogSimulation.py | 18 +++++++++++++++ simulation/README.md | 8 +++++++ simulation/Simulation.py | 31 ++++++++++++++++++++++++++ simulation/SimulationRunner.py | 40 ++++++++++++++++++++++++++++++++++ 5 files changed, 109 insertions(+) create mode 100644 .vscode/launch.json create mode 100644 simulation/HotdogSimulation.py create mode 100644 simulation/README.md create mode 100644 simulation/Simulation.py create mode 100644 simulation/SimulationRunner.py diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..5a7d733 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,12 @@ +{ + "configurations": [ + { + "name": "Python: HotdogSimulation", + "type": "python", + "request": "launch", + "program": "simulation/SimulationRunner.py", + "justMyCode": true, + "args": "./HotdogSimulation.py" + } + ] +} diff --git a/simulation/HotdogSimulation.py b/simulation/HotdogSimulation.py new file mode 100644 index 0000000..1d137ff --- /dev/null +++ b/simulation/HotdogSimulation.py @@ -0,0 +1,18 @@ +from Simulation import Simulation +class HotdogSimulation(Simulation): + def __init__(self) -> None: + self.ticks_left = 5 + + def start(self): + print(f"DEBUG: simulation started.") + def use(self): + print(f"DEBUG: someone ate the hot dog! 🌭") + def tick(self): + self.ticks_left -= 1 + if self.ticks_left == 0: + print(f"DEBUG: simulation out of ticks, expiring.") + return False + return True + def stop(self): + print(f"DEBUG: simulation stopped.") + pass \ No newline at end of file diff --git a/simulation/README.md b/simulation/README.md new file mode 100644 index 0000000..7e42663 --- /dev/null +++ b/simulation/README.md @@ -0,0 +1,8 @@ +This is a simple example of a pluggable object simulator. If you run the +SimulatorRunner file, it'll throw up a GUI file picker if a simulation class +isn't specified on the command line. It will then: + +* Run the simulation class's `start()` method, +* Call its `tick()` method, +* Call its `use()` method, +* then call its `stop()` method once `tick()` returns false. \ No newline at end of file diff --git a/simulation/Simulation.py b/simulation/Simulation.py new file mode 100644 index 0000000..9596120 --- /dev/null +++ b/simulation/Simulation.py @@ -0,0 +1,31 @@ +from abc import ABC, abstractmethod + +class Simulation(ABC): + @abstractmethod + def start(self): + "Start the simulated object." + pass + + @abstractmethod + def tick(self) -> bool: + """ + Simulate one clock tick. + Returns: + bool: True if the simulation could advance one clock tick, or False if the object is expired. + """ + pass + + @abstractmethod + def use(self, *args, **kwargs): + """ + Use the simulated object. + Args: + args (tuple): A tuple of arguments. + kwargs (dict): A dictionary of key-value pairs of arguments. + """ + pass + + @abstractmethod + def stop(self): + "Stop the simulated object." + pass \ No newline at end of file diff --git a/simulation/SimulationRunner.py b/simulation/SimulationRunner.py new file mode 100644 index 0000000..302491c --- /dev/null +++ b/simulation/SimulationRunner.py @@ -0,0 +1,40 @@ +from importlib import import_module +import tkinter as tk +import os +import sys +from time import sleep +from tkinter import filedialog +from abc import ABC, abstractmethod + +class SimulationRunner: + def __init__(self, simulation) -> None: + self.simulation = simulation() + self.simulation.start() + while self.simulation.tick(): + self.simulation.use() + self.simulation.stop() + +if __name__ == '__main__': + if len(sys.argv) == 1: + # Create a hidden root window + root = tk.Tk() + root.withdraw() + + # Open the file chooser dialog + file_path = filedialog.askopenfilename() + print(f"Selected file: {file_path}") + else: + file_path = sys.argv[1] + + # Get the python file's directory and filename + module_dir, module_file = os.path.split(file_path) + # Get the python file's name without any extension + module_name, _ = os.path.splitext(module_file) + + # Add the module directory to sys.path so we can import it unqualified + sys.path.append(module_dir) + + simulation = import_module(module_name) + # Load the simulation module's simulation class, which should be the same + # name as the module name. + simulationrunner = SimulationRunner(getattr(simulation, module_name))