mirror of
https://github.com/ZGCA-Forge/Elevator.git
synced 2026-02-10 09:45:21 +00:00
Compare commits
6 Commits
0.0.2
...
692b853101
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
692b853101 | ||
|
|
4c86816920 | ||
|
|
349511e00f | ||
|
|
cbfae640d1 | ||
|
|
de3fa68fa6 | ||
|
|
78395349b2 |
@@ -1,5 +1,5 @@
|
|||||||
[bumpversion]
|
[bumpversion]
|
||||||
current_version = 0.0.2
|
current_version = 0.0.4
|
||||||
commit = True
|
commit = True
|
||||||
tag = True
|
tag = True
|
||||||
tag_name = v{new_version}
|
tag_name = v{new_version}
|
||||||
|
|||||||
30
.github/ISSUE_TEMPLATE/bug_report.md
vendored
30
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -0,0 +1,30 @@
|
|||||||
|
---
|
||||||
|
name: Bug Report
|
||||||
|
about: Report a bug in the project
|
||||||
|
title: "[BUG] "
|
||||||
|
labels: bug
|
||||||
|
assignees: ""
|
||||||
|
---
|
||||||
|
|
||||||
|
**Version Information**
|
||||||
|
|
||||||
|
- elevator-py version: [e.g. v0.0.5]
|
||||||
|
- Python version: [e.g. 3.11]
|
||||||
|
|
||||||
|
**Bug Description**
|
||||||
|
A clear and concise description of the bug
|
||||||
|
|
||||||
|
**Steps to Reproduce**
|
||||||
|
|
||||||
|
1.
|
||||||
|
2.
|
||||||
|
3.
|
||||||
|
|
||||||
|
**Expected Behavior**
|
||||||
|
What you expected to happen
|
||||||
|
|
||||||
|
**Actual Behavior**
|
||||||
|
What actually happened
|
||||||
|
|
||||||
|
**Additional Context (Optional)**
|
||||||
|
Any other information that might help, such as error logs, screenshots, etc.
|
||||||
|
|||||||
20
README.md
20
README.md
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
[](https://badge.fury.io/py/elevatorpy)
|
[](https://badge.fury.io/py/elevator-py)
|
||||||
[](https://pypi.org/project/elevatorpy/)
|
[](https://pypi.org/project/elevator-py/)
|
||||||
[](https://github.com/ZGCA-Forge/Elevator/actions)
|
[](https://github.com/ZGCA-Forge/Elevator/actions)
|
||||||
[](https://zgca-forge.github.io/Elevator/)
|
[](https://zgca-forge.github.io/Elevator/)
|
||||||
|
|
||||||
@@ -27,21 +27,7 @@ Elevator Saga is a Python implementation of an elevator [simulation game](https:
|
|||||||
### Basic Installation
|
### Basic Installation
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install elevatorpy
|
pip install elevator-py
|
||||||
```
|
|
||||||
|
|
||||||
### With Development Dependencies
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pip install elevatorpy[dev]
|
|
||||||
```
|
|
||||||
|
|
||||||
### From Source
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone https://github.com/ZGCA-Forge/Elevator.git
|
|
||||||
cd Elevator
|
|
||||||
pip install -e .[dev]
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|||||||
@@ -343,25 +343,6 @@ Benefits of Proxy Architecture
|
|||||||
5. **Separation of Concerns**: State management handled by proxies, logic in controller
|
5. **Separation of Concerns**: State management handled by proxies, logic in controller
|
||||||
6. **Testability**: Can mock API client for unit tests
|
6. **Testability**: Can mock API client for unit tests
|
||||||
|
|
||||||
Performance Considerations
|
|
||||||
--------------------------
|
|
||||||
|
|
||||||
Each attribute access triggers an API call. For better performance:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
# ❌ Inefficient - multiple API calls
|
|
||||||
if elevator.current_floor < elevator.target_floor:
|
|
||||||
diff = elevator.target_floor - elevator.current_floor
|
|
||||||
|
|
||||||
# ✅ Better - store references
|
|
||||||
current = elevator.current_floor
|
|
||||||
target = elevator.target_floor
|
|
||||||
if current < target:
|
|
||||||
diff = target - current
|
|
||||||
|
|
||||||
However, the API client implements **caching within a single tick**, so multiple accesses during event processing are efficient.
|
|
||||||
|
|
||||||
Next Steps
|
Next Steps
|
||||||
----------
|
----------
|
||||||
|
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ Architecture Overview
|
|||||||
│ api_client │ │ │
|
│ api_client │ │ │
|
||||||
└─────────────────┘ └─────────────────┘
|
└─────────────────┘ └─────────────────┘
|
||||||
│ │
|
│ │
|
||||||
│ GET /api/state │
|
│ GET /api/state │
|
||||||
│ POST /api/step │
|
│ POST /api/step │
|
||||||
│ POST /api/elevators/:id/go_to_floor │
|
│ POST /api/elevators/:id/go_to_floor │
|
||||||
│ │
|
│ │
|
||||||
└───────────────────────────────────────┘
|
└───────────────────────────────────────┘
|
||||||
|
|
||||||
@@ -394,37 +394,37 @@ Typical communication sequence during one tick:
|
|||||||
|
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
Client Server
|
Client Server
|
||||||
│ │
|
│ │
|
||||||
│ 1. GET /api/state │
|
│ 1. GET /api/state │
|
||||||
├────────────────────────────────────►│
|
├─────────────────────────────────────►│
|
||||||
│ ◄── SimulationState (cached) │
|
│ ◄── SimulationState (cached) │
|
||||||
│ │
|
│ │
|
||||||
│ 2. Analyze state, make decisions │
|
│ 2. Analyze state, make decisions │
|
||||||
│ │
|
│ │
|
||||||
│ 3. POST /api/elevators/0/go_to_floor │
|
│ 3. POST /api/elevators/0/go_to_floor│
|
||||||
├────────────────────────────────────►│
|
├─────────────────────────────────────►│
|
||||||
│ ◄── {"success": true} │
|
│ ◄── {"success": true} │
|
||||||
│ │
|
│ │
|
||||||
│ 4. GET /api/state (from cache) │
|
│ 4. GET /api/state (from cache) │
|
||||||
│ No HTTP request! │
|
│ No HTTP request! │
|
||||||
│ │
|
│ │
|
||||||
│ 5. POST /api/step │
|
│ 5. POST /api/step │
|
||||||
├────────────────────────────────────►│
|
├─────────────────────────────────────►│
|
||||||
│ Server processes tick │
|
│ Server processes tick │
|
||||||
│ - Moves elevators │
|
│ - Moves elevators │
|
||||||
│ - Boards/alights passengers │
|
│ - Boards/alights passengers │
|
||||||
│ - Generates events │
|
│ - Generates events │
|
||||||
│ ◄── {tick: 43, events: [...]} │
|
│ ◄── {tick: 43, events: [...]} │
|
||||||
│ │
|
│ │
|
||||||
│ 6. Process events │
|
│ 6. Process events │
|
||||||
│ Cache invalidated │
|
│ Cache invalidated │
|
||||||
│ │
|
│ │
|
||||||
│ 7. GET /api/state (fetches fresh) │
|
│ 7. GET /api/state (fetches fresh) │
|
||||||
├────────────────────────────────────►│
|
├─────────────────────────────────────►│
|
||||||
│ ◄── SimulationState │
|
│ ◄── SimulationState │
|
||||||
│ │
|
│ │
|
||||||
└─────────────────────────────────────┘
|
└──────────────────────────────────────┘
|
||||||
|
|
||||||
Error Handling
|
Error Handling
|
||||||
--------------
|
--------------
|
||||||
@@ -476,23 +476,6 @@ The simulator uses a lock to ensure thread-safe access:
|
|||||||
|
|
||||||
This allows Flask to handle concurrent requests safely.
|
This allows Flask to handle concurrent requests safely.
|
||||||
|
|
||||||
Performance Considerations
|
|
||||||
--------------------------
|
|
||||||
|
|
||||||
**Minimize HTTP Calls**:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
# ❌ Bad - 3 HTTP calls
|
|
||||||
for i in range(3):
|
|
||||||
state = api_client.get_state()
|
|
||||||
print(state.tick)
|
|
||||||
|
|
||||||
# ✅ Good - 1 HTTP call (cached)
|
|
||||||
state = api_client.get_state()
|
|
||||||
for i in range(3):
|
|
||||||
print(state.tick)
|
|
||||||
|
|
||||||
**Batch Commands**:
|
**Batch Commands**:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|||||||
@@ -8,21 +8,21 @@ Simulation Overview
|
|||||||
|
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
┌─────────────────────────────────────────────────────────┐
|
┌──────────────────────────────────────────────────────────┐
|
||||||
│ Simulation Loop │
|
│ Simulation Loop │
|
||||||
│ │
|
│ │
|
||||||
│ Tick N │
|
│ Tick N │
|
||||||
│ 1. Update elevator status (START_UP → CONSTANT_SPEED)│
|
│ 1. Update elevator status (START_UP → CONSTANT_SPEED) │
|
||||||
│ 2. Process arrivals (new passengers) │
|
│ 2. Process arrivals (new passengers) │
|
||||||
│ 3. Move elevators (physics simulation) │
|
│ 3. Move elevators (physics simulation) │
|
||||||
│ 4. Process stops (boarding/alighting) │
|
│ 4. Process stops (boarding/alighting) │
|
||||||
│ 5. Generate events │
|
│ 5. Generate events │
|
||||||
│ │
|
│ │
|
||||||
│ Events sent to client → Client processes → Commands │
|
│ Events sent to client → Client processes → Commands │
|
||||||
│ │
|
│ │
|
||||||
│ Tick N+1 │
|
│ Tick N+1 │
|
||||||
│ (repeat...) │
|
│ (repeat...) │
|
||||||
└─────────────────────────────────────────────────────────┘
|
└──────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
Tick-Based Execution
|
Tick-Based Execution
|
||||||
--------------------
|
--------------------
|
||||||
@@ -463,27 +463,6 @@ Here's what happens in a typical tick:
|
|||||||
Key Timing Concepts
|
Key Timing Concepts
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
Command vs. Execution
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
# Tick 42: Controller sends command
|
|
||||||
elevator.go_to_floor(5, immediate=False)
|
|
||||||
# ← Command queued in elevator.next_target_floor
|
|
||||||
|
|
||||||
# Tick 43: Server processes
|
|
||||||
# ← _update_elevator_status() assigns target
|
|
||||||
# ← Elevator starts moving
|
|
||||||
|
|
||||||
# Tick 44-46: Elevator in motion
|
|
||||||
# ← Events: PASSING_FLOOR
|
|
||||||
|
|
||||||
# Tick 47: Elevator arrives
|
|
||||||
# ← Event: STOPPED_AT_FLOOR
|
|
||||||
|
|
||||||
There's a **one-tick delay** between command and execution (unless ``immediate=True``).
|
|
||||||
|
|
||||||
Immediate vs. Queued
|
Immediate vs. Queued
|
||||||
~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
@@ -531,47 +510,6 @@ Key metrics:
|
|||||||
- **System time**: ``dropoff_tick - arrive_tick`` (total time in system)
|
- **System time**: ``dropoff_tick - arrive_tick`` (total time in system)
|
||||||
- **P95**: 95th percentile (worst-case for most passengers)
|
- **P95**: 95th percentile (worst-case for most passengers)
|
||||||
|
|
||||||
Best Practices
|
|
||||||
--------------
|
|
||||||
|
|
||||||
1. **React to Events**: Don't poll state - implement event handlers
|
|
||||||
2. **Use Queued Commands**: Default ``immediate=False`` is safer
|
|
||||||
3. **Track Passengers**: Monitor ``on_passenger_call`` to know demand
|
|
||||||
4. **Optimize for Wait Time**: Reduce time between arrival and pickup
|
|
||||||
5. **Consider Load**: Check ``elevator.is_full`` before dispatching
|
|
||||||
6. **Handle Idle**: Always give idle elevators something to do (even if it's "go to floor 0")
|
|
||||||
|
|
||||||
Example: Efficient Dispatch
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
def on_passenger_call(self, passenger: ProxyPassenger, floor: ProxyFloor, direction: str) -> None:
|
|
||||||
"""Dispatch nearest suitable elevator"""
|
|
||||||
best_elevator = None
|
|
||||||
best_cost = float('inf')
|
|
||||||
|
|
||||||
for elevator in self.elevators:
|
|
||||||
# Skip if full
|
|
||||||
if elevator.is_full:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Calculate cost (distance + current load)
|
|
||||||
distance = abs(elevator.current_floor - floor.floor)
|
|
||||||
load_penalty = elevator.load_factor * 10
|
|
||||||
cost = distance + load_penalty
|
|
||||||
|
|
||||||
# Check if going in right direction
|
|
||||||
if elevator.target_floor_direction.value == direction:
|
|
||||||
cost *= 0.5 # Prefer elevators already going that way
|
|
||||||
|
|
||||||
if cost < best_cost:
|
|
||||||
best_cost = cost
|
|
||||||
best_elevator = elevator
|
|
||||||
|
|
||||||
if best_elevator:
|
|
||||||
best_elevator.go_to_floor(floor.floor)
|
|
||||||
|
|
||||||
Summary
|
Summary
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
Welcome to Elevator Saga's Documentation!
|
Welcome to Elevator Saga's Documentation!
|
||||||
==========================================
|
==========================================
|
||||||
|
|
||||||
.. image:: https://badge.fury.io/py/elevatorpy.svg
|
.. image:: https://badge.fury.io/py/elevator-py.svg
|
||||||
:target: https://badge.fury.io/py/elevatorpy
|
:target: https://badge.fury.io/py/elevator-py
|
||||||
:alt: PyPI version
|
:alt: PyPI version
|
||||||
|
|
||||||
.. image:: https://img.shields.io/pypi/pyversions/elevatorpy.svg
|
.. image:: https://img.shields.io/pypi/pyversions/elevator-py.svg
|
||||||
:target: https://pypi.org/project/elevatorpy/
|
:target: https://pypi.org/project/elevator-py/
|
||||||
:alt: Python versions
|
:alt: Python versions
|
||||||
|
|
||||||
.. image:: https://github.com/ZGCA-Forge/Elevator/actions/workflows/ci.yml/badge.svg
|
.. image:: https://github.com/ZGCA-Forge/Elevator/actions/workflows/ci.yml/badge.svg
|
||||||
@@ -40,23 +40,7 @@ Basic Installation
|
|||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
pip install elevatorpy
|
pip install elevator-py
|
||||||
|
|
||||||
With Development Dependencies
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
pip install elevatorpy[dev]
|
|
||||||
|
|
||||||
From Source
|
|
||||||
~~~~~~~~~~~
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
git clone https://github.com/ZGCA-Forge/Elevator.git
|
|
||||||
cd Elevator
|
|
||||||
pip install -e .[dev]
|
|
||||||
|
|
||||||
Quick Start
|
Quick Start
|
||||||
-----------
|
-----------
|
||||||
|
|||||||
@@ -6,5 +6,5 @@ A Python implementation of the Elevator Saga game with event-driven architecture
|
|||||||
realistic elevator dispatch algorithm development and testing.
|
realistic elevator dispatch algorithm development and testing.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__version__ = "0.0.2"
|
__version__ = "0.0.4"
|
||||||
__author__ = "ZGCA Team"
|
__author__ = "ZGCA Team"
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ requires = ["setuptools>=61.0", "wheel"]
|
|||||||
build-backend = "setuptools.build_meta"
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "elevatorpy"
|
name = "elevator-py"
|
||||||
dynamic = ["version"]
|
dynamic = ["version"]
|
||||||
description = "Python implementation of Elevator Saga game with event system"
|
description = "Python implementation of Elevator Saga game with event system"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|||||||
Reference in New Issue
Block a user