miron / NeonCore

Terminal based Cyberpunk Tabletop RPG with Nostr as database and openAI API compatible commands
3 stars 1 forks source link

Design Patterns #12

Open miron opened 1 year ago

miron commented 1 year ago

There are several design patterns that could be suitable for a turn-based distributed RPG game. Some design patterns that may be relevant include:

The Strategy pattern, which allows you to define a set of interchangeable algorithms or behaviors and switch between them at runtime. This could be useful for implementing different character classes or abilities in the game.

from abc import ABC, abstractmethod

class Weapon(ABC):
    @abstractmethod
    def attack(self):
        pass

class Sword(Weapon):
    def attack(self):
        print("Swinging sword")

class Bow(Weapon):
    def attack(self):
        print("Shooting arrow")

class MagicWand(Weapon):
    def attack(self):
        print("Casting spell")

class Player:
    def __init__(self, weapon: Weapon):
        self.weapon = weapon

    def attack(self):
        self.weapon.attack()

player = Player(Sword())
player.attack()  # Swinging sword

player.weapon = Bow()
player.attack()  # Shooting arrow

player.weapon = MagicWand()
player.attack()  # Casting spell

The Singleton pattern, which ensures that a class has only one instance and provides a global point of access to it. This could be useful for ensuring that there is only one instance of certain game objects, such as a player character.

class Singleton:
     _singletons = {}
    def __new__(cls, *args, **kwds):
        if cls not in cls._singletons:
            cls._singletons[cls] = obj = super().__new__(cls)
            obj._initialized = False 
        return cls._singletons[cls]

The Command pattern, which encapsulates a request or action as an object that can be passed to different parts of the program, stored in a queue, or logged, without the sender of the request having to know anything about the request or the object that handles it. This could be useful for implementing different checks or skill tests in the game.

from abc import ABC, abstractmethod

# Command interface
class Command(ABC):
    @abstractmethod
    def execute(self):
        pass

# Concrete command classes
class JumpCommand(Command):
    def execute(self):
        print("Jump!")

class FireCommand(Command):
    def execute(self):
        print("Fire weapon!")

# Invoker class
class InputHandler:
    def __init__(self):
        self.commands = {}

    def set_command(self, key, command):
        self.commands[key] = command

    def handle_input(self, key):
        if key in self.commands:
            self.commands[key].execute()

# Client code
input_handler = InputHandler()
input_handler.set_command('space', JumpCommand())
input_handler.set_command('f', FireCommand())
input_handler.handle_input('space')
input_handler.handle_input('f')

The Factory pattern, which uses a factory class to create the appropriate story class based on the settings.

An event-driven architecture, you could use events to trigger the start of a new turn, to notify players of changes in the game state, or to trigger certain actions based on player interactions. Additionally, you could use events to trigger different parts of the story, allowing for more flexibility and ease of modification. Overall, the use of event-driven architecture could help improve the modularity and maintainability of your game.

In addition, it may be appropriate to follow the SOLID principles for designing maintainable and scalable software. It is also a good idea to use a plugin or modular system for allowing other developers to easily switch out different stories in your game, and to use a configuration file or settings file for making it easy to change settings.

miron commented 1 year ago

The Template Method pattern could be applicable in a turn-based distributed RPG game, as it is useful for defining the basic structure of an algorithm and allowing subclasses to implement specific steps in the algorithm. This pattern can be useful for defining the basic structure of different types of game events or actions, and allowing subclasses to implement the specific behavior for each event or action.

For example, you could define a base Action class with a template method that outlines the basic steps for executing an action, such as validating the action, applying any effects or damage, and updating the game state. Subclasses could then implement the specific behavior for different types of actions, such as an attack action or a healing action.

The Template Method pattern can also be useful for creating a consistent user interface across different parts of the game. For example, you could define a base View class with a template method that outlines the basic steps for rendering a view, such as setting up the layout and rendering the content. Subclasses could then implement the specific behavior for different types of views, such as a character sheet or an inventory screen.

Overall, the Template Method pattern can be a useful tool for creating a flexible and extensible architecture for a turn-based distributed RPG game.

from abc import ABC, abstractmethod

class GameLevel(ABC):
    @abstractmethod
    def spawn_enemies(self):
        pass

    @abstractmethod
    def handle_input(self):
        pass

    @abstractmethod
    def update_entities(self):
        pass

    @abstractmethod
    def render_screen(self):
        pass

    def play(self):
        self.spawn_enemies()
        while True:
            self.handle_input()
            self.update_entities()
            self.render_screen()
            if self.is_level_completed():
                print("Level completed!")
                break

    def is_level_completed(self):
        return False

class Level1(GameLevel):
    def spawn_enemies(self):
        print("Spawning level 1 enemies")

    def handle_input(self):
        print("Handling level 1 input")

    def update_entities(self):
        print("Updating level 1 entities")

    def render_screen(self):
        print("Rendering level 1 screen")

class Level2(GameLevel):
    def spawn_enemies(self):
        print("Spawning level 2 enemies")

    def handle_input(self):
        print("Handling level 2 input")

    def update_entities(self):
        print("Updating level 2 entities")

    def render_screen(self):
        print("Rendering level 2 screen")

    def is_level_completed(self):
        return True

level1 = Level1()
level1.play()

level2 = Level2()
level2.play()