|
|
|
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' |
|
|
|
|
|
try: |
|
stockfish = Stockfish( |
|
path="/usr/local/bin/stockfish", |
|
parameters={ |
|
"Threads": 2, |
|
"Hash": 256, |
|
"Skill Level": 15, |
|
"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 |
|
self.board = chess.Board() |
|
self.moves_history = [] |
|
self.current_player = 'white' |
|
self.game_status = 'active' |
|
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) |
|
|
|
|
|
self.current_player = 'black' if self.current_player == 'white' else 'white' |
|
|
|
|
|
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) |
|
} |
|
|
|
|
|
games = {} |
|
|
|
@app.route('/') |
|
def index(): |
|
return render_template('index.html') |
|
|
|
@app.route('/game/<mode>') |
|
def game(mode): |
|
if mode not in ['human', 'ai']: |
|
return "Mode de jeu invalide", 400 |
|
|
|
|
|
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': |
|
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 |
|
|
|
|
|
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] |
|
|
|
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) |