some api interaction
This commit is contained in:
parent
6f7708d368
commit
d526332658
5 changed files with 127 additions and 23 deletions
|
|
@ -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", "1", "-b", "0.0.0.0:5000", "api:app"]
|
CMD ["gunicorn", "-w", "1", "-k", "gevent", "-b", "0.0.0.0:5000", "api:app"]
|
||||||
|
|
|
||||||
|
|
@ -197,5 +197,25 @@ def play_draw_api():
|
||||||
current_game.play_draw()
|
current_game.play_draw()
|
||||||
return jsonify({'state': current_game.get_state()})
|
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__':
|
if __name__ == '__main__':
|
||||||
app.run(debug=True, port=5000)
|
app.run(debug=True, port=5000)
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,17 @@ class Game:
|
||||||
|
|
||||||
self.end = False
|
self.end = False
|
||||||
|
|
||||||
|
# L'Est pioche une tuile dès le début
|
||||||
|
if self.turn == 0:
|
||||||
|
tile = self.wall.draw()
|
||||||
|
self.hand_player.draw_tile(tile)
|
||||||
|
self.has_draw = True
|
||||||
|
else:
|
||||||
|
tile = self.wall.draw()
|
||||||
|
self.hands_bots[self.turn-1].draw_tile(tile)
|
||||||
|
|
||||||
def new_turn(self, repeat=False):
|
def new_turn(self, repeat=False):
|
||||||
|
"""Nouvelle manche"""
|
||||||
if repeat:
|
if repeat:
|
||||||
self.repeat += 1
|
self.repeat += 1
|
||||||
else:
|
else:
|
||||||
|
|
@ -78,8 +88,15 @@ class Game:
|
||||||
self.wall.shuffle()
|
self.wall.shuffle()
|
||||||
|
|
||||||
def next_turn(self):
|
def next_turn(self):
|
||||||
"""Passe au tour suivant."""
|
"""Passe au joueur suivant."""
|
||||||
pass
|
# TODO: check for pon/chii
|
||||||
|
self.turn = (self.turn + 1) % 4
|
||||||
|
self.has_draw = False
|
||||||
|
|
||||||
|
if self.turn != 0: # a bot has to play
|
||||||
|
self.bot_turn()
|
||||||
|
else:
|
||||||
|
self.play_draw()
|
||||||
|
|
||||||
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.)."""
|
||||||
|
|
@ -139,10 +156,55 @@ class Game:
|
||||||
for tile in hand
|
for tile in hand
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_discards(self, player_id):
|
def get_discards(self, player_id: int):
|
||||||
"""Retourne les tuiles défaussées d'un joueur."""
|
if player_id == 0:
|
||||||
pass
|
return [
|
||||||
|
{
|
||||||
|
'id': tile.id,
|
||||||
|
'family': str(tile.family),
|
||||||
|
'value': str(tile.value),
|
||||||
|
'svg': tile.get_img()
|
||||||
|
}
|
||||||
|
for tile in self.discard_player
|
||||||
|
]
|
||||||
|
elif 1 <= player_id <= 3:
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
'id': tile.id,
|
||||||
|
'family': str(tile.family),
|
||||||
|
'value': str(tile.value),
|
||||||
|
'svg': tile.get_img()
|
||||||
|
}
|
||||||
|
for tile in self.discards_bots[player_id - 1]
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
return []
|
||||||
|
|
||||||
def get_possible_actions(self, player_id):
|
def get_possible_actions(self, player_id):
|
||||||
"""Retourne les actions possibles pour un joueur."""
|
"""Retourne les actions possibles pour un joueur."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def bot_turn(self):
|
||||||
|
# Joue un tour de bot sans sleep
|
||||||
|
if self.turn != 0:
|
||||||
|
# Pioche une tuile pour le bot
|
||||||
|
tile = self.wall.draw()
|
||||||
|
self.hands_bots[self.turn - 1].draw_tile(tile)
|
||||||
|
# Défausse une tuile aléatoire
|
||||||
|
hand = self.hands_bots[self.turn - 1]
|
||||||
|
n = rd.randint(0, len(hand.tiles) - 1)
|
||||||
|
tile_to_discard = hand.tiles[n]
|
||||||
|
discarded = hand.discard_tile(tile_to_discard.id)
|
||||||
|
if discarded:
|
||||||
|
self.discards_bots[self.turn - 1].append(discarded)
|
||||||
|
# Passe au joueur suivant
|
||||||
|
self.turn = (self.turn + 1) % 4
|
||||||
|
self.has_draw = True if self.turn == 0 else False
|
||||||
|
|
||||||
|
def discard_tile(self, tile_id: int):
|
||||||
|
# Défausse la tuile (de la main ou de la tuile piochée)
|
||||||
|
if self.turn == 0 and self.has_draw:
|
||||||
|
discarded = self.hand_player.discard_tile(tile_id)
|
||||||
|
if discarded:
|
||||||
|
self.discard_player.append(discarded)
|
||||||
|
self.next_turn()
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
Flask==3.0.0
|
Flask==3.0.0
|
||||||
flask-cors==4.0.0
|
flask-cors==4.0.0
|
||||||
gunicorn==21.2.0
|
gunicorn==21.2.0
|
||||||
|
gevent>=1.4
|
||||||
|
|
@ -145,25 +145,9 @@
|
||||||
|
|
||||||
// Fonction pour mettre à jour l'état du jeu
|
// Fonction pour mettre à jour l'état du jeu
|
||||||
function updateGameState() {
|
function updateGameState() {
|
||||||
if (isDrawing) {
|
|
||||||
console.log('[JS] draw already in progress, skip');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
fetch('/api/game/state')
|
fetch('/api/game/state')
|
||||||
.then(r => r.json())
|
.then(r => r.json())
|
||||||
.then(data => {
|
.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)) {
|
if (data.state && Array.isArray(data.state.hand_player)) {
|
||||||
window.lastDrawTile = data.state.draw ? data.state.draw.svg : null;
|
window.lastDrawTile = data.state.draw ? data.state.draw.svg : null;
|
||||||
displayHand(data.state.hand_player, 'hand-0');
|
displayHand(data.state.hand_player, 'hand-0');
|
||||||
|
|
@ -221,6 +205,8 @@
|
||||||
tileDiv.innerHTML = '<svg viewBox="0 0 310 410" width="60" height="80"><image href="/img/Regular/Back.svg" width="310" height="410"/></svg>';
|
tileDiv.innerHTML = '<svg viewBox="0 0 310 410" width="60" height="80"><image href="/img/Regular/Back.svg" width="310" height="410"/></svg>';
|
||||||
} else {
|
} else {
|
||||||
tileDiv.innerHTML = tile.svg;
|
tileDiv.innerHTML = tile.svg;
|
||||||
|
tileDiv.style.cursor = 'pointer';
|
||||||
|
tileDiv.addEventListener('click', () => discard_tile(tile.id));
|
||||||
}
|
}
|
||||||
display.appendChild(tileDiv);
|
display.appendChild(tileDiv);
|
||||||
});
|
});
|
||||||
|
|
@ -234,6 +220,41 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function discard_tile(tileId) {
|
||||||
|
console.log('[JS] discard_tile', tileId);
|
||||||
|
fetch('/api/discard_tile', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ tile_id: tileId })
|
||||||
|
})
|
||||||
|
.then(r => r.json())
|
||||||
|
.then(data => {
|
||||||
|
console.log('[JS] discard response', data);
|
||||||
|
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');
|
||||||
|
}
|
||||||
|
// Affiche la défausse du joueur
|
||||||
|
if (data.state) {
|
||||||
|
fetch('/api/game/discards/0')
|
||||||
|
.then(r => r.json())
|
||||||
|
.then(discardsData => {
|
||||||
|
displayDiscards(discardsData.discards, 'discards-0');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayDiscards(discards, displayId) {
|
||||||
|
const display = document.getElementById(displayId);
|
||||||
|
display.innerHTML = '';
|
||||||
|
discards.forEach(tile => {
|
||||||
|
const tileDiv = document.createElement('div');
|
||||||
|
tileDiv.innerHTML = tile.svg;
|
||||||
|
display.appendChild(tileDiv);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// 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 = 500) {
|
function fetchBotHandWithRetry(id, tries = 8, delay = 500) {
|
||||||
fetch(`/api/game/hand/${id}`)
|
fetch(`/api/game/hand/${id}`)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue