domino-engine
Version:
Domino Engine to create Domino Games. The library would generate all the tiles and structures to easily create one of the multiple domino games.
133 lines (107 loc) • 3.22 kB
text/typescript
export enum Pips {
blank = "0",
one = "1",
two = "2",
tree = "3",
four = "4",
five = "5",
six = "6",
seven = "7",
eight = "8",
nine = "9",
ten = "10",
eleven = "11",
twelve = "12",
}
export const Values: number[] = Object.keys(Pips).map((pip) =>
Number(Pips[pip])
);
export const ValuesToKeys = Object.keys(Pips).reduce((acum, pip) => {
acum[Pips[pip]] = pip;
return acum;
}, {});
export const KeysToValues = Object.keys(Pips).reduce((acum, pip) => {
acum[pip] = Number(Pips[pip]);
return acum;
}, {});
export class Tile {
private values: [Pips, Pips];
private isDouble: boolean = false;
private connected = new Set<{ value: Pips; tile: Tile }>();
public isRoot: boolean = false;
constructor(one: Pips, two: Pips) {
this.values = [one, two];
if (one === two) {
this.isDouble = true;
}
}
value = () => [...this.values];
toString = () => `[${this.values[0]},${this.values[1]}]`;
has = (match: Pips) => this.values.includes(match);
canAttach = (tile: Tile) => {
const [value1, value2] = tile.value();
const match = this.has(value1) || this.has(value2);
if (!match) return false;
return this.isDouble ? this.connected.size <= 4 : this.connected.size <= 2;
};
attach = (tile: Tile, value: Pips, options: { clean?: boolean } = {}) => {
const ofSameValue = [...this.connected].filter(
(currentTile) => currentTile.value === value
).length;
const enoughSpace = this.isDouble ? ofSameValue < 3 : ofSameValue < 2;
if (this.canAttach(tile) && tile.canAttach(this) && enoughSpace) {
this.connected.add({ value, tile });
if (!options.clean) {
tile.attach(this, value, { clean: true });
}
return true;
}
return false;
};
attached = () => [...this.connected];
}
export type Suite = {
[key in Pips]: Tile;
};
export type Hand = Set<Tile>;
export const generateSuite = (amount?: Pips) => {
const box = new Set<Tile>();
const max = Number(amount || Values[Values.length - 1]);
for (let suiteIndex = max; suiteIndex > -1; suiteIndex--) {
const suite = Pips[ValuesToKeys[suiteIndex]];
const suiteTile = new Tile(suite, suite);
box.add(suiteTile);
for (let valueIndex = suiteIndex - 1; valueIndex > -1; valueIndex--) {
const value = Pips[ValuesToKeys[valueIndex]];
const tile: Tile = new Tile(suite, value);
box.add(tile);
}
}
return box;
};
export class Box {
private box: Tile[];
constructor(options: { box?: Set<Tile>; level?: Pips } = {}) {
this.box = [...(options.box || generateSuite(options.level)).values()];
}
next = (amount: number = 1) => {
const drawed: Tile[] = [];
while (amount > 0) {
const tile = this.box.pop();
drawed.push(tile);
amount--;
}
return drawed;
};
draw = () => this.box.splice(~~(Math.random() * this.box.length), 1);
suffle = () => {
const shuffled: Tile[] = [];
while (this.box.length !== 0) {
const randomIndex = ~~(Math.random() * this.box.length);
shuffled.push(this.box[randomIndex]);
this.box.splice(randomIndex, 1);
}
this.box = shuffled;
};
valueOf = () => [...this.box];
}