The code of this website is:
import html
from pathlib import Path
from typing import Annotated
from dopynion.data_model import (
CardName,
CardNameAndHand,
Game,
Hand,
MoneyCardsInHand,
PossibleCards,
)
from fastapi import Depends, FastAPI, Header, Request
from fastapi.responses import HTMLResponse, JSONResponse
from pydantic import BaseModel
app = FastAPI()
#####################################################
# Data model for responses
#####################################################
class DopynionResponseBool(BaseModel):
game_id: str
decision: bool
class DopynionResponseCardName(BaseModel):
game_id: str
decision: CardName
class DopynionResponseStr(BaseModel):
game_id: str
decision: str
#####################################################
# Getter for the game identifier
#####################################################
def get_game_id(x_game_id: str = Header(description="ID of the game")) -> str:
return x_game_id
GameIdDependency = Annotated[str, Depends(get_game_id)]
#####################################################
# Error management
#####################################################
@app.exception_handler(Exception)
def unknown_exception_handler(_request: Request, exc: Exception) -> JSONResponse:
print(exc.__class__.__name__, str(exc))
return JSONResponse(
status_code=500,
content={
"message": "Oops!",
"detail": str(exc),
"name": exc.__class__.__name__,
},
)
#####################################################
# Template extra bonus
#####################################################
# The root of the website shows the code of the website
@app.get("/", response_class=HTMLResponse)
def root() -> str:
header = (
"<html><head><title>Dopynion template</title></head><body>"
"<h1>Dopynion documentation</h1>"
"<h2>API documentation</h2>"
'<p><a href="/docs">Read the documentation.</a></p>'
"<h2>Code template</h2>"
"<p>The code of this website is:</p>"
"<pre>"
)
footer = "</pre></body></html>"
return header + html.escape(Path(__file__).read_text(encoding="utf-8")) + footer
#####################################################
# The code of the strategy
#####################################################
@app.get("/name")
def name() -> str:
return "Default player name"
@app.get("/start_game")
def start_game(game_id: GameIdDependency) -> DopynionResponseStr:
return DopynionResponseStr(game_id=game_id, decision="OK")
@app.get("/start_turn")
def start_turn(game_id: GameIdDependency) -> DopynionResponseStr:
return DopynionResponseStr(game_id=game_id, decision="OK")
@app.post("/play")
def play(_game: Game, game_id: GameIdDependency) -> DopynionResponseStr:
return DopynionResponseStr(game_id=game_id, decision="END_TURN")
@app.get("/end_game")
def end_game(game_id: GameIdDependency) -> DopynionResponseStr:
return DopynionResponseStr(game_id=game_id, decision="OK")
@app.post("/confirm_discard_card_from_hand")
async def confirm_discard_card_from_hand(
game_id: GameIdDependency,
_decision_input: CardNameAndHand,
) -> DopynionResponseBool:
return DopynionResponseBool(game_id=game_id, decision=True)
@app.post("/discard_card_from_hand")
async def discard_card_from_hand(
game_id: GameIdDependency,
decision_input: Hand,
) -> DopynionResponseCardName:
return DopynionResponseCardName(game_id=game_id, decision=decision_input.hand[0])
@app.post("/confirm_trash_card_from_hand")
async def confirm_trash_card_from_hand(
game_id: GameIdDependency,
_decision_input: CardNameAndHand,
) -> DopynionResponseBool:
return DopynionResponseBool(game_id=game_id, decision=True)
@app.post("/trash_card_from_hand")
async def trash_card_from_hand(
game_id: GameIdDependency,
decision_input: Hand,
) -> DopynionResponseCardName:
return DopynionResponseCardName(game_id=game_id, decision=decision_input.hand[0])
@app.post("/confirm_discard_deck")
async def confirm_discard_deck(
game_id: GameIdDependency,
) -> DopynionResponseBool:
return DopynionResponseBool(game_id=game_id, decision=True)
@app.post("/choose_card_to_receive_in_discard")
async def choose_card_to_receive_in_discard(
game_id: GameIdDependency,
decision_input: PossibleCards,
) -> DopynionResponseCardName:
return DopynionResponseCardName(
game_id=game_id,
decision=decision_input.possible_cards[0],
)
@app.post("/choose_card_to_receive_in_deck")
async def choose_card_to_receive_in_deck(
game_id: GameIdDependency,
decision_input: PossibleCards,
) -> DopynionResponseCardName:
return DopynionResponseCardName(
game_id=game_id,
decision=decision_input.possible_cards[0],
)
@app.post("/skip_card_reception_in_hand")
async def skip_card_reception_in_hand(
game_id: GameIdDependency,
_decision_input: CardNameAndHand,
) -> DopynionResponseBool:
return DopynionResponseBool(game_id=game_id, decision=True)
@app.post("/trash_money_card_for_better_money_card")
async def trash_money_card_for_better_money_card(
game_id: GameIdDependency,
decision_input: MoneyCardsInHand,
) -> DopynionResponseCardName:
return DopynionResponseCardName(
game_id=game_id,
decision=decision_input.money_in_hand[0],
)