Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/python-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install flake8 pytest
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
pip install poetry
poetry install --no-interaction --no-root --with dev
- name: Lint with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
poetry run flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
poetry run flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Test with pytest
run: |
pytest
poetry run pytest
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ A game based on electricity market coupling
1. Clone the repository
2. Set up a virtual environment with Python 3.12
3. Install poetry `pip install poetry`
4. Install dependencies with `poetry install`
4. Install dependencies with `poetry install --no-root`
131 changes: 129 additions & 2 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
[tool.black]
line-length = 88
line-length = 120
skip-string-normalization = true
target-version = ["py312"]

[tool.flake8]
max-line-length = 120

[tool.poetry]
name = "power-flow-game"
version = "0.0.0"
Expand All @@ -18,3 +21,6 @@ numpy = "^2.2.5"

[tool.poetry.group.dev.dependencies]
black = "^25.1.0"
flake8 = "^7.2.0"
pytest = "^8.3.5"
flake8-pyproject = "^1.2.3"
73 changes: 67 additions & 6 deletions src/engine/engine.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,78 @@
from src.models.event import Event
from src.models.event import (
Event,
EngineEvent,
UpdateBidEvent,
BuyAssetEvent,
EndTurnEvent,
)
from src.models.game_state import GameState


class Engine:
def __init__(self, game_state: GameState) -> None:
self.game_state = game_state

def handle_event(self, event: Event) -> None:
@classmethod
def handle_event(cls, game_state: GameState, event: Event) -> tuple[GameState, list[EngineEvent]]:
"""
Events happen every time a player takes an action or a timer runs out.
Every time an event occurs, the engine is informed and it can then:
-Update the game state
-Send messages back to the player interface if required
:param event:
:param game_state: The current state of the game
:param event: The triggering event
:return: The new game state and a list of events to be sent to the player interface
"""
# Handle the event based on its type
if isinstance(event, UpdateBidEvent):
return cls.handle_update_bid_event(game_state, event)
elif isinstance(event, BuyAssetEvent):
return cls.handle_buy_asset_event(game_state, event)
elif isinstance(event, EndTurnEvent):
return cls.handle_end_turn_event(game_state, event)
else:
raise NotImplementedError(f"Event type {type(event)} not implemented.")

@classmethod
def handle_update_bid_event(
cls,
game_state: GameState,
event: Event,
) -> tuple[GameState, list[EngineEvent]]:
"""
Handle an update bid event.
:param game_state: The current state of the game
:param event: The triggering event
:return: The new game state and a list of events to be sent to the player interface
"""
# TODO Update bids in the game state and then return updated game state and maybe engine events
raise NotImplementedError()

@classmethod
def handle_buy_asset_event(
cls,
game_state: GameState,
event: Event,
) -> tuple[GameState, list[EngineEvent]]:
"""
Handle a buy asset event.
:param game_state: The current state of the game
:param event: The triggering event
:return: The new game state and a list of events to be sent to the player interface
"""
# TODO Update assets ownership in the game state and then return updated game state and maybe engine events
raise NotImplementedError()

@classmethod
def handle_end_turn_event(
cls,
game_state: GameState,
event: Event,
) -> tuple[GameState, list[EngineEvent]]:
"""
Handle an end turn event.
:param game_state: The current state of the game
:param event: The triggering event
:return: The new game state and a list of events to be sent to the player interface
"""
# TODO Update the player to indicate that their turn has ended.
# If in the current phase the players need to take turns (asynchronous), then go to the next player
# If all turns are over, then do some special action and go to the next phase?
raise NotImplementedError()
16 changes: 16 additions & 0 deletions src/engine/market_coupling.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from src.models.assets import AssetRepo
from src.models.market_coupling_result import MarketCouplingResult
from src.models.transmission import TransmissionRepo


class MarketCouplingCalculator:
@classmethod
def run(cls, assets: AssetRepo, transmission: TransmissionRepo) -> MarketCouplingResult:
"""
Run the market coupling algorithm.
:param assets: The asset repository
:param transmission: The transmission repository
:return: The market coupling result
"""
# TODO Implement the market coupling algorithm
raise NotImplementedError("Market coupling algorithm not implemented.")
1 change: 1 addition & 0 deletions src/engine/new_game.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# TODO Handle the creation of a new game
10 changes: 10 additions & 0 deletions src/engine/rules.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from dataclasses import dataclass


@dataclass(frozen=True)
class Rules:
max_connections_per_bus: int


def get_rules() -> Rules:
return Rules(max_connections_per_bus=7)
Loading