-
Notifications
You must be signed in to change notification settings - Fork 81
SimulationEngine infrastructure for 2D/3D modes #294
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
50a522f
01bff2a
d95dcd1
4dbc9ba
fdc2347
e4bc74a
92b798b
e8af848
485937a
1ab5e1d
e44680e
a2f83f2
5ffb875
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,62 @@ | ||||||||||||||||||||||||||||||||||
| """The simulation engine of pooltool""" | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| from __future__ import annotations | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| import attrs | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| from pooltool.evolution.event_based.detect import EventDetector | ||||||||||||||||||||||||||||||||||
| from pooltool.physics.dimensionality import Dim | ||||||||||||||||||||||||||||||||||
| from pooltool.physics.resolve import Resolver | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| @attrs.define | ||||||||||||||||||||||||||||||||||
| class SimulationEngine: | ||||||||||||||||||||||||||||||||||
| """A pluggable bundle of strategies used by the simulator. | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| Holds the strategies that define how a simulation is carried out: how events are | ||||||||||||||||||||||||||||||||||
| detected and how they are resolved. The simulator is handed an instance of this | ||||||||||||||||||||||||||||||||||
| class and routes work to its components. | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| Attributes: | ||||||||||||||||||||||||||||||||||
| resolver: | ||||||||||||||||||||||||||||||||||
| The strategy responsible for resolving events. | ||||||||||||||||||||||||||||||||||
| detector: | ||||||||||||||||||||||||||||||||||
| The strategy responsible for detecting the next event. | ||||||||||||||||||||||||||||||||||
| is_3d: | ||||||||||||||||||||||||||||||||||
| Whether the simulation supports the airborne motion state and ball-table | ||||||||||||||||||||||||||||||||||
| events. Validated at construction against the dimensionality capability | ||||||||||||||||||||||||||||||||||
| (``dim``) of every bundled strategy in ``resolver`` and ``detector``. | ||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| resolver: Resolver = attrs.field(factory=Resolver.default) | ||||||||||||||||||||||||||||||||||
| detector: EventDetector = attrs.field(factory=EventDetector.default) | ||||||||||||||||||||||||||||||||||
| is_3d: bool = False | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| def __attrs_post_init__(self) -> None: | ||||||||||||||||||||||||||||||||||
| self._validate_dimensionality() | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| def _validate_dimensionality(self) -> None: | ||||||||||||||||||||||||||||||||||
| required = Dim.THREE if self.is_3d else Dim.TWO | ||||||||||||||||||||||||||||||||||
| for bundle in (self.resolver, self.detector): | ||||||||||||||||||||||||||||||||||
| for field in attrs.fields(type(bundle)): | ||||||||||||||||||||||||||||||||||
| strategy = getattr(bundle, field.name) | ||||||||||||||||||||||||||||||||||
| if not attrs.has(type(strategy)): | ||||||||||||||||||||||||||||||||||
| continue | ||||||||||||||||||||||||||||||||||
| if not hasattr(strategy, "dim"): | ||||||||||||||||||||||||||||||||||
| raise AttributeError( | ||||||||||||||||||||||||||||||||||
| f"{type(bundle).__name__}.{field.name} " | ||||||||||||||||||||||||||||||||||
| f"({type(strategy).__name__}) is missing required " | ||||||||||||||||||||||||||||||||||
| f"'dim' attribute" | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
| if strategy.dim not in (required, Dim.BOTH): | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+43
to
+51
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Dimensionality validation is bypassable for non-attrs strategy implementations. Line 43 skips validation when a strategy instance is not an attrs class. That allows incompatible custom strategies to pass without Suggested fix- if not attrs.has(type(strategy)):
- continue
if not hasattr(strategy, "dim"):
raise AttributeError(
f"{type(bundle).__name__}.{field.name} "
f"({type(strategy).__name__}) is missing required "
f"'dim' attribute"
)📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||
| raise ValueError( | ||||||||||||||||||||||||||||||||||
| f"{type(bundle).__name__}.{field.name} " | ||||||||||||||||||||||||||||||||||
| f"({type(strategy).__name__}) has dim={strategy.dim}, " | ||||||||||||||||||||||||||||||||||
| f"incompatible with is_3d={self.is_3d}; " | ||||||||||||||||||||||||||||||||||
| f"expected {required} or {Dim.BOTH}" | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| __all__ = [ | ||||||||||||||||||||||||||||||||||
| "SimulationEngine", | ||||||||||||||||||||||||||||||||||
| ] | ||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| from __future__ import annotations | ||
|
|
||
| from pooltool.physics.utils import get_ball_energy | ||
| from pooltool.system.datatypes import System | ||
|
|
||
|
|
||
| def _system_has_energy(system: System) -> bool: | ||
| """Return True if any ball in the system has kinetic energy. | ||
|
|
||
| Cue energy (e.g. ``system.cue.V0 > 0``) does not count. | ||
| """ | ||
| return any( | ||
| bool( | ||
| get_ball_energy( | ||
| ball.state.rvw, | ||
| ball.params.R, | ||
| ball.params.m, | ||
| ) | ||
| ) | ||
| for ball in system.balls.values() | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| from pooltool.evolution.event_based.detect.ball_ball import ( | ||
| BallBallDetection, | ||
| BallBallDetectionStrategy, | ||
| ) | ||
| from pooltool.evolution.event_based.detect.ball_cushion import ( | ||
| BallCCushionDetection, | ||
| BallCCushionDetectionStrategy, | ||
| BallLCushionDetection, | ||
| BallLCushionDetectionStrategy, | ||
| ) | ||
| from pooltool.evolution.event_based.detect.ball_pocket import ( | ||
| BallPocketDetection, | ||
| BallPocketDetectionStrategy, | ||
| ) | ||
| from pooltool.evolution.event_based.detect.detector import EventDetector | ||
| from pooltool.evolution.event_based.detect.stick_ball import ( | ||
| StickBallDetection, | ||
| StickBallDetectionStrategy, | ||
| ) | ||
|
|
||
| __all__ = [ | ||
| "EventDetector", | ||
| "BallBallDetection", | ||
| "BallBallDetectionStrategy", | ||
| "BallCCushionDetection", | ||
| "BallCCushionDetectionStrategy", | ||
| "BallLCushionDetection", | ||
| "BallLCushionDetectionStrategy", | ||
| "BallPocketDetection", | ||
| "BallPocketDetectionStrategy", | ||
| "StickBallDetection", | ||
| "StickBallDetectionStrategy", | ||
| ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix broken
SimulationEnginecross-reference target.This anchor points to
pooltool.evolution.engine.SimulationEngine, but that module is now excluded from AutoAPI. Link to the exported API path (pooltool.evolution.SimulationEngine) instead.🔧 Suggested patch
📝 Committable suggestion
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)
[warning] 202-202: Link fragments should be valid
(MD051, link-fragments)
🤖 Prompt for AI Agents