Docfile commited on
Commit
bf22ad3
·
verified ·
1 Parent(s): 55ab6b8

Update app.py

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