135 lines
3.4 KiB
JavaScript
135 lines
3.4 KiB
JavaScript
// 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;
|