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)