from flask import Flask, render_template, request, jsonify, session from flask_session import Session # Pour gérer les sessions côté serveur si besoin de plus de complexité import chess import chess.svg from stockfish import Stockfish import os app = Flask(__name__) # Configuration de la clé secrète pour les sessions Flask app.config["SECRET_KEY"] = os.urandom(24) # Ou une chaîne fixe pour le développement # Configuration pour Flask-Session (stocke les sessions côté serveur, ex: filesystem) # Ceci est optionnel pour cet exemple simple où FEN est petit, mais bon pour des états plus complexes. app.config["SESSION_PERMANENT"] = False app.config["SESSION_TYPE"] = "filesystem" # Peut être redis, memcached, etc. Session(app) # --- IMPORTANT : MODIFIEZ CE CHEMIN --- # Mettez le chemin absolu vers votre exécutable Stockfish # Exemples: # Windows: "C:\\Chemin\\Vers\\Stockfish\\stockfish_15.1_win_x64_avx2.exe" # macOS/Linux: "/usr/local/bin/stockfish" ou "./stockfish-ubuntu-x86-64-avx2" STOCKFISH_PATH = "/usr/local/bin/stockfish" # <--- MODIFIEZ CECI ! try: stockfish = Stockfish(path=STOCKFISH_PATH, depth=15, # Profondeur de recherche par défaut parameters={ "Skill Level": 5, # Niveau de compétence (0-20) "Threads": 2, # Nombre de threads CPU à utiliser "Hash": 128 # Mémoire pour la table de transposition (en Mo) }) print(f"Stockfish initialisé avec succès. Version: {stockfish.get_stockfish_major_version()}") except Exception as e: print(f"ERREUR: Impossible d'initialiser Stockfish. Vérifiez le chemin: {STOCKFISH_PATH}") print(f"Détail de l'erreur: {e}") stockfish = None # Pour que l'app puisse démarrer même si SF échoue (mode IA sera désactivé) @app.route('/') def index(): """Affiche la page principale du jeu.""" # Initialiser un nouveau plateau si aucun n'existe dans la session if 'board_fen' not in session: board = chess.Board() session['board_fen'] = board.fen() session['game_mode'] = 'human' # ou 'ai' session['player_color'] = chess.WHITE # Si l'humain joue les blancs contre l'IA return render_template('index.html', initial_fen=session['board_fen']) @app.route('/new_game', methods=['POST']) def new_game(): """Commence une nouvelle partie.""" data = request.get_json() mode = data.get('mode', 'human') # 'human' ou 'ai' player_plays_white = data.get('player_color_white', True) # True si le joueur joue blanc board = chess.Board() session['board_fen'] = board.fen() session['game_mode'] = mode session['player_color'] = chess.WHITE if player_plays_white else chess.BLACK ai_move_uci = None ai_move_san = None if mode == 'ai' and not player_plays_white: # L'IA joue les blancs (premier coup) if stockfish: stockfish.set_fen_position(board.fen()) best_move_uci = stockfish.get_best_move() if best_move_uci: move = chess.Move.from_uci(best_move_uci) ai_move_san = board.san(move) board.push(move) session['board_fen'] = board.fen() ai_move_uci = best_move_uci else: return jsonify({'error': 'Stockfish non disponible'}), 500 return jsonify({ 'fen': board.fen(), 'board_svg': chess.svg.board(board=board, size=350), 'turn': 'Blanc' if board.turn == chess.WHITE else 'Noir', 'game_over': board.is_game_over(), 'status': get_game_status(board), 'ai_move_uci': ai_move_uci, 'ai_move_san': ai_move_san }) @app.route('/move', methods=['POST']) def make_move(): """Gère un coup du joueur et potentiellement la réponse de l'IA.""" if 'board_fen' not in session: return jsonify({'error': 'Partie non initialisée. Commencez une nouvelle partie.'}), 400 board = chess.Board(session['board_fen']) game_mode = session.get('game_mode', 'human') player_color = session.get('player_color', chess.WHITE) data = request.get_json() move_uci = data.get('move') # ex: "e2e4" if not move_uci: return jsonify({'error': 'Aucun coup fourni'}), 400 player_move_san = None try: move = chess.Move.from_uci(move_uci) if move in board.legal_moves: player_move_san = board.san(move) board.push(move) session['board_fen'] = board.fen() else: return jsonify({'error': 'Coup illégal', 'fen': board.fen(), 'board_svg': chess.svg.board(board=board, size=350)}), 400 except ValueError: return jsonify({'error': 'Format de coup invalide', 'fen': board.fen(), 'board_svg': chess.svg.board(board=board, size=350)}), 400 ai_move_uci = None ai_move_san = None game_over = board.is_game_over() status = get_game_status(board) if not game_over and game_mode == 'ai' and board.turn != player_color: if stockfish: stockfish.set_fen_position(board.fen()) best_move_ai_uci = stockfish.get_best_move_time(1000) # L'IA réfléchit max 1 seconde if best_move_ai_uci: ai_chess_move = chess.Move.from_uci(best_move_ai_uci) ai_move_san = board.san(ai_chess_move) board.push(ai_chess_move) session['board_fen'] = board.fen() ai_move_uci = best_move_ai_uci game_over = board.is_game_over() # Vérifier à nouveau après le coup de l'IA status = get_game_status(board) else: status = "Stockfish non disponible. L'IA ne peut pas jouer." return jsonify({ 'fen': board.fen(), 'board_svg': chess.svg.board(board=board, size=350, lastmove=move if not ai_move_uci else ai_chess_move), 'turn': 'Blanc' if board.turn == chess.WHITE else 'Noir', 'game_over': game_over, 'status': status, 'player_move_san': player_move_san, 'ai_move_uci': ai_move_uci, 'ai_move_san': ai_move_san, 'last_move_uci': move_uci if not ai_move_uci else ai_move_uci }) @app.route('/get_board_state') def get_board_state(): if 'board_fen' not in session: return jsonify({'error': 'Partie non initialisée'}), 404 board = chess.Board(session['board_fen']) return jsonify({ 'fen': board.fen(), 'board_svg': chess.svg.board(board=board, size=350), 'turn': 'Blanc' if board.turn == chess.WHITE else 'Noir', 'game_over': board.is_game_over(), 'status': get_game_status(board) }) def get_game_status(board): if board.is_checkmate(): return f"Échec et mat ! {'Les Noirs' if board.turn == chess.WHITE else 'Les Blancs'} gagnent." if board.is_stalemate(): return "Pat ! Partie nulle." if board.is_insufficient_material(): return "Matériel insuffisant. Partie nulle." if board.is_seventyfive_moves(): return "Règle des 75 coups. Partie nulle." if board.is_fivefold_repetition(): return "Répétition (5 fois). Partie nulle." if board.is_check(): return "Échec !" return "Partie en cours." if __name__ == '__main__': if not os.path.exists("flask_session"): # Crée le dossier pour les sessions si besoin os.makedirs("flask_session") app.run(debug=True)