# app.py from flask import Flask, render_template, request, jsonify, session from stockfish import Stockfish import uuid import chess import chess.pgn from datetime import datetime app = Flask(__name__) app.secret_key = 'your-secret-key-change-this' # Configuration Stockfish try: stockfish = Stockfish( path="/usr/local/bin/stockfish", # Ajustez selon votre installation parameters={ "Threads": 2, "Hash": 256, "Skill Level": 15, # Niveau IA (0-20) "Minimum Thinking Time": 100 } ) except: stockfish = None print("Stockfish non trouvé. Mode IA désactivé.") class ChessGame: def __init__(self, game_id, mode='human'): self.game_id = game_id self.mode = mode # 'human' ou 'ai' self.board = chess.Board() self.moves_history = [] self.current_player = 'white' self.game_status = 'active' # 'active', 'checkmate', 'stalemate', 'draw' self.created_at = datetime.now() def make_move(self, move_uci): """Effectue un coup et retourne le résultat""" try: move = chess.Move.from_uci(move_uci) if move in self.board.legal_moves: self.board.push(move) self.moves_history.append(move_uci) # Changer de joueur self.current_player = 'black' if self.current_player == 'white' else 'white' # Vérifier l'état du jeu self._update_game_status() return { 'success': True, 'move': move_uci, 'board_fen': self.board.fen(), 'current_player': self.current_player, 'game_status': self.game_status, 'legal_moves': [move.uci() for move in self.board.legal_moves], 'is_check': self.board.is_check() } else: return {'success': False, 'error': 'Coup illégal'} except Exception as e: return {'success': False, 'error': str(e)} def get_ai_move(self): """Obtient le coup de l'IA via Stockfish""" if not stockfish or self.mode != 'ai': return None try: stockfish.set_fen_position(self.board.fen()) ai_move = stockfish.get_best_move() return ai_move except: return None def _update_game_status(self): """Met à jour l'état du jeu""" if self.board.is_checkmate(): winner = 'black' if self.current_player == 'white' else 'white' self.game_status = f'checkmate_{winner}' elif self.board.is_stalemate(): self.game_status = 'stalemate' elif self.board.is_insufficient_material(): self.game_status = 'draw_material' elif self.board.is_seventyfive_moves(): self.game_status = 'draw_75moves' elif self.board.is_fivefold_repetition(): self.game_status = 'draw_repetition' def get_board_state(self): """Retourne l'état complet du plateau""" return { 'fen': self.board.fen(), 'current_player': self.current_player, 'game_status': self.game_status, 'legal_moves': [move.uci() for move in self.board.legal_moves], 'is_check': self.board.is_check(), 'moves_history': self.moves_history, 'move_count': len(self.moves_history) } # Stockage des parties en mémoire (remplacez par une base de données en production) games = {} @app.route('/') def index(): return render_template('index.html') @app.route('/game/') def game(mode): if mode not in ['human', 'ai']: return "Mode de jeu invalide", 400 # Créer une nouvelle partie game_id = str(uuid.uuid4()) games[game_id] = ChessGame(game_id, mode) session['game_id'] = game_id return render_template('game.html', mode=mode, game_id=game_id) @app.route('/api/game/state') def get_game_state(): game_id = session.get('game_id') if not game_id or game_id not in games: return jsonify({'error': 'Partie non trouvée'}), 404 game = games[game_id] return jsonify(game.get_board_state()) @app.route('/api/game/move', methods=['POST']) def make_move(): game_id = session.get('game_id') if not game_id or game_id not in games: return jsonify({'error': 'Partie non trouvée'}), 404 data = request.json move = data.get('move') if not move: return jsonify({'error': 'Coup manquant'}), 400 game = games[game_id] result = game.make_move(move) return jsonify(result) @app.route('/api/game/ai-move', methods=['POST']) def get_ai_move(): game_id = session.get('game_id') if not game_id or game_id not in games: return jsonify({'error': 'Partie non trouvée'}), 404 game = games[game_id] if game.mode != 'ai': return jsonify({'error': 'Mode IA non activé'}), 400 if game.current_player != 'black': # IA joue les noirs return jsonify({'error': 'Ce n\'est pas le tour de l\'IA'}), 400 ai_move = game.get_ai_move() if not ai_move: return jsonify({'error': 'IA ne peut pas jouer'}), 500 # Effectuer le coup de l'IA result = game.make_move(ai_move) result['ai_move'] = True return jsonify(result) @app.route('/api/game/reset', methods=['POST']) def reset_game(): game_id = session.get('game_id') if not game_id or game_id not in games: return jsonify({'error': 'Partie non trouvée'}), 404 game = games[game_id] # Réinitialiser la partie games[game_id] = ChessGame(game_id, game.mode) return jsonify({'success': True, 'message': 'Partie réinitialisée'}) @app.route('/api/game/legal-moves') def get_legal_moves(): game_id = session.get('game_id') if not game_id or game_id not in games: return jsonify({'error': 'Partie non trouvée'}), 404 data = request.args square = data.get('square') if not square: return jsonify({'error': 'Case manquante'}), 400 game = games[game_id] legal_moves = [] for move in game.board.legal_moves: if move.from_square == chess.parse_square(square): legal_moves.append(chess.square_name(move.to_square)) return jsonify({'legal_moves': legal_moves}) if __name__ == '__main__': app.run(debug=True)