drawing a tile

This commit is contained in:
Didictateur 2026-02-25 21:14:32 +01:00
parent b9901c133c
commit eaae09676b
4 changed files with 79 additions and 10 deletions

View file

@ -23,4 +23,4 @@ EXPOSE 5000
# Définir PYTHONPATH pour que les imports relatifs fonctionnent # Définir PYTHONPATH pour que les imports relatifs fonctionnent
ENV PYTHONPATH=/app:$PYTHONPATH ENV PYTHONPATH=/app:$PYTHONPATH
CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:5000", "api:app"] CMD ["gunicorn", "-w", "1", "-b", "0.0.0.0:5000", "api:app"]

View file

@ -128,6 +128,7 @@ def start_game():
def game_state(): def game_state():
global current_game global current_game
with game_lock: 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: if current_game is None:
return jsonify({'error': 'Aucune partie en cours'}), 400 return jsonify({'error': 'Aucune partie en cours'}), 400
return jsonify({'state': current_game.get_state()}) return jsonify({'state': current_game.get_state()})
@ -186,5 +187,15 @@ def game_get_actions(player_id):
actions = current_game.get_possible_actions(player_id) actions = current_game.get_possible_actions(player_id)
return jsonify({'actions': actions}) 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()})
if __name__ == '__main__': if __name__ == '__main__':
app.run(debug=True, port=5000) app.run(debug=True, port=5000)

View file

@ -61,10 +61,13 @@ class Game:
self.hidden_discards_bots = [[] for _ in range(3)] self.hidden_discards_bots = [[] for _ in range(3)]
def play_draw(self): def play_draw(self):
if self.turn == 0: print(f"[Game] play_draw called: has_draw={self.has_draw}, turn={self.turn}")
self.hand_player.draw(self.wall.draw()) if not self.has_draw:
self.has_draw = True if self.turn == 0:
print(f"player {self.turn} has draw") tile = self.wall.draw()
self.hand_player.draw_tile(tile)
self.has_draw = True
print(f"Change has_draw to {self.has_draw}")
def draw_tile(self, hand: Hand): def draw_tile(self, hand: Hand):
tile = self.wall.draw() tile = self.wall.draw()
@ -81,14 +84,13 @@ class Game:
def get_state(self): def get_state(self):
"""Retourne l'état actuel de la partie (joueurs, scores, main, etc.).""" """Retourne l'état actuel de la partie (joueurs, scores, main, etc.)."""
hand_tiles = list(getattr(self.hand_player, 'tiles', [])) hand_tiles = list(getattr(self.hand_player, 'tiles', []))
if getattr(self.hand_player, 'draw', None) is not None:
hand_tiles = hand_tiles + [self.hand_player.draw]
return { return {
'scores': list(self.scores), 'scores': list(self.scores),
'winds': list(self.winds), 'winds': list(self.winds),
'turn': int(self.turn), 'turn': int(self.turn),
'riichi': list(self.riichi), 'riichi': list(self.riichi),
'repeat': int(self.repeat), 'repeat': int(self.repeat),
'has_draw': bool(self.has_draw),
'end': bool(self.end), 'end': bool(self.end),
'hand_player': [ 'hand_player': [
{ {
@ -98,7 +100,16 @@ class Game:
'svg': tile.get_img() 'svg': tile.get_img()
} }
for tile in hand_tiles for tile in hand_tiles
] ],
'draw': (
{
'id': self.hand_player.draw.id,
'family': str(self.hand_player.draw.family),
'value': str(self.hand_player.draw.value),
'svg': self.hand_player.draw.get_img()
}
if self.hand_player.draw is not None else None
)
} }
def declare_riichi(self, player_id): def declare_riichi(self, player_id):

View file

@ -135,6 +135,46 @@
<script src="/frontend/js/fr/texts.js"></script> <script src="/frontend/js/fr/texts.js"></script>
<script> <script>
let isDrawing = false;
// Fonction pour mettre à jour l'état du jeu
function updateGameState() {
if (isDrawing) {
console.log('[JS] draw already in progress, skip');
return;
}
fetch('/api/game/state')
.then(r => r.json())
.then(data => {
if (data.state && data.state.has_draw === false) {
console.log('[JS] has_draw is false, will try draw in 10s');
isDrawing = true;
setTimeout(() => {
fetch('/api/play_draw', { method: 'POST' })
.then(() => {
isDrawing = false;
console.log('[JS] draw finished, polling resumes');
});
}, 500);
return;
}
if (data.state && Array.isArray(data.state.hand_player)) {
window.lastDrawTile = data.state.draw ? data.state.draw.svg : null;
displayHand(data.state.hand_player, 'hand-0');
}
[1, 2, 3].forEach(id => {
fetch(`/api/game/hand/${id}`)
.then(r => r.json())
.then(botData => {
if (botData.hand) {
displayHand(botData.hand, `hand-${id}`);
}
});
});
});
}
setInterval(updateGameState, 500);
// Charger le menu // Charger le menu
fetch('/components/menu.html') fetch('/components/menu.html')
.then(r => r.text()) .then(r => r.text())
@ -168,10 +208,18 @@
} }
display.appendChild(tileDiv); display.appendChild(tileDiv);
}); });
// Affiche la tuile draw à la fin si elle existe (pour hand-0)
if (displayId === 'hand-0' && window.lastDrawTile) {
const drawDiv = document.createElement('div');
drawDiv.id = 'draw-tile';
drawDiv.style.marginLeft = '10px';
drawDiv.innerHTML = window.lastDrawTile;
display.appendChild(drawDiv);
}
} }
// Polling pour récupérer la main d'un bot // Polling pour récupérer la main d'un bot
function fetchBotHandWithRetry(id, tries = 8, delay = 300) { function fetchBotHandWithRetry(id, tries = 8, delay = 500) {
fetch(`/api/game/hand/${id}`) fetch(`/api/game/hand/${id}`)
.then(r => r.json()) .then(r => r.json())
.then(botData => { .then(botData => {
@ -201,7 +249,6 @@
if (data.state && data.state.has_draw === false) { if (data.state && data.state.has_draw === false) {
fetch('/api/play_draw', { method: 'POST' }) fetch('/api/play_draw', { method: 'POST' })
.then(() => { .then(() => {
location.reload();
}); });
return; return;
} }