cannot win without yaku
This commit is contained in:
parent
e82cc8fc7a
commit
3333dbd011
1 changed files with 42 additions and 13 deletions
53
src/game.ts
53
src/game.ts
|
|
@ -138,7 +138,7 @@ export class Game {
|
||||||
if (this.chooseChii) {
|
if (this.chooseChii) {
|
||||||
drawChiis(ctx, this.getChii(0));
|
drawChiis(ctx, this.getChii(0));
|
||||||
} else {
|
} else {
|
||||||
const canTsumoLocal = this.hasPicked && this.hasWin(0);
|
const canTsumoLocal = this.hasPicked && this.hasWin(0) && (!this.enableYakus || this.handHasAnyYaku(this.hands[0], this.groups[0]));
|
||||||
let canRonLocal = false;
|
let canRonLocal = false;
|
||||||
if (this.lastDiscard !== undefined && this.lastDiscard !== 0) {
|
if (this.lastDiscard !== undefined && this.lastDiscard !== 0) {
|
||||||
if (this.canRonCache.lastDiscard === this.lastDiscard && this.canRonCache.handVer === this.handVersion[0]) {
|
if (this.canRonCache.lastDiscard === this.lastDiscard && this.canRonCache.handVer === this.handVersion[0]) {
|
||||||
|
|
@ -153,7 +153,9 @@ export class Game {
|
||||||
}
|
}
|
||||||
sim.push(new Tile(last.getFamily(), last.getValue(), last.isRed()));
|
sim.push(new Tile(last.getFamily(), last.getValue(), last.isRed()));
|
||||||
sim.sort();
|
sim.sort();
|
||||||
canRonLocal = sim.toGroup() !== undefined;
|
const simGroups = sim.toGroup() as Array<Group> | undefined;
|
||||||
|
const combinedGroups = this.groups[0].concat(simGroups ? simGroups : []);
|
||||||
|
canRonLocal = sim.toGroup() !== undefined && (!this.enableYakus || this.handHasAnyYaku(sim, combinedGroups));
|
||||||
} else {
|
} else {
|
||||||
canRonLocal = false;
|
canRonLocal = false;
|
||||||
}
|
}
|
||||||
|
|
@ -227,6 +229,27 @@ export class Game {
|
||||||
this.staticDirty = true;
|
this.staticDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether a given hand (possibly simulated) yields at least one yaku.
|
||||||
|
* Does not modify `lastYakus`/`lastTotalHan` — only inspects using yakus detectors.
|
||||||
|
*/
|
||||||
|
private handHasAnyYaku(hand: Hand, groups: Array<Group> = []): boolean {
|
||||||
|
try {
|
||||||
|
for (const k of Object.keys(yakus)) {
|
||||||
|
const fn = (yakus as any)[k];
|
||||||
|
try {
|
||||||
|
const han = fn(hand, groups, this.windPlayer);
|
||||||
|
if (han && han > 0) return true;
|
||||||
|
} catch (e) {
|
||||||
|
// ignore detector errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private initializeGame(): void {
|
private initializeGame(): void {
|
||||||
this.deck.shuffle();
|
this.deck.shuffle();
|
||||||
|
|
||||||
|
|
@ -350,7 +373,7 @@ export class Game {
|
||||||
public click(mp: MousePos): void {
|
public click(mp: MousePos): void {
|
||||||
const rect = this.cv.getBoundingClientRect();
|
const rect = this.cv.getBoundingClientRect();
|
||||||
|
|
||||||
if (this.hasWin(0)) {
|
if (this.hasWin(0) && (!this.enableYakus || this.handHasAnyYaku(this.hands[0], this.groups[0]))) {
|
||||||
this.resolveWin(0, 1);
|
this.resolveWin(0, 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -361,7 +384,7 @@ export class Game {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine if Ron/Tsumo should be available for player 0
|
// Determine if Ron/Tsumo should be available for player 0
|
||||||
const canTsumo = this.hasPicked && this.hasWin(0);
|
const canTsumo = this.hasPicked && this.hasWin(0) && (!this.enableYakus || this.handHasAnyYaku(this.hands[0], this.groups[0]));
|
||||||
let canRon = false;
|
let canRon = false;
|
||||||
if (this.lastDiscard !== undefined && this.lastDiscard !== 0) {
|
if (this.lastDiscard !== undefined && this.lastDiscard !== 0) {
|
||||||
const d = this.discards[this.lastDiscard];
|
const d = this.discards[this.lastDiscard];
|
||||||
|
|
@ -373,7 +396,9 @@ export class Game {
|
||||||
}
|
}
|
||||||
sim.push(new Tile(last.getFamily(), last.getValue(), last.isRed()));
|
sim.push(new Tile(last.getFamily(), last.getValue(), last.isRed()));
|
||||||
sim.sort();
|
sim.sort();
|
||||||
canRon = sim.toGroup() !== undefined;
|
const simGroups = sim.toGroup() as Array<Group> | undefined;
|
||||||
|
const combinedGroups = this.groups[0].concat(simGroups ? simGroups : []);
|
||||||
|
canRon = sim.toGroup() !== undefined && (!this.enableYakus || this.handHasAnyYaku(sim, combinedGroups));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -514,7 +539,7 @@ export class Game {
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleBotTurn(): void {
|
private handleBotTurn(): void {
|
||||||
if (this.hasWin(this.turn)) {
|
if (this.hasWin(this.turn) && (!this.enableYakus || this.handHasAnyYaku(this.hands[this.turn], this.groups[this.turn]))) {
|
||||||
this.resolveWin(this.turn, 2);
|
this.resolveWin(this.turn, 2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -567,7 +592,9 @@ export class Game {
|
||||||
}
|
}
|
||||||
sim.push(new Tile(last.getFamily(), last.getValue(), last.isRed()));
|
sim.push(new Tile(last.getFamily(), last.getValue(), last.isRed()));
|
||||||
sim.sort();
|
sim.sort();
|
||||||
if (sim.toGroup() !== undefined) return true;
|
const simGroups = sim.toGroup() as Array<Group> | undefined;
|
||||||
|
const combinedGroups = this.groups[p].concat(simGroups ? simGroups : []);
|
||||||
|
if (sim.toGroup() !== undefined && (!this.enableYakus || this.handHasAnyYaku(sim, combinedGroups))) return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -589,7 +616,7 @@ export class Game {
|
||||||
if (this.turn === 3) {
|
if (this.turn === 3) {
|
||||||
this.turn = 0;
|
this.turn = 0;
|
||||||
this.pick(0);
|
this.pick(0);
|
||||||
if (this.hasWin(0)) {
|
if (this.hasWin(0) && (!this.enableYakus || this.handHasAnyYaku(this.hands[0], this.groups[0]))) {
|
||||||
this.resolveWin(0, 1);
|
this.resolveWin(0, 1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -696,7 +723,7 @@ export class Game {
|
||||||
this.tenpaiCacheVersion[p] = -1;
|
this.tenpaiCacheVersion[p] = -1;
|
||||||
this.canRonCache = { result: false };
|
this.canRonCache = { result: false };
|
||||||
|
|
||||||
if (this.hasWin(p)) {
|
if (this.hasWin(p) && (!this.enableYakus || this.handHasAnyYaku(this.hands[p], this.groups[p]))) {
|
||||||
this.resolveWin(p, p === 0 ? 1 : 2);
|
this.resolveWin(p, p === 0 ? 1 : 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -865,7 +892,7 @@ export class Game {
|
||||||
this.tenpaiCacheVersion[thief] = -1;
|
this.tenpaiCacheVersion[thief] = -1;
|
||||||
this.canRonCache = { result: false };
|
this.canRonCache = { result: false };
|
||||||
|
|
||||||
if (this.hasWin(thief)) {
|
if (this.hasWin(thief) && (!this.enableYakus || this.handHasAnyYaku(this.hands[thief], this.groups[thief]))) {
|
||||||
this.resolveWin(thief, thief === 0 ? 1 : 2);
|
this.resolveWin(thief, thief === 0 ? 1 : 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -903,7 +930,7 @@ export class Game {
|
||||||
drawChiis(this.staticCtx, this.getChii(0));
|
drawChiis(this.staticCtx, this.getChii(0));
|
||||||
} else {
|
} else {
|
||||||
// Compute availability of ron/tsumo for player 0
|
// Compute availability of ron/tsumo for player 0
|
||||||
const canTsumoLocal = this.hasPicked && this.hasWin(0);
|
const canTsumoLocal = this.hasPicked && this.hasWin(0) && (!this.enableYakus || this.handHasAnyYaku(this.hands[0], this.groups[0]));
|
||||||
let canRonLocal = false;
|
let canRonLocal = false;
|
||||||
if (this.lastDiscard !== undefined && this.lastDiscard !== 0) {
|
if (this.lastDiscard !== undefined && this.lastDiscard !== 0) {
|
||||||
// Use cache when lastDiscard and player's hand version are unchanged
|
// Use cache when lastDiscard and player's hand version are unchanged
|
||||||
|
|
@ -919,7 +946,9 @@ export class Game {
|
||||||
}
|
}
|
||||||
sim.push(new Tile(last.getFamily(), last.getValue(), last.isRed()));
|
sim.push(new Tile(last.getFamily(), last.getValue(), last.isRed()));
|
||||||
sim.sort();
|
sim.sort();
|
||||||
canRonLocal = sim.toGroup() !== undefined;
|
const simGroups = sim.toGroup() as Array<Group> | undefined;
|
||||||
|
const combinedGroups = this.groups[0].concat(simGroups ? simGroups : []);
|
||||||
|
canRonLocal = sim.toGroup() !== undefined && (!this.enableYakus || this.handHasAnyYaku(sim, combinedGroups));
|
||||||
} else {
|
} else {
|
||||||
canRonLocal = false;
|
canRonLocal = false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue