shogiops
Version:
Shogi rules and operations
94 lines • 3.56 kB
JavaScript
import { attacks, goldAttacks, kingAttacks, pawnAttacks } from '../attacks.js';
import { SquareSet } from '../square-set.js';
import { defined, opposite } from '../util.js';
import { Position } from './position.js';
import { fullSquareSet, promotionZone } from './util.js';
export class Dobutsu extends Position {
constructor() {
super('dobutsu');
this.validation = {
doublePawn: false,
oppositeCheck: false,
unpromotedForcedPromotion: false,
maxNumberOfRoyalPieces: 1,
};
}
static from(setup, strict) {
const pos = new Dobutsu();
pos.fromSetup(setup);
return pos.validate(strict).map((_) => pos);
}
squareAttackers(square, attacker, _occupied) {
const defender = opposite(attacker);
const board = this.board;
return board.color(attacker).intersect(limitedAttacks({ role: 'rook', color: attacker }, square)
.intersect(board.roles('rook'))
.union(limitedAttacks({ role: 'bishop', color: attacker }, square).intersect(board.roles('bishop')))
.union(goldAttacks(square, defender).intersect(board.roles('tokin')))
.union(pawnAttacks(square, defender).intersect(board.role('pawn')))
.union(kingAttacks(square).intersect(board.roles('king'))));
}
squareSnipers(_square, _attacker) {
return SquareSet.empty();
}
moveDests(square, ctx) {
ctx = ctx || this.ctx();
const piece = this.board.get(square);
if (!piece || piece.color !== ctx.color)
return SquareSet.empty();
let pseudo = limitedAttacks(piece, square).intersect(fullSquareSet(this.rules));
pseudo = pseudo.diff(this.board.color(ctx.color));
return pseudo.intersect(fullSquareSet(this.rules));
}
dropDests(piece, ctx) {
ctx = ctx || this.ctx();
if (piece.color !== ctx.color)
return SquareSet.empty();
return this.board.occupied.complement().intersect(fullSquareSet(this.rules));
}
outcome(ctx) {
ctx = ctx || this.ctx();
if (this.kingsOf(ctx.color).isEmpty()) {
return {
result: 'kingsLost',
winner: opposite(ctx.color),
};
}
const isTryRule = (color) => {
const king = this.kingsOf(color).singleSquare();
return defined(king) && promotionZone(this.rules)(color).has(king) && !this.isCheck(color);
};
const senteTryRule = isTryRule('sente');
const goteTryRule = isTryRule('gote');
if (senteTryRule && !goteTryRule) {
return {
result: 'tryRule',
winner: 'sente',
};
}
else if (goteTryRule && !senteTryRule) {
return {
result: 'tryRule',
winner: 'gote',
};
}
else if (!this.hasDests()) {
return {
result: 'stalemate',
winner: opposite(ctx.color),
};
}
return undefined;
}
}
function limitedAttacks(piece, square) {
switch (piece.role) {
case 'bishop':
return kingAttacks(square).withoutMany(square - 16, square + 16, square - 1, square + 1);
case 'rook':
return kingAttacks(square).withoutMany(square - 15, square - 17, square + 15, square + 17);
default:
return attacks(piece, square, SquareSet.empty());
}
}
//# sourceMappingURL=dobutsu.js.map