219 lines
5.4 KiB
JavaScript
219 lines
5.4 KiB
JavaScript
import "./tile.js";
|
|
|
|
class Group {
|
|
constructor(tiles, stollenTile = null, dir = null) {
|
|
this.tiles = tiles;
|
|
this.stollenTile = stollenTile;
|
|
this.dir = dir; // 1 for left, 2 for middle, 3 for right
|
|
}
|
|
}
|
|
|
|
class Hand {
|
|
constructor(tiles = []) {
|
|
this.tiles = tiles;
|
|
this.groups = [];
|
|
this.drawn= null;
|
|
}
|
|
|
|
drawTile(tile) {
|
|
this.drawn = tile;
|
|
}
|
|
|
|
discard(k) {
|
|
if (k === this.tiles.length) {
|
|
const tile = this.drawn;
|
|
this.drawn = null;
|
|
return tile;
|
|
} else {
|
|
const tile = this.tiles[k];
|
|
this.tiles.splice(k, 1);
|
|
return tile;
|
|
}
|
|
}
|
|
|
|
sort() {
|
|
this.tiles.sort((a, b) => {
|
|
if (a.lessThan(b)) return -1;
|
|
if (b.lessThan(a)) return 1;
|
|
return 0;
|
|
});
|
|
}
|
|
|
|
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);
|
|
}
|
|
this.drawn = null;
|
|
this.sort();
|
|
}
|
|
|
|
makeGroup(tiles, stollenTile = null, dir = null) {
|
|
const group = new Group(tiles, stollenTile, dir);
|
|
this.groups.push(group);
|
|
for (let tile of tiles) {
|
|
const index = this.tiles.findIndex(t => t.equals(tile));
|
|
if (index !== -1) {
|
|
this.tiles.splice(index, 1);
|
|
}
|
|
}
|
|
this.flatten();
|
|
}
|
|
}
|
|
|
|
class Draw {
|
|
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]];
|
|
}
|
|
}
|
|
|
|
drawTile() {
|
|
return this.tiles.pop();
|
|
}
|
|
|
|
drawHand() {
|
|
const handTiles = [];
|
|
for (let i = 0; i < 13; i++) {
|
|
handTiles.push(this.drawTile());
|
|
}
|
|
return new Hand(handTiles);
|
|
}
|
|
}
|
|
|
|
class Discard {
|
|
constructor() {
|
|
this.tiles = [];
|
|
this.hiddenTiles = [];
|
|
}
|
|
|
|
add(tile) {
|
|
this.tiles.push(tile);
|
|
}
|
|
|
|
beeingStollen() {
|
|
this.hiddenTiles.push(this.tiles.pop());
|
|
return this.hiddenTiles[this.hiddenTiles.length - 1];
|
|
}
|
|
|
|
isIn(tile) {
|
|
return this.tiles.some(t => t.equals(tile)) || this.hiddenTiles.some(t => t.equals(tile));
|
|
}
|
|
}
|
|
|
|
class Game {
|
|
constructor(skipInitialDeal = false) {
|
|
this.discards = [
|
|
new Discard(),
|
|
new Discard(),
|
|
new Discard(),
|
|
new Discard()
|
|
];
|
|
this.wall = new Draw();
|
|
|
|
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;
|
|
|
|
if (!skipInitialDeal) {
|
|
this.draw(this.turn);
|
|
}
|
|
}
|
|
|
|
newDeal(hasRepeat = false) {
|
|
this.discards = [
|
|
new Discard(),
|
|
new Discard(),
|
|
new Discard(),
|
|
new Discard()
|
|
];
|
|
this.wall = new Draw();
|
|
this.hands = [
|
|
this.wall.drawHand(),
|
|
this.wall.drawHand(),
|
|
this.wall.drawHand(),
|
|
this.wall.drawHand()
|
|
];
|
|
if (!hasRepeat) {
|
|
this.turn = (this.firstDealer + 1) % 4;
|
|
} else {
|
|
this.repeat++;
|
|
}
|
|
}
|
|
|
|
nextTurn() {
|
|
this.turn = (this.turn + 1) % 4;
|
|
}
|
|
|
|
draw(player) {
|
|
this.hands[player].drawTile(this.wall.drawTile());
|
|
}
|
|
|
|
discard(player, k) {
|
|
if (player === this.turn) {
|
|
const tile = this.hands[player].discard(k);
|
|
this.discards[player].add(tile);
|
|
this.hands[player].flatten();
|
|
}
|
|
}
|
|
|
|
chii(player, tiles, dir) {
|
|
const hand = this.hands[player];
|
|
dir = (player - this.turn) % 4;
|
|
console.assert(dir == 1);
|
|
this.hands[player].makeGroup(tiles, this.discards[this.turn].beeingStollen(), dir);
|
|
}
|
|
|
|
pon(player, tiles, dir) {
|
|
const hand = this.hands[player];
|
|
dir = (player - this.turn + 4) % 4;
|
|
console.assert(dir == 1 || dir == 2 ||dir == 3, `Invalid direction: ${dir}`);
|
|
this.hands[player].makeGroup(tiles, this.discards[this.turn].beeingStollen(), dir);
|
|
}
|
|
|
|
canPon(player) {
|
|
const lastTile = this.discards[this.turn].tiles[this.discards[this.turn].tiles.length - 1];
|
|
return this.hands[player].tiles.filter(t => t.equals(lastTile)).length >= 2;
|
|
}
|
|
|
|
botPlay() {
|
|
// Le bot défausse une tuile au hasard (supposant qu'il a déjà pioché)
|
|
const hand = this.hands[this.turn];
|
|
const randomIndex = Math.floor(Math.random() * (hand.tiles.length + (hand.drawn ? 1 : 0)));
|
|
this.discard(this.turn, randomIndex);
|
|
}
|
|
}
|
|
|
|
export { Discard, Draw, Game, Group, Hand };
|
|
|