diff --git a/frontend/js/game.js b/frontend/js/game.js index 3dcff34..ad59f4e 100644 --- a/frontend/js/game.js +++ b/frontend/js/game.js @@ -39,6 +39,13 @@ class Hand { }); } + shuffle() { + for (let i = this.tiles.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [this.tiles[i], this.tiles[j]] = [this.tiles[j], this.tiles[i]]; + } + } + flatten() { if (this.drawn) { this.tiles.push(this.drawn); @@ -107,7 +114,7 @@ class Discard { } class Game { - constructor() { + constructor(skipInitialDeal = false) { this.discards = [ new Discard(), new Discard(), @@ -115,20 +122,33 @@ class Game { new Discard() ]; this.wall = new Draw(); - this.hands = [ - this.wall.drawHand(), - this.wall.drawHand(), - this.wall.drawHand(), - this.wall.drawHand() - ]; - for (let hand of this.hands) { - hand.sort(); + + if (skipInitialDeal) { + this.hands = [ + new Hand(), + new Hand(), + new Hand(), + new Hand() + ]; + } else { + this.hands = [ + this.wall.drawHand(), + this.wall.drawHand(), + this.wall.drawHand(), + this.wall.drawHand() + ]; + for (let hand of this.hands) { + hand.sort(); + } } + this.firstDealer = Math.floor(Math.random() * 4) * 0; this.turn = this.firstDealer; this.repeat = 0; - this.draw(this.turn); + if (!skipInitialDeal) { + this.draw(this.turn); + } } newDeal(hasRepeat = false) { diff --git a/frontend/pages/riichi/chap5.html b/frontend/pages/riichi/chap5.html index b0ad07f..f87b780 100644 --- a/frontend/pages/riichi/chap5.html +++ b/frontend/pages/riichi/chap5.html @@ -344,14 +344,15 @@ startButton.addEventListener('click', () => { startScreen.style.display = 'none'; gameCenter.style.display = 'flex'; - // Instancier une nouvelle partie et afficher les mains - game = new Game(); - renderHands(); - updateTurnIndicator(); + // Instancier une nouvelle partie avec mains vides pour distribution animée + game = new Game(true); + // Lancer l'animation de distribution + distributeHands(); }); // Déclarer les variables et fonctions ici pour qu'elles soient accessibles partout let game; + let isDistributing = false; // Charger le menu fetch('/components/menu.html') .then(r => r.text()) @@ -373,6 +374,119 @@ // Instancier une nouvelle partie et afficher les mains + async function distributeHands() { + isDistributing = true; + // Distribution 4 par 4, puis 1 par 1 comme dans la vraie vie + // 3 rounds de 4 tuiles par joueur = 12 tuiles + for (let round = 0; round < 3; round++) { + for (let player = 0; player < 4; player++) { + for (let i = 0; i < 4; i++) { + game.hands[player].tiles.push(game.wall.drawTile()); + } + renderHands(); + await new Promise(resolve => setTimeout(resolve, 300)); + } + } + + // Distribution finale : 1 par 1 pour la 13e tuile + for (let player = 0; player < 4; player++) { + game.hands[player].tiles.push(game.wall.drawTile()); + renderHands(); + await new Promise(resolve => setTimeout(resolve, 300)); + } + + // Trier les mains avec animation pour le joueur + const playerHandContainer = document.getElementById('hand-0').querySelector('.hand-tiles'); + const playerTiles = game.hands[0].tiles; + const playerTileDivs = Array.from(playerHandContainer.children); + + // Créer un map pour associer chaque tuile à son élément DOM + const tileToElement = new Map(); + playerTileDivs.forEach((div, index) => { + tileToElement.set(playerTiles[index], div); + }); + + // Enregistrer les positions avant tri (en pixels relatifs au conteneur) + const originalPositions = new Map(); + playerTileDivs.forEach((div, index) => { + originalPositions.set(div, index * (60 + 5)); // calcul basé sur width + gap + }); + + // Trier les mains + for (let hand of game.hands) { + hand.sort(); + } + + // Récupérer les nouvelles positions + const newPositions = new Map(); + game.hands[0].tiles.forEach((tile, newIndex) => { + newPositions.set(tileToElement.get(tile), newIndex * (60 + 5)); + }); + + // Appliquer une translation pour que les éléments restent à leur place visuelle + playerTileDivs.forEach(div => { + const originalX = originalPositions.get(div); + const newX = newPositions.get(div); + const deltaX = originalX - newX; + + div.style.transform = `translateX(${deltaX}px)`; + div.style.transition = 'none'; + }); + + // Forcer un reflow + void playerHandContainer.offsetWidth; + + // Ré-ordonner les éléments dans le DOM selon le tri + const sortedDivs = game.hands[0].tiles.map(tile => tileToElement.get(tile)); + sortedDivs.forEach(div => playerHandContainer.appendChild(div)); + + // Forcer un autre reflow + void playerHandContainer.offsetWidth; + + // Animer vers les positions finales + playerTileDivs.forEach(div => { + div.style.transition = 'transform 0.6s ease-in-out'; + div.style.transform = 'translateX(0)'; + }); + + // Attendre la fin de l'animation + await new Promise(resolve => setTimeout(resolve, 600)); + + // Nettoyer les styles + playerTileDivs.forEach(div => { + div.style.transition = ''; + div.style.transform = ''; + }); + + // Re-rendre les bots sans animation + for (let i = 1; i < 4; i++) { + const botHandDiv = document.getElementById(`hand-${i}`); + const botHandTiles = document.createElement('div'); + botHandTiles.className = 'hand-tiles'; + + for (let k = 0; k < game.hands[i].tiles.length; k++) { + const tileDiv = document.createElement('div'); + tileDiv.innerHTML = ` + + + `; + botHandTiles.appendChild(tileDiv); + } + + const botHandWithDraw = botHandDiv.querySelector('.hand-with-draw') || botHandDiv; + const oldHandTiles = botHandWithDraw.querySelector('.hand-tiles'); + if (oldHandTiles) oldHandTiles.remove(); + botHandWithDraw.insertBefore(botHandTiles, botHandWithDraw.firstChild); + } + + // Le joueur 0 pioche sa tuile supplémentaire + await new Promise(resolve => setTimeout(resolve, 500)); + game.draw(game.turn); + renderHands(); + updateTurnIndicator(); + isDistributing = false; + } + function renderHands() { for (let i = 0; i < 4; i++) { const handDiv = document.getElementById(`hand-${i}`); @@ -397,6 +511,9 @@ const handleClick = (() => { const tileToDiscard = tile; return () => { + // Ne rien faire pendant la distribution + if (isDistributing) return; + // Trouver l'index actuel de la tuile const currentIdx = game.hands[0].tiles.findIndex(t => t === tileToDiscard); if (currentIdx !== -1) {