// frontend/js/game.js // Adaptation frontend de la logique de game.py en JavaScript async function think(t) { return new Promise(resolve => setTimeout(resolve, 1000 * t)); } class Wall { constructor() { this.tiles = Tile.generateAll(); this.shuffle(); } 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]]; } } draw() { return this.tiles.shift(); } drawHand() { const handTiles = this.tiles.splice(0, 13); return new Hand(handTiles); } } class Hand { constructor(tiles) { this.tiles = tiles; this.draw = null; } drawTile(tile) { this.draw = tile; } discardTile(tileId) { let idx = this.tiles.findIndex(t => t.id === tileId); if (idx !== -1) { return this.tiles.splice(idx, 1)[0]; } if (this.draw && this.draw.id === tileId) { const discarded = this.draw; this.draw = null; return discarded; } return null; } flatten() { if (this.draw) { this.tiles.push(this.draw); this.draw = null; } } } class Game { constructor(onUpdate) { this.wall = new Wall(); this.handPlayer = this.wall.drawHand(); this.discardPlayer = []; this.handsBots = [this.wall.drawHand(), this.wall.drawHand(), this.wall.drawHand()]; this.discardsBots = [[], [], []]; this.turn = 0; this.hasDraw = true; this.end = false; this.onUpdate = onUpdate || (() => {}); // Est pioche une tuile const tile = this.wall.draw(); if (tile) this.handPlayer.drawTile(tile); this.onUpdate(this); } drawTile(hand) { const tile = this.wall.draw(); if (tile) hand.drawTile(tile); } putTile(hand, tileId) { const discarded = hand.discardTile(tileId); if (discarded) { this.wall.tiles.push(discarded); this.wall.shuffle(); } } async nextTurn() { this.turn = (this.turn + 1) % 4; this.hasDraw = false; this.onUpdate(this); if (this.turn !== 0) { await this.botTurn(); } else { this.drawTile(this.handPlayer); this.hasDraw = true; this.onUpdate(this); } } async botTurn() { const bot = this.handsBots[this.turn - 1]; this.drawTile(bot); this.onUpdate(this); // Affiche la pioche await think(2); // Défausse une tuile aléatoire const idx = Math.floor(Math.random() * bot.tiles.length); const tileToDiscard = bot.tiles[idx]; const discarded = bot.discardTile(tileToDiscard.id); bot.flatten() this.onUpdate(this); // Affiche la défausse await think(0.5); if (discarded) this.discardsBots[this.turn - 1].push(discarded); await this.nextTurn(); } async discardTile(tileId) { if (this.turn === 0 && this.hasDraw) { const wasDraw = (this.handPlayer.draw && this.handPlayer.draw.id === tileId); const discarded = this.handPlayer.discardTile(tileId); // Si la tuile défaussée n'était pas draw, on intègre draw à la main avant le rendu if (!wasDraw) { this.handPlayer.flatten(); } this.onUpdate(this); // Affiche la défausse if (discarded) this.discardPlayer.push(discarded); await this.nextTurn(); return discarded; } return null; } } // Expose dans le scope global window.Game = Game; window.Hand = Hand; window.Wall = Wall;