ChessHog / app.py
nahid112376's picture
update position analysis response
fd506b6
Raw
History Blame Contribute Delete
3.34 kB
import json
import chess
import chess.engine
from http.server import BaseHTTPRequestHandler, HTTPServer
ENGINE_PATH = "/usr/games/stockfish"
engine = chess.engine.SimpleEngine.popen_uci(ENGINE_PATH)
def analyse_position(fen, depth):
board = chess.Board(fen)
info = engine.analyse(board, chess.engine.Limit(depth=depth))
score = info["score"].pov(chess.WHITE).score(mate_score=10000)
best_move = info["pv"][0].uci() if "pv" in info and info["pv"] else None
return score, best_move
def classify(cp_loss):
if cp_loss >= 200:
return "blunder"
elif cp_loss >= 100:
return "mistake"
elif cp_loss >= 50:
return "inaccuracy"
return None
class Handler(BaseHTTPRequestHandler):
def do_POST(self):
length = int(self.headers.get("Content-Length", 0))
body = json.loads(self.rfile.read(length))
fens = body.get("fens", [])[:10]
moves = body.get("moves", []) # SAN or UCI, len = len(fens) - 1
depth = body.get("depth", 12)
if len(fens) < 2:
self._respond({"error": "need at least 2 fens"}, 400)
return
# analyse every position once, reuse for before/after pairs
analysed = [analyse_position(f, depth) for f in fens]
flagged = []
for i in range(len(fens) - 1):
board_before = chess.Board(fens[i])
mover_is_white = board_before.turn == chess.WHITE
eval_before, best_move = analysed[i]
eval_after, _ = analysed[i + 1]
swing = (eval_after - eval_before) if mover_is_white else (eval_before - eval_after)
cp_loss = max(0, -swing)
severity = classify(cp_loss)
# figure out what move was actually played
played_move_uci = None
if i < len(moves):
try:
played_move_uci = board_before.push_san(moves[i]).uci()
except Exception:
played_move_uci = None
missed_best = (
best_move is not None
and played_move_uci is not None
and played_move_uci != best_move
)
# flag if it's a real mistake tier OR a missed-best-move with non-trivial cost
if severity or (missed_best and cp_loss >= 30):
flagged.append({
"index": i,
"fen_before": fens[i],
"move_played": moves[i] if i < len(moves) else None,
"best_move": best_move,
"eval_before": eval_before,
"eval_after": eval_after,
"cp_loss": cp_loss,
"severity": severity or "missed_chance",
"missed_best_move": missed_best
})
self._respond({"flagged_positions": flagged})
def _respond(self, data, status=200):
self.send_response(status)
self.send_header("Content-Type", "application/json")
self.end_headers()
self.wfile.write(json.dumps(data).encode())
def do_GET(self):
self.send_response(200)
self.end_headers()
self.wfile.write(b"Stockfish engine is running")
if __name__ == "__main__":
server = HTTPServer(("0.0.0.0", 7860), Handler)
server.serve_forever()