File size: 7,497 Bytes
0efcaab
0356fb2
 
 
1a3554c
0356fb2
7bc796e
aa815df
0356fb2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1a3554c
7bc796e
 
0356fb2
 
 
 
 
 
 
 
7bc796e
0356fb2
dfaf016
0356fb2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dfaf016
0356fb2
 
 
 
 
 
 
dfaf016
0efcaab
0356fb2
1a3554c
0356fb2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dfaf016
0356fb2
 
 
 
 
 
 
 
 
dfaf016
0efcaab
0356fb2
 
 
 
 
dfaf016
0356fb2
 
 
 
 
dfaf016
 
0356fb2
 
 
 
 
 
 
 
 
 
 
 
 
 
0efcaab
 
0356fb2
 
0efcaab
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
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)