from flask import Flask, jsonify, request from flask_cors import CORS from game.tile import * from game.hand import * from game.game import * from game.error import * app = Flask(__name__) import threading CORS(app) tiles = Tile.generateAll() current_game = None # Stockage de la partie actuelle game_lock = threading.Lock() # ============= GET ================ @app.route('/api/tiles', methods=['GET']) def get_all_tiles(): """Récupère toutes les tuiles""" tiles_data = [ { 'id': tile.id, 'family': str(tile.family), 'value': str(tile.value), 'svg': tile.get_img() } for tile in tiles ] return jsonify({'tiles': tiles_data}) @app.route('/api/tiles/', methods=['GET']) def get_tile(tile_id): if tile_id < 0 or tile_id >= len(tiles): return jsonify({'error': 'Tuile non trouvée'}), 404 tile = tiles[tile_id] svg = f'{tile.get_img()}' return jsonify({ 'id': tile.id, 'family': str(tile.family), 'value': str(tile.value), 'svg': svg }) @app.route('/api/random_hand', methods=['GET']) def get_random_hand(): """Récupère une main aléatoire de 13 tuiles""" hand = Hand.random() hand_data = [ { 'id': tile.id, 'family': str(tile.family), 'value': str(tile.value), 'svg': tile.get_img() } for tile in hand.tiles ] return jsonify({'hand': hand_data}) @app.route('/api/hand_with_draw', methods=['GET']) def get_hand_with_draw(): """Crée une partie et retourne le hand_player avec une tuile piochée""" global current_game with game_lock: current_game = Game() current_game.draw_tile(current_game.hand_player) hand_data = [ { 'id': tile.id, 'family': str(tile.family), 'value': str(tile.value), 'svg': tile.get_img() } for tile in current_game.hand_player.tiles ] draw_data = { 'id': current_game.hand_player.draw.id, 'family': str(current_game.hand_player.draw.family), 'value': str(current_game.hand_player.draw.value), 'svg': current_game.hand_player.draw.get_img() } if getattr(current_game.hand_player, 'draw', None) else None return jsonify({'hand': hand_data, 'draw': draw_data}) @app.route('/api/discard', methods=['POST']) def discard_tile(): """Défausse une tuile de la main du joueur et pioche une nouvelle""" global current_game with game_lock: if current_game is None: return jsonify({'error': 'Aucune partie en cours'}), 400 data = request.json tile_id = data.get('tile_id') if tile_id is None: return jsonify({'error': 'tile_id manquant'}), 400 current_game.put_tile(current_game.hand_player, tile_id) current_game.draw_tile(current_game.hand_player) hand_data = [ { 'id': tile.id, 'family': str(tile.family), 'value': str(tile.value), 'svg': tile.get_img() } for tile in current_game.hand_player.tiles ] draw_data = { 'id': current_game.hand_player.draw.id, 'family': str(current_game.hand_player.draw.family), 'value': str(current_game.hand_player.draw.value), 'svg': current_game.hand_player.draw.get_img() } if getattr(current_game.hand_player, 'draw', None) else None return jsonify({'hand': hand_data, 'draw': draw_data}) # ============== POST ================ # ============== GAME MANAGEMENT ================ # Démarrer une nouvelle partie @app.route('/api/game/start', methods=['POST']) def start_game(): global current_game with game_lock: current_game = Game() return jsonify({'status': 'started', 'state': current_game.get_state()}) # Récupérer l'état de la partie @app.route('/api/game/state', methods=['GET']) def game_state(): global current_game with game_lock: print(f"[API] /api/game/state called. current_game is {'None' if current_game is None else 'OK'}") if current_game is None: return jsonify({'error': 'Aucune partie en cours'}), 400 return jsonify({'state': current_game.get_state()}) # Passer au tour suivant @app.route('/api/game/next_turn', methods=['POST']) def game_next_turn(): global current_game with game_lock: if current_game is None: return jsonify({'error': 'Aucune partie en cours'}), 400 current_game.next_turn() return jsonify({'state': current_game.get_state()}) # Déclarer Riichi @app.route('/api/game/riichi', methods=['POST']) def game_declare_riichi(): global current_game with game_lock: if current_game is None: return jsonify({'error': 'Aucune partie en cours'}), 400 data = request.json player_id = data.get('player_id') if player_id is None: return jsonify({'error': 'player_id manquant'}), 400 current_game.declare_riichi(player_id) return jsonify({'state': current_game.get_state()}) # Récupérer la main d'un joueur @app.route('/api/game/hand/', methods=['GET']) def game_get_hand(player_id): global current_game with game_lock: if current_game is None: return jsonify({'error': 'Aucune partie en cours'}), 400 hand = current_game.get_hand(player_id) return jsonify({'hand': hand}) # Récupérer les défausses d'un joueur @app.route('/api/game/discards/', methods=['GET']) def game_get_discards(player_id): global current_game with game_lock: if current_game is None: return jsonify({'error': 'Aucune partie en cours'}), 400 discards = current_game.get_discards(player_id) return jsonify({'discards': discards}) # Récupérer les actions possibles pour un joueur @app.route('/api/game/actions/', methods=['GET']) def game_get_actions(player_id): global current_game with game_lock: if current_game is None: return jsonify({'error': 'Aucune partie en cours'}), 400 actions = current_game.get_possible_actions(player_id) return jsonify({'actions': actions}) @app.route('/api/play_draw', methods=['POST']) def play_draw_api(): global current_game with game_lock: print('[API] /api/play_draw called') if current_game is None: return jsonify({'error': 'Aucune partie en cours'}), 400 current_game.play_draw() return jsonify({'state': current_game.get_state()}) @app.route('/api/discard_tile', methods=['POST']) def api_discard_tile(): global current_game with game_lock: if current_game is None: return jsonify({'error': 'Aucune partie en cours'}), 400 data = request.json tile_id = data.get('tile_id') if tile_id is None: return jsonify({'error': 'tile_id manquant'}), 400 discarded = current_game.discard_tile(tile_id) if not discarded: return jsonify({'error': 'Tuile non trouvée ou non défaussée'}), 400 return jsonify({'state': current_game.get_state(), 'discarded': { 'id': discarded.id, 'family': str(discarded.family), 'value': str(discarded.value), 'svg': discarded.get_img() }}) if __name__ == '__main__': app.run(debug=True, port=5000)