diff --git a/README.md b/README.md index dfb7591..e086bae 100644 --- a/README.md +++ b/README.md @@ -8,10 +8,10 @@ - Destination: center of a board (W / 2, H / 2) - Initial player position: Random on board border - Available moves: - - left - - right - - up - - down + - left + - right + - up + - down - Optional on-board obstacles ### Rules @@ -24,6 +24,7 @@ ## Game States ```plantuml +scale 1024 width hide empty description state "Start Game" as StartGame @@ -202,33 +203,33 @@ Check REST API interface on [FastAPI docs](http://localhost:8010/docs). Request body: ```json { - "player_name": "Pero" + "player_name": "Pero" } ``` Response body: ```json { - "board": { - "width": 101, - "height": 101 - }, - "destination": { - "position": { - "x": 50, - "y": 50 - } - }, - "player": { - "id": "75bba7cd-a4c1-4b50-b0b5-6382c2822a25", - "name": "Pero", - "position": { - "x": 0, - "y": 10 - }, - "move_count": 0, - "move_attempt_count": 0 - } + "board": { + "width": 101, + "height": 101 + }, + "destination": { + "position": { + "x": 50, + "y": 50 + } + }, + "player": { + "id": "75bba7cd-a4c1-4b50-b0b5-6382c2822a25", + "name": "Pero", + "position": { + "x": 0, + "y": 10 + }, + "move_count": 0, + "move_attempt_count": 0 + } } ``` @@ -251,16 +252,16 @@ Response code: Response body: ```json { - "player": { - "id": "string", - "name": "Pero", - "position": { - "x": 50, - "y": 50 - }, - "move_count": 10, - "move_attempt_count": 12 - } + "player": { + "id": "string", + "name": "Pero", + "position": { + "x": 50, + "y": 50 + }, + "move_count": 10, + "move_attempt_count": 12 + } } ``` @@ -273,16 +274,16 @@ Request body: None Response body: ```json { - "player": { - "id": "string", - "name": "Pero", - "position": { - "x": 50, - "y": 50 - }, - "move_count": 10, - "move_attempt_count": 12 - } + "player": { + "id": "string", + "name": "Pero", + "position": { + "x": 50, + "y": 50 + }, + "move_count": 10, + "move_attempt_count": 12 + } } ``` @@ -293,19 +294,19 @@ 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 - } + "playerId": "75bba7cd-a4c1-4b50-b0b5-6382c2822a25", + "board": { + "width": 101, + "height": 101 + }, + "destinationPosition": { + "x": 50, + "y": 50 + }, + "playerPosition": { + "x": 0, + "y": 10 + } } ``` @@ -314,120 +315,222 @@ Response body: ### WS Data format - json +```json +{ + "message": message_type, + "data": ... +} +``` + ### Game state structure -URI: `/game-state` +Message: `game_dump` Data: ```json { - "board": { - "width": 21, - "height": 21 - }, - "destination": { - "position": { - "x": 10, - "y": 10 - } - }, - "players": [ - { - "id": "test-player-id", - "name": "Pero", - "active": true, - "position": { - "x": 2, - "y": 2 - }, - "move_count": 3, - "move_attempt_count": 3 - }, - { - "id": "95962b49-0003-4bf2-b205-71f2590f2318", - "name": "Mirko", - "active": true, - "position": { - "x": 0, - "y": 0 - }, - "move_count": 15, - "move_attempt_count": 20 - } - ], - "layers": [ - { - "name": "obstacles", - "objects": [ - { - "type": "OBSTACLE", - "position": { - "x": 4, - "y": 2 - } - }, - { - "type": "OBSTACLE", - "position": { - "x": 4, - "y": 13 - } - }, - { - "type": "OBSTACLE", - "position": { - "x": 18, - "y": 18 - } - }, - { - "type": "OBSTACLE", - "position": { - "x": 5, - "y": 4 - } - }, - { - "type": "OBSTACLE", - "position": { - "x": 7, - "y": 10 - } - } - ] - }, - { - "name": "destination", - "objects": [ - { - "type": "DESTINATION", - "position": { - "x": 10, - "y": 10 - } - } - ] - }, - { - "name": "players", - "objects": [ - { - "type": "PLAYER", - "position": { - "x": 2, - "y": 2 - } - }, - { - "type": "PLAYER", - "position": { - "x": 0, - "y": 0 - } - } - ] - } - ] + "board": { + "width": 10, + "height": 10 + }, + "destination": { + "position": { + "x": 5, + "y": 5 + } + }, + "players": [ + { + "id": "test-player-pero", + "name": "Pero", + "active": true, + "position": { + "x": 3, + "y": 3 + }, + "move_count": 0, + "move_attempt_count": 0, + "state": "CREATED" + }, + { + "id": "test-player-mirko", + "name": "Mirko", + "active": true, + "position": { + "x": 4, + "y": 4 + }, + "move_count": 0, + "move_attempt_count": 0, + "state": "CREATED" + } + ], + "layers": [ + { + "name": "obstacles", + "objects": [ + { + "type": "OBSTACLE", + "position": { + "x": 0, + "y": 6 + } + }, + { + "type": "OBSTACLE", + "position": { + "x": 5, + "y": 1 + } + }, + { + "type": "OBSTACLE", + "position": { + "x": 1, + "y": 6 + } + } + ] + }, + { + "name": "destination", + "objects": [ + { + "type": "DESTINATION", + "position": { + "x": 5, + "y": 5 + } + } + ] + }, + { + "name": "players", + "objects": [ + { + "type": "PLAYER", + "position": { + "x": 3, + "y": 3 + } + }, + { + "type": "PLAYER", + "position": { + "x": 4, + "y": 4 + } + } + ] + } + ] } ``` + +### Product purchase start + +Message: `product_purchase_start` + +Data: +```json +{ + "player": { + "id": "test-player-pero", + "name": "Pero", + "active": true, + "position": { + "x": 10, + "y": 10 + }, + "move_count": 1, + "move_attempt_count": 1, + "state": "ON_DESTINATION" + }, + "products": [ + { + "name": "CocaCola", + "id": "cocacola-id", + "description": null + }, + { + "name": "Pepsi", + "id": "pepsi-id", + "description": null + }, + { + "name": "Fanta", + "id": "fanta-id", + "description": null + }, + { + "name": "Snickers", + "id": "snickers-id", + "description": null + }, + { + "name": "Mars", + "id": "mars-id", + "description": null + }, + { + "name": "Burek", + "id": "burek-id", + "description": null + } + ], + "timeout": 5 +} +``` + +### Product purchase timer tick + +Message: `product_purchase_timer_tick` + +Data: +```json +{ + "time_left": 4, + "player": { + "id": "test-player-pero", + "name": "Pero", + "active": true, + "position": { + "x": 10, + "y": 10 + }, + "move_count": 1, + "move_attempt_count": 1, + "state": "ON_DESTINATION" + } +} +``` + +### Product purchase timer done + +Message: `product_purchase_done` + +Data: +```json +{ + "player": { + "id": "test-player-pero", + "name": "Pero", + "active": true, + "position": { + "x": 10, + "y": 10 + }, + "move_count": 1, + "move_attempt_count": 1, + "state": "ON_DESTINATION" + }, + "product": { + "name": "CocaCola", + "id": "cocacola-id", + "description": null + } +} +``` + +If product selection timeout occured, product will be null. diff --git a/fairhopper-sdk b/fairhopper-sdk index 10290db..edca936 160000 --- a/fairhopper-sdk +++ b/fairhopper-sdk @@ -1 +1 @@ -Subproject commit 10290dba54cb926dccc376c3675cceec919a77ce +Subproject commit edca936325fa20803cf05c69d0b5b66cfe195c5d diff --git a/hopper/models/config.py b/hopper/models/config.py index 3a5a6f9..7cb4ad2 100644 --- a/hopper/models/config.py +++ b/hopper/models/config.py @@ -45,5 +45,5 @@ class Settings: ws_server: WSServerSettings purchase_timeout: int = 10 # seconds log_level: int = logging.INFO - products: Optional[List[Product]] = None + products: List[Product] = None debug: Optional[DebugSettings] = None