update game and display player's hand
This commit is contained in:
parent
8964165e78
commit
75d8cba654
4 changed files with 252 additions and 57 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -1,4 +1,5 @@
|
||||||
node_modules/
|
node_modules/
|
||||||
package-lock.json
|
package-lock.json
|
||||||
build/
|
build/
|
||||||
__pycache__
|
__pycache__
|
||||||
|
restart.sh
|
||||||
|
|
@ -7,10 +7,12 @@ from game.game import *
|
||||||
from game.error import *
|
from game.error import *
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
import threading
|
||||||
CORS(app)
|
CORS(app)
|
||||||
|
|
||||||
tiles = Tile.generateAll()
|
tiles = Tile.generateAll()
|
||||||
current_game = None # Stockage de la partie actuelle
|
current_game = None # Stockage de la partie actuelle
|
||||||
|
game_lock = threading.Lock()
|
||||||
|
|
||||||
# ============= GET ================
|
# ============= GET ================
|
||||||
@app.route('/api/tiles', methods=['GET'])
|
@app.route('/api/tiles', methods=['GET'])
|
||||||
|
|
@ -60,65 +62,129 @@ def get_random_hand():
|
||||||
def get_hand_with_draw():
|
def get_hand_with_draw():
|
||||||
"""Crée une partie et retourne le hand_player avec une tuile piochée"""
|
"""Crée une partie et retourne le hand_player avec une tuile piochée"""
|
||||||
global current_game
|
global current_game
|
||||||
current_game = Game()
|
with game_lock:
|
||||||
current_game.draw_tile(current_game.hand_player)
|
current_game = Game()
|
||||||
|
current_game.draw_tile(current_game.hand_player)
|
||||||
hand_data = [
|
hand_data = [
|
||||||
{
|
{
|
||||||
'id': tile.id,
|
'id': tile.id,
|
||||||
'family': str(tile.family),
|
'family': str(tile.family),
|
||||||
'value': str(tile.value),
|
'value': str(tile.value),
|
||||||
'svg': tile.get_img()
|
'svg': tile.get_img()
|
||||||
}
|
}
|
||||||
for tile in current_game.hand_player.tiles
|
for tile in current_game.hand_player.tiles
|
||||||
]
|
]
|
||||||
|
draw_data = {
|
||||||
draw_data = {
|
'id': current_game.hand_player.draw.id,
|
||||||
'id': current_game.hand_player.draw.id,
|
'family': str(current_game.hand_player.draw.family),
|
||||||
'family': str(current_game.hand_player.draw.family),
|
'value': str(current_game.hand_player.draw.value),
|
||||||
'value': str(current_game.hand_player.draw.value),
|
'svg': current_game.hand_player.draw.get_img()
|
||||||
'svg': current_game.hand_player.draw.get_img()
|
} if getattr(current_game.hand_player, 'draw', None) else None
|
||||||
} if current_game.hand_player.draw else None
|
return jsonify({'hand': hand_data, 'draw': draw_data})
|
||||||
|
|
||||||
return jsonify({'hand': hand_data, 'draw': draw_data})
|
|
||||||
|
|
||||||
@app.route('/api/discard', methods=['POST'])
|
@app.route('/api/discard', methods=['POST'])
|
||||||
def discard_tile():
|
def discard_tile():
|
||||||
"""Défausse une tuile de la main du joueur et pioche une nouvelle"""
|
"""Défausse une tuile de la main du joueur et pioche une nouvelle"""
|
||||||
global current_game
|
global current_game
|
||||||
if current_game is None:
|
with game_lock:
|
||||||
return jsonify({'error': 'Aucune partie en cours'}), 400
|
if current_game is None:
|
||||||
|
return jsonify({'error': 'Aucune partie en cours'}), 400
|
||||||
data = request.json
|
data = request.json
|
||||||
tile_id = data.get('tile_id')
|
tile_id = data.get('tile_id')
|
||||||
|
if tile_id is None:
|
||||||
if tile_id is None:
|
return jsonify({'error': 'tile_id manquant'}), 400
|
||||||
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)
|
||||||
current_game.put_tile(current_game.hand_player, tile_id)
|
hand_data = [
|
||||||
current_game.draw_tile(current_game.hand_player)
|
{
|
||||||
|
'id': tile.id,
|
||||||
# Retourner la main mise à jour
|
'family': str(tile.family),
|
||||||
hand_data = [
|
'value': str(tile.value),
|
||||||
{
|
'svg': tile.get_img()
|
||||||
'id': tile.id,
|
}
|
||||||
'family': str(tile.family),
|
for tile in current_game.hand_player.tiles
|
||||||
'value': str(tile.value),
|
]
|
||||||
'svg': tile.get_img()
|
draw_data = {
|
||||||
}
|
'id': current_game.hand_player.draw.id,
|
||||||
for tile in current_game.hand_player.tiles
|
'family': str(current_game.hand_player.draw.family),
|
||||||
]
|
'value': str(current_game.hand_player.draw.value),
|
||||||
|
'svg': current_game.hand_player.draw.get_img()
|
||||||
draw_data = {
|
} if getattr(current_game.hand_player, 'draw', None) else None
|
||||||
'id': current_game.hand_player.draw.id,
|
return jsonify({'hand': hand_data, 'draw': draw_data})
|
||||||
'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 current_game.hand_player.draw else None
|
|
||||||
|
|
||||||
return jsonify({'hand': hand_data, 'draw': draw_data})
|
|
||||||
|
|
||||||
# ============== POST ================
|
# ============== 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:
|
||||||
|
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})
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app.run(debug=True, port=5000)
|
app.run(debug=True, port=5000)
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,57 @@ from .wall import *
|
||||||
import random as rd
|
import random as rd
|
||||||
|
|
||||||
class Game:
|
class Game:
|
||||||
def __init__(self):
|
def __init__(self, wind=0 , yakus=False, red=False):
|
||||||
self.wall = Wall()
|
self.wall = Wall()
|
||||||
|
|
||||||
self.hand_player = self.wall.draw_hand()
|
self.hand_player = self.wall.draw_hand()
|
||||||
self.bot_hands = [self.wall.draw_hand() for _ in range(3)]
|
self.discard_player = []
|
||||||
|
self.hidden_discard_player = []
|
||||||
|
self.hands_bots = [self.wall.draw_hand() for _ in range(3)]
|
||||||
|
self.discards_bots = [[] for _ in range(3)]
|
||||||
|
self.hidden_discards_bots = [[] for _ in range(3)]
|
||||||
|
|
||||||
|
self.scores = [25000] * 4
|
||||||
|
|
||||||
|
self.winds = [
|
||||||
|
wind % 4, # player
|
||||||
|
(wind+1) % 4, # right of player
|
||||||
|
(wind + 2) % 4, # front of player
|
||||||
|
(wind +3) % 4 # left of player
|
||||||
|
]
|
||||||
|
|
||||||
|
self.initial_est = (-wind) % 4
|
||||||
|
self.turn = self.winds.index(0)
|
||||||
|
|
||||||
|
self.riichi = [False] * 4
|
||||||
|
self.repeat = 0
|
||||||
|
|
||||||
|
self.end = False
|
||||||
|
|
||||||
|
def new_turn(self, repeat=False):
|
||||||
|
if repeat:
|
||||||
|
self.repeat += 1
|
||||||
|
else:
|
||||||
|
self.repeat = 0
|
||||||
|
self.turn = (self.turn + 1) % 4
|
||||||
|
if self.turn == self.initial_est:
|
||||||
|
self.end = True
|
||||||
|
for i in range(4):
|
||||||
|
self.winds[self.turn + i] = i
|
||||||
|
|
||||||
|
self.turn = self.winds.index(0)
|
||||||
|
|
||||||
|
self.riichi = [False] * 4
|
||||||
|
self.repeat = 0
|
||||||
|
|
||||||
|
self.wall = Wall()
|
||||||
|
|
||||||
|
self.hand_player = self.wall.draw_hand()
|
||||||
|
self.discard_player = []
|
||||||
|
self.hidden_discard_player = []
|
||||||
|
self.hands_bots = [self.wall.draw_hand() for _ in range(3)]
|
||||||
|
self.discards_bots = [[] for _ in range(3)]
|
||||||
|
self.hidden_discards_bots = [[] for _ in range(3)]
|
||||||
|
|
||||||
def draw_tile(self, hand: Hand):
|
def draw_tile(self, hand: Hand):
|
||||||
tile = self.wall.draw()
|
tile = self.wall.draw()
|
||||||
|
|
@ -17,4 +63,47 @@ class Game:
|
||||||
|
|
||||||
def put_tile(self, hand: Hand, id: int):
|
def put_tile(self, hand: Hand, id: int):
|
||||||
self.wall.tiles.append(hand.discard_tile(id))
|
self.wall.tiles.append(hand.discard_tile(id))
|
||||||
self.wall.shuffle()
|
self.wall.shuffle()
|
||||||
|
|
||||||
|
def next_turn(self):
|
||||||
|
"""Passe au tour suivant."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_state(self):
|
||||||
|
"""Retourne l'état actuel de la partie (joueurs, scores, main, etc.)."""
|
||||||
|
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 {
|
||||||
|
'scores': list(self.scores),
|
||||||
|
'winds': list(self.winds),
|
||||||
|
'turn': int(self.turn),
|
||||||
|
'riichi': list(self.riichi),
|
||||||
|
'repeat': int(self.repeat),
|
||||||
|
'end': bool(self.end),
|
||||||
|
'hand_player': [
|
||||||
|
{
|
||||||
|
'id': tile.id,
|
||||||
|
'family': str(tile.family),
|
||||||
|
'value': str(tile.value),
|
||||||
|
'svg': tile.get_img()
|
||||||
|
}
|
||||||
|
for tile in hand_tiles
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
def declare_riichi(self, player_id):
|
||||||
|
"""Déclare Riichi pour un joueur."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_hand(self, player_id):
|
||||||
|
"""Retourne la main d'un joueur."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_discards(self, player_id):
|
||||||
|
"""Retourne les tuiles défaussées d'un joueur."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_possible_actions(self, player_id):
|
||||||
|
"""Retourne les actions possibles pour un joueur."""
|
||||||
|
pass
|
||||||
|
|
@ -39,6 +39,22 @@
|
||||||
.speech-bubble.visible {
|
.speech-bubble.visible {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[id^="hand"] {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tiles-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
@ -48,7 +64,9 @@
|
||||||
<div class="speech-text" id="speech-text"></div>
|
<div class="speech-text" id="speech-text"></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="mascotte"></div>
|
<div id="mascotte"></div>
|
||||||
|
|
||||||
|
<div id="hand-0"></div>
|
||||||
|
|
||||||
<script src="/frontend/js/fr/texts.js"></script>
|
<script src="/frontend/js/fr/texts.js"></script>
|
||||||
<script>
|
<script>
|
||||||
// Charger le menu
|
// Charger le menu
|
||||||
|
|
@ -69,6 +87,27 @@
|
||||||
? '<img class="explaining" src="/img/tilineau/explaining.png" alt="Tilineau">'
|
? '<img class="explaining" src="/img/tilineau/explaining.png" alt="Tilineau">'
|
||||||
: '<img src="/img/tilineau/idle.png" alt="Tilineau">';
|
: '<img src="/img/tilineau/idle.png" alt="Tilineau">';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Initialiser une partie au chargement du chapitre 5
|
||||||
|
fetch('/api/game/start', { method: 'POST' })
|
||||||
|
.then(r => r.json())
|
||||||
|
.then(data => {
|
||||||
|
console.log('Réponse API', data);
|
||||||
|
if (data.state && data.state.hand_player) {
|
||||||
|
displayHand(data.state.hand_player, 'hand-0');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(e => console.error('Erreur initialisation partie', e));
|
||||||
|
|
||||||
|
function displayHand(hand, displayId) {
|
||||||
|
const display = document.getElementById(displayId);
|
||||||
|
display.innerHTML = '';
|
||||||
|
hand.forEach(tile => {
|
||||||
|
const tileDiv = document.createElement('div');
|
||||||
|
tileDiv.innerHTML = tile.svg;
|
||||||
|
display.appendChild(tileDiv);
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
Loading…
Reference in a new issue