Merge branch 'rename-uuid-to-id'
This commit is contained in:
24
README.md
24
README.md
@ -92,7 +92,7 @@ To activate virtual environment:
|
|||||||
poetry shell
|
poetry shell
|
||||||
```
|
```
|
||||||
|
|
||||||
WebSockets server runs on port **8011**. To run WS Server on different port, edit `settings.py` configuration.
|
WebSockets server runs on port **8011**. To run WS Server on different port, edit `settings.py` configuration.
|
||||||
|
|
||||||
|
|
||||||
## System overview
|
## System overview
|
||||||
@ -220,7 +220,7 @@ Response body:
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"player": {
|
"player": {
|
||||||
"uuid": "75bba7cd-a4c1-4b50-b0b5-6382c2822a25",
|
"id": "75bba7cd-a4c1-4b50-b0b5-6382c2822a25",
|
||||||
"name": "Pero",
|
"name": "Pero",
|
||||||
"position": {
|
"position": {
|
||||||
"x": 0,
|
"x": 0,
|
||||||
@ -234,17 +234,17 @@ Response body:
|
|||||||
|
|
||||||
### Player Move
|
### Player Move
|
||||||
|
|
||||||
- POST `/player/{uuid}/move/left`
|
- POST `/player/{id}/move/left`
|
||||||
- POST `/player/{uuid}/move/right`
|
- POST `/player/{id}/move/right`
|
||||||
- POST `/player/{uuid}/move/up`
|
- POST `/player/{id}/move/up`
|
||||||
- POST `/player/{uuid}/move/down`
|
- POST `/player/{id}/move/down`
|
||||||
|
|
||||||
Request body: None
|
Request body: None
|
||||||
|
|
||||||
Response code:
|
Response code:
|
||||||
- 200 OK: Destination reached
|
- 200 OK: Destination reached
|
||||||
- 201 Created: Player moved successfully
|
- 201 Created: Player moved successfully
|
||||||
- 403 Forbidden: Player uuid not valid, probably timeout
|
- 403 Forbidden: Player id not valid, probably timeout
|
||||||
- 409 Conflict: Invalid move, obstacle or position out of board
|
- 409 Conflict: Invalid move, obstacle or position out of board
|
||||||
- 422 Unprocessable Content: Validation error
|
- 422 Unprocessable Content: Validation error
|
||||||
|
|
||||||
@ -252,7 +252,7 @@ Response body:
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"player": {
|
"player": {
|
||||||
"uuid": "string",
|
"id": "string",
|
||||||
"name": "Pero",
|
"name": "Pero",
|
||||||
"position": {
|
"position": {
|
||||||
"x": 50,
|
"x": 50,
|
||||||
@ -266,7 +266,7 @@ Response body:
|
|||||||
|
|
||||||
### Get Player Info
|
### Get Player Info
|
||||||
|
|
||||||
GET `/player/{{uuid}}`
|
GET `/player/{{id}}`
|
||||||
|
|
||||||
Request body: None
|
Request body: None
|
||||||
|
|
||||||
@ -274,7 +274,7 @@ Response body:
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"player": {
|
"player": {
|
||||||
"uuid": "string",
|
"id": "string",
|
||||||
"name": "Pero",
|
"name": "Pero",
|
||||||
"position": {
|
"position": {
|
||||||
"x": 50,
|
"x": 50,
|
||||||
@ -334,7 +334,7 @@ Data:
|
|||||||
},
|
},
|
||||||
"players": [
|
"players": [
|
||||||
{
|
{
|
||||||
"uuid": "test-player-id",
|
"id": "test-player-id",
|
||||||
"name": "Pero",
|
"name": "Pero",
|
||||||
"active": true,
|
"active": true,
|
||||||
"position": {
|
"position": {
|
||||||
@ -345,7 +345,7 @@ Data:
|
|||||||
"move_attempt_count": 3
|
"move_attempt_count": 3
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"uuid": "95962b49-0003-4bf2-b205-71f2590f2318",
|
"id": "95962b49-0003-4bf2-b205-71f2590f2318",
|
||||||
"name": "Mirko",
|
"name": "Mirko",
|
||||||
"active": true,
|
"active": true,
|
||||||
"position": {
|
"position": {
|
||||||
|
|||||||
@ -39,7 +39,7 @@ POST http://localhost:8010/player/test-player-pero/product/purchase
|
|||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
|
|
||||||
{
|
{
|
||||||
"product_uuid": "cocacola-id"
|
"product_id": "cocacola-id"
|
||||||
}
|
}
|
||||||
###
|
###
|
||||||
|
|
||||||
|
|||||||
@ -27,7 +27,7 @@ class PositionDto(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class PlayerDto(BaseModel):
|
class PlayerDto(BaseModel):
|
||||||
uuid: str
|
id: str
|
||||||
name: str
|
name: str
|
||||||
active: bool
|
active: bool
|
||||||
position: PositionDto
|
position: PositionDto
|
||||||
@ -42,7 +42,7 @@ class DestinationDto(BaseModel):
|
|||||||
|
|
||||||
class ProductDto(BaseModel):
|
class ProductDto(BaseModel):
|
||||||
name: str
|
name: str
|
||||||
uuid: str
|
id: str
|
||||||
description: Optional[str] = None
|
description: Optional[str] = None
|
||||||
|
|
||||||
class StartGameRequestDto(BaseModel):
|
class StartGameRequestDto(BaseModel):
|
||||||
@ -75,4 +75,4 @@ class GetProductsResponse(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class PurchaseProductDto(BaseModel):
|
class PurchaseProductDto(BaseModel):
|
||||||
product_uuid: str
|
product_id: str
|
||||||
|
|||||||
@ -24,8 +24,8 @@ from settings import settings
|
|||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
def get_player(uuid: str, engine: GameEngine = Depends(get_game_engine)) -> Player:
|
def get_player(id: str, engine: GameEngine = Depends(get_game_engine)) -> Player:
|
||||||
player = engine.players.find(uuid)
|
player = engine.players.find(id)
|
||||||
if player is None:
|
if player is None:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_404_NOT_FOUND, detail="Player not found"
|
status_code=status.HTTP_404_NOT_FOUND, detail="Player not found"
|
||||||
@ -76,7 +76,7 @@ async def start_game(
|
|||||||
|
|
||||||
|
|
||||||
@router.get(
|
@router.get(
|
||||||
"/player/{uuid}",
|
"/player/{id}",
|
||||||
response_model=PlayerInfoResponseDto,
|
response_model=PlayerInfoResponseDto,
|
||||||
responses={
|
responses={
|
||||||
status.HTTP_403_FORBIDDEN: {
|
status.HTTP_403_FORBIDDEN: {
|
||||||
@ -85,7 +85,7 @@ async def start_game(
|
|||||||
},
|
},
|
||||||
status.HTTP_404_NOT_FOUND: {
|
status.HTTP_404_NOT_FOUND: {
|
||||||
"model": ErrorResponseDto,
|
"model": ErrorResponseDto,
|
||||||
"description": " Player with uuid not found, probably kicked out",
|
"description": " Player with id not found, probably kicked out",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@ -96,7 +96,7 @@ async def get_player_info(
|
|||||||
|
|
||||||
|
|
||||||
@router.post(
|
@router.post(
|
||||||
"/player/{uuid}/move/{direction}",
|
"/player/{id}/move/{direction}",
|
||||||
response_model=MovePlayerResponseDto,
|
response_model=MovePlayerResponseDto,
|
||||||
status_code=status.HTTP_201_CREATED,
|
status_code=status.HTTP_201_CREATED,
|
||||||
responses={
|
responses={
|
||||||
@ -110,7 +110,7 @@ async def get_player_info(
|
|||||||
},
|
},
|
||||||
status.HTTP_404_NOT_FOUND: {
|
status.HTTP_404_NOT_FOUND: {
|
||||||
"model": ErrorResponseDto,
|
"model": ErrorResponseDto,
|
||||||
"description": " Player with uuid not found, probably kicked out",
|
"description": " Player with id not found, probably kicked out",
|
||||||
},
|
},
|
||||||
status.HTTP_409_CONFLICT: {
|
status.HTTP_409_CONFLICT: {
|
||||||
"model": ErrorResponseDto,
|
"model": ErrorResponseDto,
|
||||||
@ -157,24 +157,24 @@ async def get_products() -> GetProductsResponse:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@router.get("/products/{uuid}", response_model=ProductDto)
|
@router.get("/products/{id}", response_model=ProductDto)
|
||||||
async def get_product(uuid: str) -> ProductDto:
|
async def get_product(id: str) -> ProductDto:
|
||||||
for product in settings.products:
|
for product in settings.products:
|
||||||
if product.uuid == uuid:
|
if product.id == id:
|
||||||
return ProductDto.from_orm(product)
|
return ProductDto.from_orm(product)
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_404_NOT_FOUND, detail="Product not found"
|
status_code=status.HTTP_404_NOT_FOUND, detail="Product not found"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@router.post("/player/{uuid}/product/purchase")
|
@router.post("/player/{id}/product/purchase")
|
||||||
async def purchase_product(
|
async def purchase_product(
|
||||||
body: PurchaseProductDto,
|
body: PurchaseProductDto,
|
||||||
engine: GameEngine = Depends(get_game_engine),
|
engine: GameEngine = Depends(get_game_engine),
|
||||||
player: Player = Depends(get_player),
|
player: Player = Depends(get_player),
|
||||||
):
|
):
|
||||||
for product in settings.products:
|
for product in settings.products:
|
||||||
if product.uuid == body.product_uuid:
|
if product.id == body.product_id:
|
||||||
try:
|
try:
|
||||||
await engine.purchase_product(player=player, product=product)
|
await engine.purchase_product(player=player, product=product)
|
||||||
except PurchaseForbiddenForPlayer:
|
except PurchaseForbiddenForPlayer:
|
||||||
|
|||||||
@ -15,7 +15,7 @@ class Position:
|
|||||||
@dataclass
|
@dataclass
|
||||||
class Player:
|
class Player:
|
||||||
name: str
|
name: str
|
||||||
uuid: str = field(default_factory=lambda: str(uuid.uuid4()))
|
id: str = field(default_factory=lambda: str(uuid.uuid4()))
|
||||||
position: Position = field(default_factory=lambda: Position(0, 0))
|
position: Position = field(default_factory=lambda: Position(0, 0))
|
||||||
move_count: int = 0
|
move_count: int = 0
|
||||||
move_attempt_count: int = 0
|
move_attempt_count: int = 0
|
||||||
@ -31,8 +31,8 @@ class Player:
|
|||||||
|
|
||||||
|
|
||||||
class PlayerList(list[Player]):
|
class PlayerList(list[Player]):
|
||||||
def find(self, uuid: str) -> Optional[Player]:
|
def find(self, id: str) -> Optional[Player]:
|
||||||
for player in self:
|
for player in self:
|
||||||
if player.uuid == uuid:
|
if player.id == id:
|
||||||
return player
|
return player
|
||||||
return None
|
return None
|
||||||
|
|||||||
@ -6,5 +6,5 @@ from typing import Optional
|
|||||||
@dataclass
|
@dataclass
|
||||||
class Product:
|
class Product:
|
||||||
name: str
|
name: str
|
||||||
uuid: str = field(default_factory=lambda: str(uuid.uuid4()))
|
id: str = field(default_factory=lambda: str(uuid.uuid4()))
|
||||||
description: Optional[str] = None
|
description: Optional[str] = None
|
||||||
|
|||||||
51
sdk/demo.py
Normal file
51
sdk/demo.py
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import random
|
||||||
|
from fh_sdk import Direction, FairHopper, Position
|
||||||
|
import math
|
||||||
|
|
||||||
|
HOST = "http://localhost"
|
||||||
|
PORT = 8010
|
||||||
|
|
||||||
|
|
||||||
|
def calc_angle(position1: Position, position2: Position) -> float:
|
||||||
|
x1, y1 = position1.x, position1.y
|
||||||
|
x2, y2 = position2.x, position2.y
|
||||||
|
return math.atan2(y2 - y1, x2 - x1) * (180 / math.pi)
|
||||||
|
|
||||||
|
|
||||||
|
fh = FairHopper(host=HOST, port=PORT)
|
||||||
|
res = fh.ping()
|
||||||
|
|
||||||
|
game = fh.start_game(player_name=f"Mirko {random.randint(0, 9999)}")
|
||||||
|
print(game.player.position)
|
||||||
|
quit()
|
||||||
|
|
||||||
|
res = fh.get_game_info()
|
||||||
|
print(">>>>>", res)
|
||||||
|
|
||||||
|
res = fh.get_player_info("XX")
|
||||||
|
print(">>>>>", res)
|
||||||
|
|
||||||
|
position = game.player.position
|
||||||
|
dest_position = game.destination.position
|
||||||
|
|
||||||
|
# p1 = PositionDto(x=0, y=20)
|
||||||
|
# p2 = PositionDto(x=10, y=10)
|
||||||
|
# angle = calc_angle(p1, p2)
|
||||||
|
# print(angle)
|
||||||
|
# quit()
|
||||||
|
|
||||||
|
for _ in range(10):
|
||||||
|
angle = calc_angle(position, dest_position) + 180
|
||||||
|
if 0 <= angle < 90:
|
||||||
|
direction = Direction.RIGHT
|
||||||
|
elif 90 <= angle <= 180:
|
||||||
|
direction = Direction.DOWN
|
||||||
|
elif 180 <= angle <= 270:
|
||||||
|
direction = Direction.RIGHT
|
||||||
|
else:
|
||||||
|
direction = Direction.UP
|
||||||
|
|
||||||
|
print(position, dest_position, int(angle), direction)
|
||||||
|
|
||||||
|
move_response = fh.move(game.player.id, direction)
|
||||||
|
position = move_response.player.position
|
||||||
@ -2,18 +2,49 @@ import logging
|
|||||||
|
|
||||||
from hopper.models.config import (
|
from hopper.models.config import (
|
||||||
BoardSettings,
|
BoardSettings,
|
||||||
|
DebugSettings,
|
||||||
GameSettings,
|
GameSettings,
|
||||||
InactivityWatchdogSettings,
|
InactivityWatchdogSettings,
|
||||||
Settings,
|
Settings,
|
||||||
WSServerSettings,
|
WSServerSettings,
|
||||||
)
|
)
|
||||||
|
from hopper.models.player import Player, Position
|
||||||
|
from hopper.models.product import Product
|
||||||
|
|
||||||
settings = Settings(
|
settings = Settings(
|
||||||
game=GameSettings(),
|
game=GameSettings(),
|
||||||
board=BoardSettings(),
|
board=BoardSettings(
|
||||||
|
WIDTH=20,
|
||||||
|
HEIGHT=20,
|
||||||
|
OBSTACLE_COUNT=10,
|
||||||
|
),
|
||||||
inacivity_watchdog=InactivityWatchdogSettings(),
|
inacivity_watchdog=InactivityWatchdogSettings(),
|
||||||
|
purchase_timeout=5,
|
||||||
log_level=logging.INFO,
|
log_level=logging.INFO,
|
||||||
|
products=[
|
||||||
|
Product(name="CocaCola", id="cocacola-id"),
|
||||||
|
Product(name="Pepsi", id="pepsi-id"),
|
||||||
|
Product(name="Fanta", id="fanta-id"),
|
||||||
|
Product(name="Snickers", id="snickers-id"),
|
||||||
|
Product(name="Mars", id="mars-id"),
|
||||||
|
Product(name="Burek", id="burek-id"),
|
||||||
|
],
|
||||||
ws_server=WSServerSettings(),
|
ws_server=WSServerSettings(),
|
||||||
purchase_timeout=10,
|
debug=DebugSettings(
|
||||||
debug=None,
|
PRINT_BOARD=True,
|
||||||
|
PLAYERS=[
|
||||||
|
Player(
|
||||||
|
name="Pero",
|
||||||
|
id="test-player-pero",
|
||||||
|
position=Position(x=9, y=10),
|
||||||
|
can_be_deactivated=False,
|
||||||
|
),
|
||||||
|
Player(
|
||||||
|
name="Mirko",
|
||||||
|
id="test-player-mirko",
|
||||||
|
position=Position(x=10, y=5),
|
||||||
|
can_be_deactivated=False,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user