File size: 8,727 Bytes
bf22ad3 56eb498 0356fb2 7bc796e aa815df bf22ad3 0356fb2 bf22ad3 1a3554c 7bc796e bf22ad3 0356fb2 bf22ad3 1a3554c bf22ad3 0356fb2 bf22ad3 56eb498 bf22ad3 56eb498 bf22ad3 56eb498 bf22ad3 56eb498 bf22ad3 56eb498 bf22ad3 56eb498 bf22ad3 3075b60 0efcaab bf22ad3 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
from flask import Flask, render_template, request, jsonify, session
import chess
import chess.svg
from stockfish import Stockfish, StockfishException
import os
app = Flask(__name__)
app.secret_key = os.urandom(24) # Nécessaire pour les sessions
# Configuration du chemin vers l'exécutable de Stockfish
# Essayez de le trouver automatiquement, sinon spécifiez le chemin
STOCKFISH_PATH = "stockfish" # Ou le chemin complet, ex: "/usr/games/stockfish"
if not os.path.exists(STOCKFISH_PATH):
# Tente quelques chemins communs si non trouvé directement
common_paths = ["/usr/games/stockfish", "/usr/local/bin/stockfish", "/opt/homebrew/bin/stockfish"]
for p in common_paths:
if os.path.exists(p) and os.access(p, os.X_OK):
STOCKFISH_PATH = p
break
else:
print(f"AVERTISSEMENT: Stockfish non trouvé à '{STOCKFISH_PATH}' ou dans les chemins communs. "
"L'IA ne fonctionnera pas. Veuillez installer Stockfish et/ou configurer STOCKFISH_PATH.")
def get_stockfish_engine():
"""Initialise et retourne une instance de Stockfish."""
try:
# Utilise les paramètres par défaut du wrapper, mais on peut les ajuster
# par ex. augmenter la Hash (RAM) et les Threads si besoin.
engine = Stockfish(path=STOCKFISH_PATH, depth=15, parameters={"Threads": 2, "Hash": 128})
# Vérifier si l'engine est bien chargé
if not engine._stockfish.poll() is None: # Si le process s'est terminé
raise StockfishException("Stockfish process terminated unexpectedly on init.")
engine.get_best_move() # Test rapide pour voir si ça fonctionne
engine.set_fen_position(chess.STARTING_FEN) # Reset
return engine
except Exception as e:
print(f"Erreur lors de l'initialisation de Stockfish: {e}")
print(f"Vérifiez que Stockfish est installé et que STOCKFISH_PATH ('{STOCKFISH_PATH}') est correct.")
return None
@app.route('/')
def index():
if 'board_fen' not in session:
session['board_fen'] = chess.Board().fen()
session['game_mode'] = 'pvp' # 'pvp' ou 'ai'
session['player_color'] = 'white' # Si AI, le joueur est blanc par défaut
board = chess.Board(session['board_fen'])
return render_template('index.html',
initial_fen=session['board_fen'],
board_svg=chess.svg.board(board=board, size=400),
game_mode=session['game_mode'],
player_color=session.get('player_color', 'white'),
is_game_over=board.is_game_over(),
outcome=get_outcome_message(board) if board.is_game_over() else "")
def get_outcome_message(board):
if board.is_checkmate():
winner = "Blancs" if board.turn == chess.BLACK else "Noirs"
return f"Échec et mat ! {winner} 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."
return ""
@app.route('/make_move', methods=['POST'])
def make_move():
board = chess.Board(session['board_fen'])
if board.is_game_over():
return jsonify({'error': 'La partie est terminée.', 'fen': board.fen(), 'game_over': True, 'outcome': get_outcome_message(board)})
move_uci = request.json.get('move')
if not move_uci:
return jsonify({'error': 'Mouvement non fourni.', 'fen': board.fen(), 'game_over': board.is_game_over()})
ai_move_made = None
ai_move_uci = None
try:
move = board.parse_uci(move_uci)
except ValueError:
try:
# Essayer de parser en SAN si l'UCI échoue (pour tests manuels par exemple)
move = board.parse_san(move_uci)
except ValueError:
return jsonify({'error': f'Mouvement invalide: {move_uci}', 'fen': board.fen(), 'game_over': board.is_game_over()})
if move in board.legal_moves:
board.push(move)
session['board_fen'] = board.fen()
# Si mode AI et ce n'est pas la fin du jeu pour le joueur
if session.get('game_mode') == 'ai' and not board.is_game_over():
stockfish_engine = get_stockfish_engine()
if stockfish_engine:
stockfish_engine.set_fen_position(board.fen())
# Augmenter le temps de réflexion pour une meilleure IA
# best_move_ai = stockfish_engine.get_best_move_time(1000) # 1 seconde
best_move_ai = stockfish_engine.get_best_move() # Utilise la profondeur configurée
if best_move_ai:
ai_move_obj = board.parse_uci(best_move_ai)
board.push(ai_move_obj)
session['board_fen'] = board.fen()
ai_move_made = True
ai_move_uci = best_move_ai
else: # L'IA ne trouve pas de coup (peut arriver si mat ou pat pour l'IA)
pass
stockfish_engine.send_quit_command() # Important pour libérer les ressources
else:
return jsonify({'error': 'Moteur Stockfish non disponible.', 'fen': board.fen(), 'game_over': board.is_game_over()})
else:
return jsonify({'error': f'Mouvement illégal: {move_uci}', 'fen': board.fen(), 'game_over': board.is_game_over()})
game_over = board.is_game_over()
outcome = get_outcome_message(board) if game_over else ""
return jsonify({
'fen': board.fen(),
'board_svg': chess.svg.board(board=board, size=400, lastmove=move if not ai_move_made else ai_move_obj),
'game_over': game_over,
'outcome': outcome,
'ai_move_uci': ai_move_uci,
'turn': 'white' if board.turn == chess.WHITE else 'black'
})
@app.route('/reset_game', methods=['POST'])
def reset_game():
session['board_fen'] = chess.Board().fen()
# Le mode de jeu et la couleur du joueur sont conservés ou peuvent être réinitialisés ici
# Par exemple, pour forcer la réinitialisation du mode :
# session['game_mode'] = request.json.get('game_mode', 'pvp')
# session['player_color'] = request.json.get('player_color', 'white')
# ... ou simplement les effacer pour qu'ils soient redéfinis
if 'stockfish_engine' in session:
del session['stockfish_engine'] # S'assurer de le recréer
return jsonify({'fen': session['board_fen'],
'board_svg': chess.svg.board(board=chess.Board(session['board_fen']), size=400),
'game_mode': session.get('game_mode'),
'player_color': session.get('player_color')})
@app.route('/set_mode', methods=['POST'])
def set_mode_route():
mode = request.json.get('game_mode')
player_color = request.json.get('player_color', 'white') # Par défaut blanc si non spécifié
if mode in ['pvp', 'ai']:
session['game_mode'] = mode
session['player_color'] = player_color # 'white' or 'black' for AI mode
session['board_fen'] = chess.Board().fen() # Reset board on mode change
board = chess.Board()
initial_ai_move_uci = None
# Si l'IA joue en premier (joueur choisit noir)
if mode == 'ai' and player_color == 'black':
stockfish_engine = get_stockfish_engine()
if stockfish_engine:
stockfish_engine.set_fen_position(board.fen())
best_move_ai = stockfish_engine.get_best_move()
if best_move_ai:
ai_move_obj = board.parse_uci(best_move_ai)
board.push(ai_move_obj)
session['board_fen'] = board.fen()
initial_ai_move_uci = best_move_ai
stockfish_engine.send_quit_command()
else:
return jsonify({'error': 'Moteur Stockfish non disponible.'})
return jsonify({
'message': f'Mode de jeu réglé sur {mode}. Joueur: {player_color if mode == "ai" else "N/A"}.',
'fen': session['board_fen'],
'board_svg': chess.svg.board(board=board, size=400, lastmove=board.move_stack[-1] if initial_ai_move_uci else None),
'game_mode': mode,
'player_color': player_color,
'turn': 'white' if board.turn == chess.WHITE else 'black',
'initial_ai_move_uci': initial_ai_move_uci
})
return jsonify({'error': 'Mode invalide'}), 400
if __name__ == '__main__':
app.run(debug=True) |