Docfile commited on
Commit
0356fb2
·
verified ·
1 Parent(s): 34d1909

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +159 -176
app.py CHANGED
@@ -1,198 +1,181 @@
1
  from flask import Flask, render_template, request, jsonify, session
 
 
 
2
  from stockfish import Stockfish
3
- import uuid
4
- import json
5
 
6
  app = Flask(__name__)
7
- app.secret_key = 'your-secret-key-change-this'
8
-
9
- # Configuration Stockfish
10
- STOCKFISH_PATH = "/usr/games/stockfish" # Ajustez selon votre installation
11
-
12
- # Stockage des parties en cours (en production, utilisez une base de données)
13
- games = {}
14
-
15
- class ChessGame:
16
- def __init__(self, game_id, mode="human"):
17
- self.game_id = game_id
18
- self.mode = mode # "human" ou "ai"
19
- self.current_player = "white"
20
- self.moves_history = []
21
- self.game_over = False
22
- self.winner = None
23
-
24
- # Initialiser Stockfish pour le mode AI
25
- if mode == "ai":
26
- try:
27
- self.stockfish = Stockfish(path=STOCKFISH_PATH)
28
- self.stockfish.set_depth(10)
29
- except:
30
- # Fallback si Stockfish n'est pas trouvé
31
- self.stockfish = None
32
- print("Attention: Stockfish non trouvé, mode AI désactivé")
33
- else:
34
- self.stockfish = None
35
-
36
- # Position de départ FEN
37
- self.fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
38
-
39
- if self.stockfish:
40
- self.stockfish.set_fen_position(self.fen)
41
-
42
- def make_move(self, move):
43
- """Effectuer un coup"""
44
- if self.game_over:
45
- return False, "La partie est terminée"
46
-
47
- if self.stockfish:
48
- # Vérifier si le coup est légal
49
- legal_moves = self.stockfish.get_legal_moves()
50
- if move not in legal_moves:
51
- return False, "Coup illégal"
52
-
53
- # Effectuer le coup
54
- self.stockfish.make_moves_from_current_position([move])
55
- self.fen = self.stockfish.get_fen_position()
56
-
57
- # Vérifier fin de partie
58
- if self.stockfish.is_game_over():
59
- self.game_over = True
60
- if self.stockfish.is_checkmate():
61
- self.winner = self.current_player
62
- else:
63
- self.winner = "draw"
64
- else:
65
- # Mode basique sans validation (pour le mode humain sans Stockfish)
66
- pass
67
-
68
- self.moves_history.append(move)
69
- self.current_player = "black" if self.current_player == "white" else "white"
70
-
71
- return True, "Coup effectué"
72
-
73
- def get_ai_move(self):
74
- """Obtenir le coup de l'IA"""
75
- if not self.stockfish or self.current_player != "black":
76
- return None
77
-
78
- best_move = self.stockfish.get_best_move()
79
- return best_move
80
-
81
- def get_legal_moves(self):
82
- """Obtenir les coups légaux"""
83
- if self.stockfish:
84
- return self.stockfish.get_legal_moves()
85
- return []
86
-
87
- def get_game_state(self):
88
- """Obtenir l'état complet du jeu"""
89
- return {
90
- "game_id": self.game_id,
91
- "mode": self.mode,
92
- "current_player": self.current_player,
93
- "fen": self.fen,
94
- "moves_history": self.moves_history,
95
- "game_over": self.game_over,
96
- "winner": self.winner,
97
- "legal_moves": self.get_legal_moves()
98
- }
99
 
100
  @app.route('/')
101
  def index():
102
- return render_template('index.html')
 
 
 
 
 
 
 
103
 
104
- @app.route('/api/new_game', methods=['POST'])
105
  def new_game():
106
- """Créer une nouvelle partie"""
107
- data = request.json
108
- mode = data.get('mode', 'human') # 'human' ou 'ai'
109
-
110
- game_id = str(uuid.uuid4())
111
- game = ChessGame(game_id, mode)
112
- games[game_id] = game
113
-
114
- # Stocker l'ID de partie dans la session
115
- session['game_id'] = game_id
116
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  return jsonify({
118
- "success": True,
119
- "game_state": game.get_game_state()
 
 
 
 
 
120
  })
121
 
122
- @app.route('/api/make_move', methods=['POST'])
123
  def make_move():
124
- """Effectuer un coup"""
125
- data = request.json
126
- game_id = session.get('game_id')
127
- move = data.get('move')
128
-
129
- if not game_id or game_id not in games:
130
- return jsonify({"success": False, "error": "Partie non trouvée"})
131
-
132
- game = games[game_id]
133
- success, message = game.make_move(move)
134
-
135
- if not success:
136
- return jsonify({"success": False, "error": message})
137
-
138
- response_data = {
139
- "success": True,
140
- "game_state": game.get_game_state()
141
- }
142
-
143
- # Si c'est le mode AI et c'est au tour de l'IA
144
- if game.mode == "ai" and game.current_player == "black" and not game.game_over:
145
- ai_move = game.get_ai_move()
146
- if ai_move:
147
- game.make_move(ai_move)
148
- response_data["ai_move"] = ai_move
149
- response_data["game_state"] = game.get_game_state()
150
-
151
- return jsonify(response_data)
152
-
153
- @app.route('/api/game_state', methods=['GET'])
154
- def get_game_state():
155
- """Obtenir l'état actuel du jeu"""
156
- game_id = session.get('game_id')
157
-
158
- if not game_id or game_id not in games:
159
- return jsonify({"success": False, "error": "Partie non trouvée"})
160
-
161
- game = games[game_id]
 
 
 
 
 
 
 
 
 
162
  return jsonify({
163
- "success": True,
164
- "game_state": game.get_game_state()
 
 
 
 
 
 
 
165
  })
166
 
167
- @app.route('/api/legal_moves', methods=['GET'])
168
- def get_legal_moves():
169
- """Obtenir les coups légaux pour la position actuelle"""
170
- game_id = session.get('game_id')
171
-
172
- if not game_id or game_id not in games:
173
- return jsonify({"success": False, "error": "Partie non trouvée"})
174
-
175
- game = games[game_id]
176
  return jsonify({
177
- "success": True,
178
- "legal_moves": game.get_legal_moves()
 
 
 
179
  })
180
 
181
- @app.route('/api/reset_game', methods=['POST'])
182
- def reset_game():
183
- """Réinitialiser la partie actuelle"""
184
- game_id = session.get('game_id')
185
-
186
- if game_id and game_id in games:
187
- mode = games[game_id].mode
188
- games[game_id] = ChessGame(game_id, mode)
189
-
190
- return jsonify({
191
- "success": True,
192
- "game_state": games[game_id].get_game_state()
193
- })
194
-
195
- return jsonify({"success": False, "error": "Partie non trouvée"})
196
 
197
  if __name__ == '__main__':
 
 
198
  app.run(debug=True)
 
1
  from flask import Flask, render_template, request, jsonify, session
2
+ from flask_session import Session # Pour gérer les sessions côté serveur si besoin de plus de complexité
3
+ import chess
4
+ import chess.svg
5
  from stockfish import Stockfish
6
+ import os
 
7
 
8
  app = Flask(__name__)
9
+
10
+ # Configuration de la clé secrète pour les sessions Flask
11
+ app.config["SECRET_KEY"] = os.urandom(24) # Ou une chaîne fixe pour le développement
12
+
13
+ # Configuration pour Flask-Session (stocke les sessions côté serveur, ex: filesystem)
14
+ # Ceci est optionnel pour cet exemple simple où FEN est petit, mais bon pour des états plus complexes.
15
+ app.config["SESSION_PERMANENT"] = False
16
+ app.config["SESSION_TYPE"] = "filesystem" # Peut être redis, memcached, etc.
17
+ Session(app)
18
+
19
+ # --- IMPORTANT : MODIFIEZ CE CHEMIN ---
20
+ # Mettez le chemin absolu vers votre exécutable Stockfish
21
+ # Exemples:
22
+ # Windows: "C:\\Chemin\\Vers\\Stockfish\\stockfish_15.1_win_x64_avx2.exe"
23
+ # macOS/Linux: "/usr/local/bin/stockfish" ou "./stockfish-ubuntu-x86-64-avx2"
24
+ STOCKFISH_PATH = "/usr/local/bin/stockfish" # <--- MODIFIEZ CECI !
25
+
26
+ try:
27
+ stockfish = Stockfish(path=STOCKFISH_PATH,
28
+ depth=15, # Profondeur de recherche par défaut
29
+ parameters={
30
+ "Skill Level": 5, # Niveau de compétence (0-20)
31
+ "Threads": 2, # Nombre de threads CPU à utiliser
32
+ "Hash": 128 # Mémoire pour la table de transposition (en Mo)
33
+ })
34
+ print(f"Stockfish initialisé avec succès. Version: {stockfish.get_stockfish_major_version()}")
35
+ except Exception as e:
36
+ print(f"ERREUR: Impossible d'initialiser Stockfish. Vérifiez le chemin: {STOCKFISH_PATH}")
37
+ print(f"Détail de l'erreur: {e}")
38
+ stockfish = None # Pour que l'app puisse démarrer même si SF échoue (mode IA sera désactivé)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
 
40
  @app.route('/')
41
  def index():
42
+ """Affiche la page principale du jeu."""
43
+ # Initialiser un nouveau plateau si aucun n'existe dans la session
44
+ if 'board_fen' not in session:
45
+ board = chess.Board()
46
+ session['board_fen'] = board.fen()
47
+ session['game_mode'] = 'human' # ou 'ai'
48
+ session['player_color'] = chess.WHITE # Si l'humain joue les blancs contre l'IA
49
+ return render_template('index.html', initial_fen=session['board_fen'])
50
 
51
+ @app.route('/new_game', methods=['POST'])
52
  def new_game():
53
+ """Commence une nouvelle partie."""
54
+ data = request.get_json()
55
+ mode = data.get('mode', 'human') # 'human' ou 'ai'
56
+ player_plays_white = data.get('player_color_white', True) # True si le joueur joue blanc
57
+
58
+ board = chess.Board()
59
+ session['board_fen'] = board.fen()
60
+ session['game_mode'] = mode
61
+ session['player_color'] = chess.WHITE if player_plays_white else chess.BLACK
62
+
63
+ ai_move_uci = None
64
+ ai_move_san = None
65
+
66
+ if mode == 'ai' and not player_plays_white: # L'IA joue les blancs (premier coup)
67
+ if stockfish:
68
+ stockfish.set_fen_position(board.fen())
69
+ best_move_uci = stockfish.get_best_move()
70
+ if best_move_uci:
71
+ move = chess.Move.from_uci(best_move_uci)
72
+ ai_move_san = board.san(move)
73
+ board.push(move)
74
+ session['board_fen'] = board.fen()
75
+ ai_move_uci = best_move_uci
76
+ else:
77
+ return jsonify({'error': 'Stockfish non disponible'}), 500
78
+
79
  return jsonify({
80
+ 'fen': board.fen(),
81
+ 'board_svg': chess.svg.board(board=board, size=350),
82
+ 'turn': 'Blanc' if board.turn == chess.WHITE else 'Noir',
83
+ 'game_over': board.is_game_over(),
84
+ 'status': get_game_status(board),
85
+ 'ai_move_uci': ai_move_uci,
86
+ 'ai_move_san': ai_move_san
87
  })
88
 
89
+ @app.route('/move', methods=['POST'])
90
  def make_move():
91
+ """Gère un coup du joueur et potentiellement la réponse de l'IA."""
92
+ if 'board_fen' not in session:
93
+ return jsonify({'error': 'Partie non initialisée. Commencez une nouvelle partie.'}), 400
94
+
95
+ board = chess.Board(session['board_fen'])
96
+ game_mode = session.get('game_mode', 'human')
97
+ player_color = session.get('player_color', chess.WHITE)
98
+
99
+ data = request.get_json()
100
+ move_uci = data.get('move') # ex: "e2e4"
101
+
102
+ if not move_uci:
103
+ return jsonify({'error': 'Aucun coup fourni'}), 400
104
+
105
+ player_move_san = None
106
+ try:
107
+ move = chess.Move.from_uci(move_uci)
108
+ if move in board.legal_moves:
109
+ player_move_san = board.san(move)
110
+ board.push(move)
111
+ session['board_fen'] = board.fen()
112
+ else:
113
+ return jsonify({'error': 'Coup illégal', 'fen': board.fen(), 'board_svg': chess.svg.board(board=board, size=350)}), 400
114
+ except ValueError:
115
+ return jsonify({'error': 'Format de coup invalide', 'fen': board.fen(), 'board_svg': chess.svg.board(board=board, size=350)}), 400
116
+
117
+ ai_move_uci = None
118
+ ai_move_san = None
119
+ game_over = board.is_game_over()
120
+ status = get_game_status(board)
121
+
122
+ if not game_over and game_mode == 'ai' and board.turn != player_color:
123
+ if stockfish:
124
+ stockfish.set_fen_position(board.fen())
125
+ best_move_ai_uci = stockfish.get_best_move_time(1000) # L'IA réfléchit max 1 seconde
126
+ if best_move_ai_uci:
127
+ ai_chess_move = chess.Move.from_uci(best_move_ai_uci)
128
+ ai_move_san = board.san(ai_chess_move)
129
+ board.push(ai_chess_move)
130
+ session['board_fen'] = board.fen()
131
+ ai_move_uci = best_move_ai_uci
132
+ game_over = board.is_game_over() # Vérifier à nouveau après le coup de l'IA
133
+ status = get_game_status(board)
134
+ else:
135
+ status = "Stockfish non disponible. L'IA ne peut pas jouer."
136
+
137
+
138
  return jsonify({
139
+ 'fen': board.fen(),
140
+ 'board_svg': chess.svg.board(board=board, size=350, lastmove=move if not ai_move_uci else ai_chess_move),
141
+ 'turn': 'Blanc' if board.turn == chess.WHITE else 'Noir',
142
+ 'game_over': game_over,
143
+ 'status': status,
144
+ 'player_move_san': player_move_san,
145
+ 'ai_move_uci': ai_move_uci,
146
+ 'ai_move_san': ai_move_san,
147
+ 'last_move_uci': move_uci if not ai_move_uci else ai_move_uci
148
  })
149
 
150
+ @app.route('/get_board_state')
151
+ def get_board_state():
152
+ if 'board_fen' not in session:
153
+ return jsonify({'error': 'Partie non initialisée'}), 404
154
+ board = chess.Board(session['board_fen'])
 
 
 
 
155
  return jsonify({
156
+ 'fen': board.fen(),
157
+ 'board_svg': chess.svg.board(board=board, size=350),
158
+ 'turn': 'Blanc' if board.turn == chess.WHITE else 'Noir',
159
+ 'game_over': board.is_game_over(),
160
+ 'status': get_game_status(board)
161
  })
162
 
163
+ def get_game_status(board):
164
+ if board.is_checkmate():
165
+ return f"Échec et mat ! {'Les Noirs' if board.turn == chess.WHITE else 'Les Blancs'} gagnent."
166
+ if board.is_stalemate():
167
+ return "Pat ! Partie nulle."
168
+ if board.is_insufficient_material():
169
+ return "Matériel insuffisant. Partie nulle."
170
+ if board.is_seventyfive_moves():
171
+ return "Règle des 75 coups. Partie nulle."
172
+ if board.is_fivefold_repetition():
173
+ return "Répétition (5 fois). Partie nulle."
174
+ if board.is_check():
175
+ return "Échec !"
176
+ return "Partie en cours."
 
177
 
178
  if __name__ == '__main__':
179
+ if not os.path.exists("flask_session"): # Crée le dossier pour les sessions si besoin
180
+ os.makedirs("flask_session")
181
  app.run(debug=True)