shortdeck1.3:ui and fix

This commit is contained in:
2025-10-11 18:24:24 +08:00
parent 4763f9a630
commit 8f30e75e1a
69 changed files with 2753 additions and 97 deletions

View File

@@ -1,12 +1,35 @@
import sys
import os
from pathlib import Path
project_root = Path(__file__).resolve().parent.parent
if str(project_root) not in sys.path:
sys.path.insert(0, str(project_root))
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel
from typing import List, Optional, Dict, Any
from .persistence import append_game_history
from .arena_adapter import ArenaGame
from shortdeck_server.persistence import append_game_history
from shortdeck_server.arena_adapter import ArenaGame
app = FastAPI(title="ShortDeck Poker Server", version="1.0.0")
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
app = FastAPI(title="shortdeck-server")
GAME = ArenaGame()
client_path = project_root / "client"
if client_path.exists():
app.mount("/client", StaticFiles(directory=str(client_path)), name="client")
class JoinRequest(BaseModel):
name: str
@@ -19,16 +42,67 @@ class JoinResponse(BaseModel):
class ActionRequest(BaseModel):
player_id: int
action: str # "fold", "call", "raise", "check", "bet"
amount: int | None = None
amount: Optional[int] = None
class ApiResponse(BaseModel):
success: bool = True
message: Optional[str] = None
data: Optional[Dict[str, Any]] = None
error: Optional[str] = None
class GameInfo(BaseModel):
game_id: str
players: List[str]
dealer_index: int
current_turn: int
stage: str
total_pot: int
side_pots: List[Dict[str, Any]]
player_cards: List[str]
board_cards: List[str]
stacks: List[int]
player_states: List[str]
current_pot: List[int]
actions: Dict[str, Any]
class HandStrength(BaseModel):
hand_type: str
description: str
strength: float
cards: List[str]
class Game1v1Response(BaseModel):
success: bool
message: str
human_player_id: Optional[int] = None
ai_player_id: Optional[int] = None
game_id: Optional[str] = None
@app.post("/reset_game")
def reset_game():
global GAME
try:
GAME = ArenaGame()
return {"success": True, "message": "游戏已重置"}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e
@app.post("/join", response_model=JoinResponse)
def join(req: JoinRequest):
try:
print(f"收到加入请求: {req.name}")
player_id = GAME.join_game(req.name)
print(f"玩家 {req.name} 成功加入ID: {player_id}")
return JoinResponse(player_id=player_id, name=req.name)
except ValueError as e:
print(f"加入游戏失败 - ValueError: {e}")
raise HTTPException(status_code=400, detail=str(e)) from e
return JoinResponse(player_id=player_id, name=req.name)
except Exception as e:
print(f"加入游戏失败 - Exception: {e}")
import traceback
traceback.print_exc()
raise HTTPException(status_code=500, detail=str(e)) from e
@app.get("/get_game_state")
@@ -40,11 +114,78 @@ def get_game_state(player_id):
return state
@app.post("/apply_action")
@app.post("/apply_action", response_model=Dict[str, Any])
def apply_action(req: ActionRequest):
try:
GAME.apply_action(req.player_id, req.action, req.amount)
result = GAME.apply_action(req.player_id, req.action, req.amount)
append_game_history(GAME.game_id, {"history": GAME.history})
return result
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e)) from e
return {"ok": True}
@app.get("/valid_actions/{player_id}")
def get_valid_actions(player_id: int):
try:
actions = GAME.get_valid_actions(player_id)
return {"valid_actions": actions}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e
@app.get("/hand_strength/{player_id}")
def get_hand_strength(player_id: int):
try:
strength = GAME.get_hand_strength(player_id)
return strength
except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e
@app.get("/winners")
def get_winners():
try:
winners = GAME.get_winners()
return winners
except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e
@app.post("/reset")
def reset_game(request: dict = None):
try:
global GAME
keep_chips = False
if request and isinstance(request, dict):
keep_chips = request.get("keep_chips", False)
if keep_chips and GAME and len(GAME.agents) >= 2:
GAME.reset_hand_keep_chips()
message = "游戏重置,筹码保持"
else:
GAME = ArenaGame()
message = "游戏完全重置"
return {"ok": True, "message": message}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e
@app.get("/hand_complete")
def check_hand_complete():
try:
is_complete = GAME.check_hand_complete()
return {"hand_complete": is_complete}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e
if __name__ == "__main__":
import uvicorn
print(" Starting ShortDeck Poker Server...")
print(" Server will run on http://localhost:8001")
print(" API docs available at http://localhost:8001/docs")
uvicorn.run(
app,
host="127.0.0.1",
port=8001,
reload=False
)