Project rename and restructure

This commit is contained in:
Eden Kirin
2023-03-25 13:21:07 +01:00
commit 0041b7d43e
21 changed files with 1328 additions and 0 deletions

316
README.md Normal file
View File

@ -0,0 +1,316 @@
# FairHopper
## Game
### Overview
- Rectangle board W × H
- Destination: center of a board (W / 2, H / 2)
- Initial player position: Random on board border
- Available moves:
- left
- right
- up
- down
- Optional on-board obstacles
### Rules
- Goal: Reach the goal destination
- Player can't move out of board
- Player can't move if destination position contains obstacle
- Move timeout: 10s. Game is finished if timeout ocurrs.
## FairHopper Game Server
Requirements:
- Python 3.10+
### Install virtual envirnonment
Project uses [Poetry](https://python-poetry.org), ultimate dependency management software for Python.
Install Poetry:
```sh
pip install poetry
```
Install virtual environment:
```sh
poetry install
```
### Setting up
Copy `settings_template.py` to `settings.py`.
Edit `settings.py` and customize application.
### Starting FairHopper Game Server
```sh
make run
```
By default, JFK runs on port **8010**. To run on other port, start `uvicorn` directly:
```sh
poetry run uvicorn main:app --host 0.0.0.0 --port 8010 --workers=1
```
To activate virtual environment:
```sh
poetry shell
```
## System overview
### Architecture
```plantuml
actor "Player 1" as P1
actor "Player 2" as P2
actor "Player 3" as P3
package Masterpiece {
usecase JFK as "JFK Game Server"
usecase WS as "WS Server"
usecase Vis as "Visualisation\nService"
}
P1 -left-> JFK: REST API
P2 -left-> JFK: REST API
P3 -left-> JFK: REST API
JFK --> WS: WebSockets
WS --> Vis: WebSockets
```
### WebSockets
```plantuml
participant JFK as "JFK Game Server"
participant WS as "WS Server"
participant Client1 as "Visualisation\nClient 1"
participant Client2 as "Visualisation\nClient 2"
JFK ->o WS: Server Connect
activate WS #coral
WS -> JFK: Get game state
activate JFK #yellow
JFK -> WS: Game state
deactivate
deactivate
Client1 ->o WS: Client Connect
activate WS #coral
WS -> Client1: Game state
deactivate
Client2 ->o WS: Client Connect
activate WS #coral
WS -> Client2: Game state
deactivate
loop #lightyellow On game state change
JFK ->o WS: Game state
activate WS #coral
WS o-> Client1: Game state
WS o-> Client2: Game state
deactivate
end
```
## REST API
- Start game
- Move left
- Move right
- Move up
- Move down
- Get current position
- Get board info
Check REST API interface on [FastAPI docs](http://localhost:8010/docs).
### Start game
**Endpoint**: POST `/game`
Request body:
```json
{
"player_name": "Pero"
}
```
Response body:
```json
{
"board": {
"width": 101,
"height": 101
},
"destination": {
"position": {
"x": 50,
"y": 50
},
},
"player": {
"uuid": "75bba7cd-a4c1-4b50-b0b5-6382c2822a25",
"position": {
"x": 0,
"y": 10
},
"move_count": 0,
"move_attempt_count": 0
}
}
```
### Player Move
POST `/player/{uuid}/move/left`
POST `/player/{uuid}/move/right`
POST `/player/{uuid}/move/up`
POST `/player/{uuid}/move/down`
Request body: None
Response code:
- 200 OK: Destination reached
- 201 Created: Player moved successfully
- 403 Forbidden: Player uuid not valid, probably timeout
- 409 Conflict: Invalid move, obstacle or position out of board
- 422 Unprocessable Content: Validation error
Response body:
```json
{
"player": {
"uuid": "string",
"position": {
"x": 50,
"y": 50
},
"move_count": 10,
"move_attempt_count": 12
}
}
```
### Get Player Info
GET `/player/{{uuid}}`
Request body: None
Response body:
```json
{
"player": {
"uuid": "string",
"position": {
"x": 50,
"y": 50
},
"move_count": 10,
"move_attempt_count": 12
}
}
```
### Get Game Info
GET `/game`
Response body:
```json
{
"playerId": "75bba7cd-a4c1-4b50-b0b5-6382c2822a25",
"board": {
"width": 101,
"height": 101
},
"destinationPosition": {
"x": 50,
"y": 50
},
"playerPosition": {
"x": 0,
"y": 10
}
}
```
## WebSockets
### WS Data format
- json
General data format:
```json
{
"command": "command",
"data": {}
}
```
### Game info structure
Command: `gameInfo`
Data:
```json
{
"board": {
"width": 101,
"height": 101
},
"destinationPosition": {
"x": 50,
"y": 50
},
"players": [
{
"id": "75bba7cd-a4c1-4b50-b0b5-6382c2822a25",
"name": "Pero",
"position": {
"x": 0,
"y": 10
}
},
{
"id": "04793b36-0785-4bf3-9396-3585c358cbac",
"name": "Mirko",
"position": {
"x": 11,
"y": 12
}
}
],
"layers": [
{
"name": "obstacles",
"objects": [
{
"type": "obstacle",
"position": {
"x": 15,
"y": 25
}
},
{
"type": "obstacle",
"position": {
"x": 33,
"y": 44
}
}
]
}
]
}
```