Riichi/backend/src/api.py
2026-02-26 19:03:05 +01:00

221 lines
7.5 KiB
Python

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/<int:tile_id>', 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'<svg viewBox="0 0 500 700" width="100" height="140">{tile.get_img()}</svg>'
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/<int:player_id>', 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/<int:player_id>', 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/<int:player_id>', 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)