Sync
This commit is contained in:
1
src/__init__.py
Normal file
1
src/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
pass
|
||||
7
src/expansion.py
Normal file
7
src/expansion.py
Normal file
@ -0,0 +1,7 @@
|
||||
class Expansion:
|
||||
def __init__(self, parent, globalConfig):
|
||||
setattr(parent, self.__class__.ID, self)
|
||||
|
||||
class PlayerExpansion:
|
||||
def __init__(self, player, localConfig):
|
||||
pass
|
||||
311
src/player_settings.py
Normal file
311
src/player_settings.py
Normal file
@ -0,0 +1,311 @@
|
||||
"""
|
||||
Needs to manage any number of players
|
||||
Needs to work with mulitple rounds/turns
|
||||
Needs to handle modifying number of players
|
||||
|
||||
"""
|
||||
|
||||
import abc
|
||||
import copy
|
||||
import json
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
_log = logging.getLogger('NoPE-Lib')
|
||||
|
||||
|
||||
class PlayersManager:
|
||||
"""
|
||||
Manager of players for a given game.
|
||||
Since this class implements most methods available to classic dict,
|
||||
you can think of this class as a python dict.
|
||||
|
||||
Attributes:
|
||||
gameID (str): The gameID of the active game
|
||||
|
||||
Methods:
|
||||
save:
|
||||
"""
|
||||
defaultPlayerConfig = {"flags": [], "expansions": {}, "games": {}}
|
||||
|
||||
def __init__(self, gameID: str=None, activePlayers: list[str]=None, playersPath: str='./players.json', loggerID: str='PlayersManager', includedExpansions: tuple[str]=None):
|
||||
"""
|
||||
Initialises a list of players.
|
||||
|
||||
Args:
|
||||
gameID (str): The ID of the game used in the configuration file.
|
||||
activePlayers (list of str): The names of the players that are playing. Defaults to none which includes all players.
|
||||
playersPath (str, optional): The path of the players.json file. Defaults to './players.json'.
|
||||
loggerID (str, optional): The ID used for logging. Defaults to 'Players'.
|
||||
"""
|
||||
|
||||
# Store the arguments
|
||||
self._log = _log.getChild(loggerID)
|
||||
self._currentGameID = gameID
|
||||
# Deal with the path
|
||||
self._playersPath = Path(playersPath)
|
||||
# Get the config file
|
||||
with open(self._playersPath, 'r') as f:
|
||||
self._cfg = json.load(f)
|
||||
# Create the players
|
||||
activePlayers = activePlayers if activePlayers is not None else self._cfg["players"].keys()
|
||||
self._player_data = {
|
||||
name: Player(name, self, **player_cfg)
|
||||
for name, player_cfg in self._cfg["players"].items()
|
||||
if name in activePlayers
|
||||
}
|
||||
|
||||
def __getitem__(self, playerName: str):
|
||||
"""
|
||||
Get a player object.
|
||||
If the player wasn't active, make them active.
|
||||
If the player didn't exist previously, create a default config and make them active.
|
||||
"""
|
||||
if playerName not in self._cfg["players"]:
|
||||
# Create the brand new player
|
||||
self._cfg["players"][playerName] = copy.deepcopy(self.defaultPlayerConfig)
|
||||
newPlayer = Player(playerName, self, **self._cfg["players"][playerName])
|
||||
# Make the player active
|
||||
self._player_data[playerName] = newPlayer
|
||||
self._log.debug(f"Created a new player called {playerName}")
|
||||
return newPlayer
|
||||
elif playerName not in self._player_data:
|
||||
# Fetch the player's data and make them active
|
||||
playerAdded = Player(playerName, self, **self._cfg["players"][playerName])
|
||||
self._player_data[playerName] = playerAdded
|
||||
self._log.debug(f"Fetched {playerName}'s data and made them active")
|
||||
return playerAdded
|
||||
else:
|
||||
return self._player_data[playerName]
|
||||
|
||||
def __setitem__(self, playerName: str, config: dict, makeNewPlayerObject=False):
|
||||
"""
|
||||
Replace a player's config with another one. It possible to also automatically replace the
|
||||
player object by specifying the corresponding argument.
|
||||
"""
|
||||
self._log.debug(f"Changed {playerName}'s config")
|
||||
if makeNewPlayerObject:
|
||||
previousInstance = self._player_data[playerName]
|
||||
self._player_data[playerName] = Player(playerName, self, **config)
|
||||
del previousInstance
|
||||
self._cfg["players"][playerName] = config
|
||||
|
||||
def __delitem__(self, playerName):
|
||||
self._log.debug(f"Removing {playerName} from active players")
|
||||
del self._player_data[playerName]
|
||||
|
||||
def __len__(self):
|
||||
return len(self._player_data)
|
||||
|
||||
def __iter__(self):
|
||||
return self._player_data.__iter__()
|
||||
|
||||
def __repr__(self):
|
||||
return f"Manager is playing {self.gameID} with {len(self._player_data)} active players"
|
||||
|
||||
@property
|
||||
def gameID(self):
|
||||
return self._currentGameID
|
||||
|
||||
@gameID.setter
|
||||
def gameID(self, gameID: str):
|
||||
self._currentGameID = gameID
|
||||
self._player_data = {name: Player(name, self, **cfg) for name, cfg in self._cfg["players"].items()}
|
||||
|
||||
@gameID.deleter
|
||||
def gameID(self):
|
||||
self._currentGameID = None
|
||||
self._player_data = {name: Player(name, self, **cfg) for name, cfg in self._cfg["players"].items()}
|
||||
|
||||
def keys(self):
|
||||
""" Iterator of the active players' names """
|
||||
return self._player_data.keys()
|
||||
|
||||
def values(self):
|
||||
""" Iterator of the active players' objects """
|
||||
return self._player_data.keys()
|
||||
|
||||
def items(self):
|
||||
""" Two iterators of the activate players' names and object """
|
||||
return self._player_data.items()
|
||||
|
||||
def save(self):
|
||||
with open(self._playersPath, 'w') as f:
|
||||
self._cfg = json.dump(f, self._cfg)
|
||||
|
||||
|
||||
class Player:
|
||||
"""
|
||||
|
||||
Attributes:
|
||||
flags:
|
||||
availableExpansions:
|
||||
expansionsConfig:
|
||||
gameSave: The game settings are not guaranteed to have data in it.
|
||||
gameState:
|
||||
|
||||
Methods:
|
||||
generateConfig:
|
||||
"""
|
||||
def __init__(self, name: str, manager: PlayersManager, **cfg):
|
||||
self._name = name
|
||||
self._manager = manager
|
||||
for key, val in cfg.items():
|
||||
setattr(self, "_" + key, val)
|
||||
|
||||
def __repr__(self):
|
||||
return f"Player {self._name} has {len(self._flags)} flag(s), {len(self._expansions)} expansions and {len(self._games)} saved game"
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def flags(self):
|
||||
return self._flags
|
||||
|
||||
@flags.setter
|
||||
def flags(self, newFlags):
|
||||
self._flags = newFlags
|
||||
# The container was changed and must be transmited to the manager
|
||||
self._manager[self._name] = self.generateConfig()
|
||||
|
||||
@property
|
||||
def expansionsConfig(self):
|
||||
return self._expansionsConfig
|
||||
|
||||
@expansionsConfig.setter
|
||||
def expansions(self, newExpansions):
|
||||
self._expansionsConfig = newExpansions
|
||||
# The container was changed and must be transmited to the manager
|
||||
self._manager[self._name] = self.generateConfig()
|
||||
|
||||
@property
|
||||
def gameSave(self):
|
||||
"""The save for the current game. If no configuration was found None is returned."""
|
||||
return self._games.get(self._manager.gameID)
|
||||
|
||||
@gameSave.setter
|
||||
def gameSave(self, newGameSave):
|
||||
self._games[self._manager.gameID] = newGameSave
|
||||
|
||||
def generateConfig(self):
|
||||
return {"flags": self._flags, "expansions": self._expansions, "games": self._games}
|
||||
|
||||
def punish(self, value, preferedExpansion: str=None):
|
||||
do_something = lambda value: value
|
||||
additionalInfos = {"expansionID": "challengeDB", "balancedValue": 0.2, "showOnScreen": "Do 100 push-up", "error": None, "done": False}
|
||||
# NOTE Make a result class instead and an error class
|
||||
additionalInfos = do_something(value)
|
||||
return additionalInfos
|
||||
|
||||
|
||||
class Expansion:
|
||||
"""
|
||||
|
||||
Attributes:
|
||||
|
||||
Methods:
|
||||
step:
|
||||
reset:
|
||||
close:
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def __init__(self):
|
||||
"""
|
||||
Raise an error if not available
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def step(self, action):
|
||||
"""
|
||||
Call close if an error is thrown
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def reset(self):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
|
||||
class ExpansionManager:
|
||||
"""
|
||||
Manager of the availability of the expansions.
|
||||
|
||||
Attributes:
|
||||
includedExpansions: tuple of str
|
||||
Container of the expansions to try making available
|
||||
releventExpansions: dict of Expansion
|
||||
Container of the relevent expansions
|
||||
"""
|
||||
tags = ["shock", "spice", "sour", "drink", "challenge"]
|
||||
|
||||
def __init__(self, playersManager: PlayersManager, includedExpansions: tuple[str]=None):
|
||||
self.playersManager = playersManager
|
||||
self._includedExpansions = tuple(includedExpansions) if includedExpansions is not None else ()
|
||||
self._releventExpansions = {} # TODO Populate the dictionnary
|
||||
|
||||
@property
|
||||
def includedExpansions(self):
|
||||
return self._includedExpansions
|
||||
|
||||
@includedExpansions.setter
|
||||
def includedExpansions(self, newIncluded: tuple[str]):
|
||||
self._includedExpansions = tuple(newIncluded)
|
||||
self._includedChanged()
|
||||
|
||||
@includedExpansions.deleter
|
||||
def includedExpansions(self):
|
||||
self._includedExpansions = ()
|
||||
|
||||
@property
|
||||
def releventExpansions(self):
|
||||
return self._releventExpansions
|
||||
|
||||
def _includedChanged(self):
|
||||
"""
|
||||
Compute the list of only the relevant expansions.
|
||||
The expansions that do not exists are excluded.
|
||||
The expansions that have no players assigned to them are excluded.
|
||||
The expansions that are not responding are excluded.
|
||||
"""
|
||||
pass
|
||||
|
||||
def _activePlayersChanged(self, activatePlayers):
|
||||
pass
|
||||
|
||||
def _errorOccured(self, expansionID):
|
||||
pass
|
||||
|
||||
def _expansionPlayersChanged(self, expansionID):
|
||||
pass
|
||||
|
||||
def resetExpansion(self, expansion: Expansion, suppressError: bool=False):
|
||||
"""
|
||||
If the expansion was relevent, close it.
|
||||
In any case, try creating a new
|
||||
"""
|
||||
# If the expansion was relevent, close it
|
||||
# Try creating a new instance of the expansion
|
||||
# Update the list of relevent expansions
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Test run to make sure nothing is flagrantly flawed
|
||||
configPath = Path(__file__).parent / "players.json"
|
||||
manager = PlayersManager(playersPath=configPath, gameID="gameID0")
|
||||
# Iteration
|
||||
for playerName in manager:
|
||||
print(playerName)
|
||||
# Modification of a players data
|
||||
brosef = manager["Brosef"]
|
||||
brosef.gameSave = [1]
|
||||
print(manager["Brosef"].gameSave)
|
||||
brosef.state = ["alive"]
|
||||
14
src/players.json
Normal file
14
src/players.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"expansions":
|
||||
{
|
||||
"shockColar1": {"players": ["Brosef"], "class": "pishock", "type": ["shock"]},
|
||||
"robotBarman": {"players": ["Tango", "TRS_MML"], "class": "roboticBarman", "type": ["drink"]},
|
||||
"challengeDB": {"players": ["TRS_MML"], "class": "challengeDataBase", "type": ["challenge"]},
|
||||
"sourCandy": {"players": [], "class": "sourCandy", "type": ["food"]}
|
||||
},
|
||||
"players": {
|
||||
"Brosef": {"flags": [], "expansions": {"exampleExpansion": {"playerOption": 5}}, "games": {"gameID0": 2}},
|
||||
"TRS_MML": {"flags": [], "expansions": {"exampleExpansion": {"playerOption": 5}}, "games": {"gameID0": 1}},
|
||||
"Tango": {"flags": [], "expansions": {"exampleExpansion": {"playerOption": 5}}, "games": {"gameID0": 0}}
|
||||
}
|
||||
}
|
||||
6
src/standardFlags.py
Normal file
6
src/standardFlags.py
Normal file
@ -0,0 +1,6 @@
|
||||
NO_ALCOHOL = 'no-alcohol'
|
||||
NO_SHOCK = 'no-shock'
|
||||
NO_SPICE = 'no-spice'
|
||||
NO_SOUR = 'no-sour'
|
||||
EASY_MODE = 'pussy-mode'
|
||||
HARD_MODE = 'hard-mode'
|
||||
Reference in New Issue
Block a user