123 lines
3.5 KiB
Python
123 lines
3.5 KiB
Python
from fastapi import APIRouter, Depends, HTTPException, Response
|
|
from starlette import status
|
|
|
|
from hopper.api.dependencies import get_game_engine
|
|
from hopper.api.dto import (
|
|
DestinationDto,
|
|
ErrorResponseDto,
|
|
GameInfoDto,
|
|
MovePlayerResponseDto,
|
|
PingResponse,
|
|
PlayerInfoResponseDto,
|
|
StartGameRequestDto,
|
|
StartGameResponseDto,
|
|
)
|
|
from hopper.engine import GameEngine
|
|
from hopper.enums import Direction, PlayerMoveResult
|
|
from hopper.errors import Collision, PositionOutOfBounds
|
|
from hopper.models.player import Player
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
def get_player(uuid: str, engine: GameEngine = Depends(get_game_engine)) -> Player:
|
|
player = engine.players.find(uuid)
|
|
if player is None:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND, detail="Player not found"
|
|
)
|
|
if not player.active:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="Player kicked out due to inactivity",
|
|
)
|
|
return player
|
|
|
|
|
|
@router.get("/ping", response_model=PingResponse)
|
|
async def ping() -> PingResponse:
|
|
return PingResponse(
|
|
message="Pong!",
|
|
)
|
|
|
|
|
|
@router.get("/game", response_model=GameInfoDto)
|
|
async def get_game_info(
|
|
engine: GameEngine = Depends(get_game_engine),
|
|
) -> GameInfoDto:
|
|
return GameInfoDto(
|
|
board=engine.board,
|
|
destination=DestinationDto(
|
|
position=engine.board.destination.position,
|
|
),
|
|
)
|
|
|
|
|
|
@router.post("/game", response_model=StartGameResponseDto)
|
|
async def start_game(
|
|
body: StartGameRequestDto,
|
|
engine: GameEngine = Depends(get_game_engine),
|
|
) -> StartGameResponseDto:
|
|
new_player = await engine.start_game(player_name=body.player_name)
|
|
|
|
return StartGameResponseDto(
|
|
board=engine.board,
|
|
player=new_player,
|
|
destination=DestinationDto(
|
|
position=engine.board.destination.position,
|
|
),
|
|
)
|
|
|
|
|
|
@router.get(
|
|
"/player/{uuid}",
|
|
response_model=PlayerInfoResponseDto,
|
|
status_code=status.HTTP_201_CREATED,
|
|
)
|
|
async def get_player_info(
|
|
player: Player = Depends(get_player),
|
|
) -> MovePlayerResponseDto:
|
|
return PlayerInfoResponseDto(player=player)
|
|
|
|
|
|
@router.post(
|
|
"/player/{uuid}/move/{direction}",
|
|
response_model=MovePlayerResponseDto,
|
|
status_code=status.HTTP_201_CREATED,
|
|
responses={
|
|
status.HTTP_200_OK: {
|
|
"model": MovePlayerResponseDto,
|
|
"description": "Destination reached!",
|
|
},
|
|
status.HTTP_403_FORBIDDEN: {
|
|
"model": ErrorResponseDto,
|
|
"description": " Player uuid not valid, probably due to inactivity",
|
|
},
|
|
status.HTTP_409_CONFLICT: {
|
|
"model": ErrorResponseDto,
|
|
"description": " Position out of bounds or collision with an object",
|
|
},
|
|
},
|
|
)
|
|
async def move_player(
|
|
direction: Direction,
|
|
response: Response,
|
|
engine: GameEngine = Depends(get_game_engine),
|
|
player: Player = Depends(get_player),
|
|
) -> MovePlayerResponseDto:
|
|
try:
|
|
move_result = await engine.move_player(player, direction)
|
|
except PositionOutOfBounds:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_409_CONFLICT, detail="Position out of bounds"
|
|
)
|
|
except Collision:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_409_CONFLICT, detail="Collision with an object"
|
|
)
|
|
|
|
if move_result == PlayerMoveResult.DESTINATION_REACHED:
|
|
response.status_code = status.HTTP_200_OK
|
|
|
|
return MovePlayerResponseDto(player=player)
|