// 3a --> {x:3, y:10}
static SquareToCoords(sq) {
- return ArrayFun.toObject(["x", "y"],
- [0, 1].map(i => parseInt(sq[i], 36)));
+ const [x, y] = [0, 1].map(i => parseInt(sq[i], 36));
+ return { x, y };
}
// {x:11, y:12} --> bc
const counts = reserveStr.split("").map(c => parseInt(c, 36));
const L = V.ReserveArray.length;
this.reserve = {
- w: ArrayFun.toObject(V.ReserveArray, counts.slice(0, L)),
- b: ArrayFun.toObject(V.ReserveArray, counts.slice(L, 2 * L))
+ w: Object.fromEntries(V.ReserveArray.map((k, i) => [k, counts[i]])),
+ b: Object.fromEntries(V.ReserveArray.map((k, i) => [k, counts[L + i]]))
};
}
initIspawn(ispawnStr) {
- if (ispawnStr != "-")
- this.ispawn = ArrayFun.toObject(ispawnStr.split(","), true);
+ if (ispawnStr != "-") {
+ this.ispawn =
+ Object.fromEntries(ispawnStr.split(",").map(k => [k, true]));
+ }
else
this.ispawn = {};
}
const piece = this.getPieceType(x, y);
let moves = this.getPotentialMovesOf(piece, [x, y]);
if (this.hasEnpassant && !!this.epSquare_s) {
- moves = [...moves, this.getEnpassantCaptures(piece, [x, y])];
+ Array.prototype.push.apply(moves,
+ this.getEnpassantCaptures(piece, [x, y]));
+ }
if (this.isKing(0, 0, piece) && this.hasCastle)
Array.prototype.push.apply(moves, this.getCastleMoves([x, y]));
if (!noPP)
return [];
const color = this.getColor(moves[0].start.x, moves[0].start.y);
const oppCols = this.getOppCols(color);
-
if (this.options["capture"] && this.atLeastOneCapture(color))
moves = this.capturePostProcess(moves, oppCols);
-
if (this.options["atomic"])
moves = this.atomicPostProcess(moves, color, oppCols);
-
if (
moves.length > 0 &&
this.getPieceType(moves[0].start.x, moves[0].start.y) == "p"
) {
moves = this.pawnPostProcess(moves, color, oppCols);
}
-
if (this.options["cannibal"] && this.options["rifle"])
// In this case a rifle-capture from last rank may promote a pawn
moves = this.riflePromotePostProcess(moves, color);
-
return moves;
}
// Extract potential en-passant square from just played move
setEpSquare_s(move) {
- this.epSquare = undefined;
+ this.epSquare_s = undefined;
const s = move.start,
e = move.end;
const gap = Math.abs(e.x - s.x);
)
) {
const step = (e.x - s.x) / gap;
- this.epSquare = {
- x: (s.x + e.x) / 2,
- y: s.y
- };
+ this.epSquare_s = [
+ {
+ x: (s.x + e.x) / 2,
+ y: s.y
+ },
+ e //add endpoint (to know where captured piece is)
+ ];
}
}
- // Special case of en-passant captures: treated separately
+ // Special case of (pawn) en-passant captures: treated separately
getEnpassantCaptures(piece, [x, y]) {
- if (piece != 'p')
+ if (piece != 'p' || !this.epSquare_s)
return [];
const color = this.getColor(x, y);
- const shiftX = (color == 'w' ? -1 : 1);
- const oppCols = this.getOppCols(color);
- if (
- this.epSquare &&
- this.epSquare.x == x + shiftX && //NOTE: epSquare.x not on edge
- Math.abs(this.getY(this.epSquare.y - y)) == 1 &&
- // Doublemove (and Progressive?) guards:
- this.board[this.epSquare.x][this.epSquare.y] == "" &&
- oppCols.includes(this.getColor(x, this.epSquare.y))
- ) {
- const [epx, epy] = [this.epSquare.x, this.epSquare.y];
- this.board[epx][epy] = this.board[x][this.epSquare.y];
- let enpassantMove = this.getBasicMove([x, y], [epx, epy]);
- this.board[epx][epy] = "";
- const lastIdx = enpassantMove.vanish.length - 1; //think Rifle
- enpassantMove.vanish[lastIdx].x = x;
- return [enpassantMove];
- }
- return [];
+ const shiftX = (color == 'w' ? -1 : 1),
+ oppCols = this.getOppCols(color);
+ const L = this.epSquare_s.length;
+ const captSq = this.epSquare_s[L-1];
+ let res = [];
+ for (let i = 0; i < L-1; i++) {
+ const sq = this.epSquare_s[i];
+ if (
+ sq.x == x + shiftX && //NOTE: epSquare.x not on edge
+ Math.abs(this.getY(sq.y - y)) == 1 &&
+ // Doublemove (and Progressive?) guards:
+ this.board[sq.x][sq.y] == "" &&
+ oppCols.includes(this.getColor(captSq.x, captSq.y))
+ ) {
+ this.board[sq.x][sq.y] = this.board[captSq.x][captSq.y];
+ let enpassantMove = this.getBasicMove([x, y], [sq.x, sq.y]);
+ this.board[sq.x][sq.y] = "";
+ const lastIdx = enpassantMove.vanish.length - 1; //think Rifle
+ enpassantMove.vanish[lastIdx].x = captSq.x;
+ enpassantMove.vanish[lastIdx].y = captSq.y; //in case of (Enpassant..)
+ res.push(enpassantMove);
+ }
+ }
+ return res;
}
getCastleMoves([x, y], finalSquares, castleWith, castleFlags) {
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+ Vágtató (fekete)
+ Készült: a knight-b.svg felhasználásával
+ Felhasználási feltételek: Nevezd meg! - Így add tovább! (Creative Commons)
+ Uray M. János
+ 2013-2018
+-->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="128" height="128" viewBox="0 0 45 45">
+ <!-- alap -->
+ <g fill="#000" stroke="#000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
+ <!-- test -->
+ <path d="M 21.5,10 C 32.5,11 38.5,18 38,39 L 15,39 C 15,30 25,32.5 23,18"/>
+ <!-- fej -->
+ <path d="M 24,18 C 24.38,20.91 18.45,25.37 16,27 C 13,29 13.18,31.34 11,31 C 9.958,30.06 12.41,27.96 11,28 C 10,28 11.19,29.23 10,30 C 9,30 5.997,31 6,26 C 6,24 12,14 12,14 C 12,14 13.89,12.1 14,10.5 C 13.5,9.5 13.5,8.0 11.5,5.5 C 13.0,4.5 16.5,10 16.5,10 L 18.5,10 C 19.0,8 19.5,6 19.0,4.5 C 20.5,4.0 21.0,7 21.5,10"/>
+ </g>
+ <!-- sebességvonalak -->
+ <defs>
+ <linearGradient id="speed-grad" x1="0%" y1="0%" x2="100%" y2="0%" spreadMethod="pad">
+ <stop offset="30%" stop-color="#000" stop-opacity="0.6"/>
+ <stop offset="100%" stop-color="#000" stop-opacity="0"/>
+ </linearGradient>
+ </defs>
+ <g>
+ <rect fill="url(#speed-grad)" x="30.0" y="12" width="7.5" height="2"/>
+ <rect fill="url(#speed-grad)" x="34.0" y="16" width="6.5" height="2"/>
+ <rect fill="url(#speed-grad)" x="36.0" y="20" width="6.0" height="2"/>
+ <rect fill="url(#speed-grad)" x="37.0" y="25" width="5.5" height="2"/>
+ <rect fill="url(#speed-grad)" x="38.0" y="30" width="5.0" height="2"/>
+ <rect fill="url(#speed-grad)" x="38.0" y="35" width="5.0" height="2"/>
+ </g>
+ <!-- vonalak -->
+ <g fill="#FFF" stroke="#FFF" stroke-width="1.5" stroke-linejoin="round">
+ <!-- szemkötő -->
+ <path stroke="none" d="M 12.8,13 C 11.8,14 10.0,17 9.1,19 L 33,16 L 27,11 Z"/>
+ <!-- hát -->
+ <path stroke="none" d="M 24.55,10.4 L 24.1,11.85 L 24.6,12 C 27.75,13 30.25,14.49 32.5,18.75 C 34.75,23.01 35.75,29.06 35.25,39 L 35.2,39.5 L 37.45,39.5 L 37.5,39 C 38,28.94 36.62,22.15 34.25,17.66 C 31.88,13.17 28.46,11.02 25.06,10.5 L 24.55,10.4 Z"/>
+ <!-- orr -->
+ <path d="M 9.5 25.5 A 0.5,0.5,0 1,1 8.5,25.5 A 0.5,0.5,0 1,1 9.5,25.5 Z"/>
+ </g>
+ <!-- szem -->
+ <g fill="#000" stroke="#000" stroke-width="1.5" stroke-linejoin="round">
+ <path d="M 15.8,14.75 A 0.5,1.5,60 1,1 13.2,16.25 A 0.5,1.5,60 1,1 15.8,14.75 Z"/>
+ </g>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+ Vágtató (fehér)
+ Készült: a knight-w.svg felhasználásával
+ Felhasználási feltételek: Nevezd meg! - Így add tovább! (Creative Commons)
+ Uray M. János
+ 2013-2018
+-->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="128" height="128" viewBox="0 0 45 45">
+ <!-- alap -->
+ <g fill="#FFF" stroke="#000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
+ <!-- test -->
+ <path d="M 21.5,10 C 32.5,11 38.5,18 38,39 L 15,39 C 15,30 25,32.5 23,18"/>
+ <!-- fej -->
+ <path d="M 24,18 C 24.38,20.91 18.45,25.37 16,27 C 13,29 13.18,31.34 11,31 C 9.958,30.06 12.41,27.96 11,28 C 10,28 11.19,29.23 10,30 C 9,30 5.997,31 6,26 C 6,24 12,14 12,14 C 12,14 13.89,12.1 14,10.5 C 13.5,9.5 13.5,8.0 11.5,5.5 C 13.0,4.5 16.5,10 16.5,10 L 18.5,10 C 19.0,8 19.5,6 19.0,4.5 C 20.5,4.0 21.0,7 21.5,10"/>
+ </g>
+ <path fill="#000" d="M 13,13 L 9,19 L 34,16 L 28,11 Z"/>
+ <!-- orr -->
+ <g fill="#000" stroke="#000" stroke-width="1.5" stroke-linejoin="round">
+ <path d="M 9.5 25.5 A 0.5,0.5,0 1,1 8.5,25.5 A 0.5,0.5,0 1,1 9.5,25.5 Z"/>
+ </g>
+ <!-- szem -->
+ <g fill="#FFF" stroke="#FFF" stroke-width="1.5" stroke-linejoin="round">
+ <path d="M 15.8,14.75 A 0.5,1.5,60 1,1 13.2,16.25 A 0.5,1.5,60 1,1 15.8,14.75 Z"/>
+ </g>
+ <!-- sebességvonalak -->
+ <defs>
+ <linearGradient id="speed-grad" x1="0%" y1="0%" x2="100%" y2="0%" spreadMethod="pad">
+ <stop offset="30%" stop-color="#000" stop-opacity="0.6"/>
+ <stop offset="100%" stop-color="#000" stop-opacity="0"/>
+ </linearGradient>
+ </defs>
+ <g>
+ <rect fill="url(#speed-grad)" x="30.0" y="12" width="7.5" height="2"/>
+ <rect fill="url(#speed-grad)" x="34.0" y="16" width="6.5" height="2"/>
+ <rect fill="url(#speed-grad)" x="36.0" y="20" width="6.0" height="2"/>
+ <rect fill="url(#speed-grad)" x="37.0" y="25" width="5.5" height="2"/>
+ <rect fill="url(#speed-grad)" x="38.0" y="30" width="5.0" height="2"/>
+ <rect fill="url(#speed-grad)" x="38.0" y="35" width="5.0" height="2"/>
+ </g>
+</svg>
import ChessRules from "/js/base_rules.js";
+import PiPo from "/utils/PiPo.js";
export default class EnpassantRules extends ChessRules {
pieceDef(piece, color, x, y) {
let res = super.pieceDef(piece, color, x, y);
- if (piece == 'n')
+ if (piece == 'n') {
+ res["class"] = "nightrider";
res.both[0].range = 8; //"infinite"
+ }
return res;
}
- // TODO: comma separated (convention ?! yes..)
- readEpSquare_s(squares) {
- if (squares == "-")
- return undefined;
- // Expand init + dest squares into a full path:
- const init = C.SquareToCoords(square.substr(0, 2));
- let newPath = [init];
- if (square.length == 2)
- return newPath;
- const dest = C.SquareToCoords(square.substr(2));
- const delta = ['x', 'y'].map(i => Math.abs(dest[i] - init[i]));
- // Check if it's a knight(rider) movement:
- let step = [0, 0];
- if (delta[0] > 0 && delta[1] > 0 && delta[0] != delta[1]) {
- // Knightrider
- const minShift = Math.min(delta[0], delta[1]);
- step[0] = (dest.x - init.x) / minShift;
- step[1] = (dest.y - init.y) / minShift;
- }
- else {
- // "Sliders"
- step = ['x', 'y'].map((i, idx) => {
- return (dest[i] - init[i]) / delta[idx] || 0
- });
- }
- let x = init.x + step[0],
- y = init.y + step[1];
- while (x != dest.x || y != dest.y) {
- newPath.push({ x: x, y: y });
- x += step[0];
- y += step[1];
- }
- newPath.push(dest);
- return newPath;
- }
-
setEpSquare_s(move) {
- // Argument is a move: all intermediate squares are en-passant candidates,
+ // All intermediate squares are en-passant candidates,
// except if the moving piece is a king.
- const move = moveOrSquare;
const piece = move.appear[0].p;
- if (piece == V.KING ||
+ if (piece == 'k' ||
(
- Math.abs(move.end.x-move.start.x) <= 1 &&
- Math.abs(move.end.y-move.start.y) <= 1
+ Math.abs(move.end.x - move.start.x) <= 1 &&
+ Math.abs(move.end.y - move.start.y) <= 1
)
) {
- return undefined;
+ this.epSquare_s = undefined;
}
- const delta = [move.end.x-move.start.x, move.end.y-move.start.y];
- let step = undefined;
- if (piece == V.KNIGHT) {
- const divisor = Math.min(Math.abs(delta[0]), Math.abs(delta[1]));
- step = [delta[0]/divisor || 0, delta[1]/divisor || 0];
- } else {
- step = [
- delta[0]/Math.abs(delta[0]) || 0,
- delta[1]/Math.abs(delta[1]) || 0
- ];
- }
- let res = [];
- for (
- let [x,y] = [move.start.x+step[0],move.start.y+step[1]];
- x != move.end.x || y != move.end.y;
- x += step[0], y += step[1]
- ) {
- res.push({ x: x, y: y });
+ else {
+ const delta = [move.end.x-move.start.x, move.end.y-move.start.y];
+ const divisor = [Math.abs(delta[0]), Math.abs(delta[1])].sort();
+ const idx = (divisor[0] > 0 ? 0 : 1);
+ const step = [delta[0]/divisor[idx], delta[1]/divisor[idx]];
+ this.epSquare_s = [];
+ for (
+ let [x,y] = [move.start.x + step[0], move.start.y + step[1]];
+ x != move.end.x || y != move.end.y;
+ x += step[0], y += step[1]
+ ) {
+ this.epSquare_s.push({ x: x, y: y });
+ }
+ // Add final square to know which piece is taken en passant:
+ this.epSquare_s.push(move.end);
}
- // Add final square to know which piece is taken en passant:
- res.push(move.end);
- return res;
- }
-
- getEnpassantFen() {
- const L = this.epSquares.length;
- if (!this.epSquares[L - 1]) return "-"; //no en-passant
- const epsq = this.epSquares[L - 1];
- if (epsq.length <= 2) return epsq.map(V.CoordsToSquare).join("");
- // Condensate path: just need initial and final squares:
- return V.CoordsToSquare(epsq[0]) + V.CoordsToSquare(epsq[epsq.length - 1]);
}
getPotentialMovesFrom([x, y]) {
let moves = super.getPotentialMovesFrom([x,y]);
- // Add en-passant captures from this square:
- const L = this.epSquares.length;
- if (!this.epSquares[L - 1]) return moves;
- const squares = this.epSquares[L - 1];
- const S = squares.length;
- // Object describing the removed opponent's piece:
- const pipoV = new PiPo({
- x: squares[S-1].x,
- y: squares[S-1].y,
- c: V.GetOppCol(this.turn),
- p: this.getPiece(squares[S-1].x, squares[S-1].y)
- });
- // Check if existing non-capturing moves could also capture en passant
- moves.forEach(m => {
- if (
- m.appear[0].p != V.PAWN && //special pawn case is handled elsewhere
- m.vanish.length <= 1 &&
- [...Array(S-1).keys()].some(i => {
- return m.end.x == squares[i].x && m.end.y == squares[i].y;
- })
- ) {
- m.vanish.push(pipoV);
- }
- });
// Special case of the king knight's movement:
- if (this.getPiece(x, y) == V.KING) {
- V.steps[V.KNIGHT].forEach(step => {
- const endX = x + step[0];
- const endY = y + step[1];
- if (
- V.OnBoard(endX, endY) &&
- [...Array(S-1).keys()].some(i => {
- return endX == squares[i].x && endY == squares[i].y;
- })
- ) {
- let enpassantMove = this.getBasicMove([x, y], [endX, endY]);
- enpassantMove.vanish.push(pipoV);
- moves.push(enpassantMove);
- }
- });
- }
- return moves;
- }
-
- getEnpassantCaptures([x, y], shiftX) {
- const Lep = this.epSquares.length;
- const squares = this.epSquares[Lep - 1];
- let moves = [];
- if (!!squares) {
- const S = squares.length;
- const taken = squares[S-1];
+ if (!!this.epSquare_s) {
+ const L = this.epSquare_s.length;
const pipoV = new PiPo({
- x: taken.x,
- y: taken.y,
- p: this.getPiece(taken.x, taken.y),
- c: this.getColor(taken.x, taken.y)
+ x: this.epSquare_s[L-1].x,
+ y: this.epSquare_s[L-1].y,
+ c: C.GetOppTurn(this.turn),
+ p: this.getPiece(this.epSquare_s[L-1].x, this.epSquare_s[L-1].y)
});
- [...Array(S-1).keys()].forEach(i => {
- const sq = squares[i];
- if (sq.x == x + shiftX && Math.abs(sq.y - y) == 1) {
- let enpassantMove = this.getBasicMove([x, y], [sq.x, sq.y]);
- enpassantMove.vanish.push(pipoV);
- moves.push(enpassantMove);
+ // Check if existing non-capturing moves could also capture en passant
+ moves.forEach(m => {
+ if (
+ m.appear[0].p != 'p' && //special pawn case is handled elsewhere
+ m.vanish.length <= 1 &&
+ this.epSquare_s.some(sq => m.end.x == sq.x && m.end.y == sq.y)
+ ) {
+ m.vanish.push(pipoV);
}
});
+ if (this.getPiece(x, y) == 'k') {
+ super.pieceDef('n').both[0].steps.forEach(step => {
+ const [endX, endY] = [x + step[0], y + step[1]];
+ if (
+ this.onBoard(endX, endY) &&
+ this.epSquare_s.some(sq => endX == sq.x && endY == sq.y)
+ ) {
+ let enpassantMove = this.getBasicMove([x, y], [endX, endY]);
+ enpassantMove.vanish.push(pipoV);
+ moves.push(enpassantMove);
+ }
+ });
+ }
}
return moves;
}
<p>
All pieces can be captured "en passant" when they make more than one step.
- So, for more fun, knights can make multi-steps: they turn into knightriders.
+ So, for more fun, knights can make multi-steps: they turn into (k)nightriders.
</p>
<p>
1.e4 d5 2.Qh5 Bxg4 would take the queen en passant.
</p>
+<p>Note: the king has the extra ability to capture en-passant like a knight.</p>
+
<p class="author">Andy Kurnia (1998).</p>
<p>
@import url("/css/base_pieces.css");
+
+piece.white.nightrider {
+ background-image: url('/pieces/white_nightrider.svg');
+}
+piece.black.nightrider {
+ background-image: url('/pieces/black_nightrider.svg');
+}
-import { ChessRules } from "@/js/base_rules";
+import ChessRules from "/js/base_rules.js";
-export class EvolutionRules extends ChessRules {
+export default class EvolutionRules extends ChessRules {
+
+// static get Options() {
+// return C.Options;
+// }
getPotentialMovesFrom([x, y]) {
let moves = super.getPotentialMovesFrom([x, y]);
const c = this.getColor(x, y);
const piece = this.getPiece(x, y);
if (
- [V.BISHOP, V.ROOK, V.QUEEN].includes(piece) &&
+ ['b', 'r', 'q'].includes(piece) &&
(c == 'w' && x == 7) || (c == 'b' && x == 0)
) {
// Move from first rank
const forward = (c == 'w' ? -1 : 1);
for (let shift of [-2, 0, 2]) {
- if (
- (piece == V.ROOK && shift != 0) ||
- (piece == V.BISHOP && shift == 0)
- ) {
+ if ((piece == 'r' && shift != 0) || (piece == 'b' && shift == 0))
continue;
- }
if (
- V.OnBoard(x+2*forward, y+shift) &&
- this.board[x+forward][y+shift/2] != V.EMPTY &&
+ this.onBoard(x+2*forward, y+shift) &&
+ this.board[x+forward][y+shift/2] != "" &&
this.getColor(x+2*forward, y+shift) != c
) {
moves.push(this.getBasicMove([x,y], [x+2*forward,y+shift]));
--- /dev/null
+<p>Long-range pieces can jump over an obstacle when they are on the first rank.</p>
+
+<p>
+ From the first rank, rook, bishops and queen can play directly on the third
+ rank, even if an obstacle stands in-between. Development is thus accelerated.
+ This also help for defense.
+</p>
+
+<p class="author">Zied Haddad (2020).</p>
--- /dev/null
+@import url("/css/base_pieces.css");
-import { ChessRules } from "@/js/base_rules";
+import ChessRules from "/js/base_rules.js";
-export class ExtinctionRules extends ChessRules {
+export default class ExtinctionRules extends ChessRules {
- static get PawnSpecs() {
- return Object.assign(
- {},
- ChessRules.PawnSpecs,
- { promotions: ChessRules.PawnSpecs.promotions.concat([V.KING]) }
- );
- }
+// static get Options() {
+// return C.Options;
+// }
- static IsGoodPosition(position) {
- if (!ChessRules.IsGoodPosition(position)) return false;
- // Also check that each piece type is present
- const rows = position.split("/");
- let pieces = {};
- for (let row of rows) {
- for (let i = 0; i < row.length; i++) {
- if (isNaN(parseInt(row[i], 10)) && !pieces[row[i]])
- pieces[row[i]] = true;
- }
- }
- if (Object.keys(pieces).length != 12) return false;
- return true;
- }
-
- setOtherVariables(fen) {
- super.setOtherVariables(fen);
- const pos = V.ParseFen(fen).position;
- // NOTE: no need for safety "|| []", because each piece type is present
- // (otherwise game is already over!)
- this.material = {
- w: {
- [V.KING]: pos.match(/K/g).length,
- [V.QUEEN]: pos.match(/Q/g).length,
- [V.ROOK]: pos.match(/R/g).length,
- [V.KNIGHT]: pos.match(/N/g).length,
- [V.BISHOP]: pos.match(/B/g).length,
- [V.PAWN]: pos.match(/P/g).length
- },
- b: {
- [V.KING]: pos.match(/k/g).length,
- [V.QUEEN]: pos.match(/q/g).length,
- [V.ROOK]: pos.match(/r/g).length,
- [V.KNIGHT]: pos.match(/n/g).length,
- [V.BISHOP]: pos.match(/b/g).length,
- [V.PAWN]: pos.match(/p/g).length
- }
- };
- }
-
- // TODO: verify this assertion
- atLeastOneMove() {
- return true; //always at least one possible move
+ pawnPromotions() {
+ return super.pawnPromotions().concat('k');
}
filterValid(moves) {
return moves; //there is no check
}
- getCheckSquares() {
- return [];
- }
-
- postPlay(move) {
- super.postPlay(move);
- // Treat the promotion case: (not the capture part)
- if (move.appear[0].p != move.vanish[0].p) {
- this.material[move.appear[0].c][move.appear[0].p]++;
- this.material[move.appear[0].c][V.PAWN]--;
- }
- if (move.vanish.length == 2 && move.appear.length == 1)
- //capture
- this.material[move.vanish[1].c][move.vanish[1].p]--;
- }
-
- postUndo(move) {
- super.postUndo(move);
- if (move.appear[0].p != move.vanish[0].p) {
- this.material[move.appear[0].c][move.appear[0].p]--;
- this.material[move.appear[0].c][V.PAWN]++;
- }
- if (move.vanish.length == 2 && move.appear.length == 1)
- this.material[move.vanish[1].c][move.vanish[1].p]++;
- }
-
getCurrentScore() {
- if (this.atLeastOneMove()) {
- // Game not over?
- const color = this.turn;
- if (
- Object.keys(this.material[color]).some(p => {
- return this.material[color][p] == 0;
- })
- ) {
- return this.turn == "w" ? "0-1" : "1-0";
- }
- return "*";
- }
- return this.turn == "w" ? "0-1" : "1-0"; //NOTE: currently unreachable...
- }
-
- evalPosition() {
const color = this.turn;
- if (
- Object.keys(this.material[color]).some(p => {
- return this.material[color][p] == 0;
- })
- ) {
- // Very negative (resp. positive)
- // if white (reps. black) pieces set is incomplete
- return (color == "w" ? -1 : 1) * V.INFINITY;
+ let material = { 'w': {}, 'b': {} };
+ this.board.flat().forEach(cell => {
+ if (cell != "")
+ material[cell.charAt(0)][cell.charAt(1)] = true;
+ });
+ for (const c of ['w', 'b']) {
+ if (Object.keys(material[c]).length < 6)
+ return c == 'w' ? "0-1" : "1-0";
}
- return super.evalPosition();
+ return "*";
}
};
--- /dev/null
+<p>Losing all pieces of some kind means losing the game.</p>
+
+<p>
+ There are no checks: kings can be captured too
+ (and pawns can promote into kings).
+</p>
+
+<p class="author">R. Wayne Schmittberger (1985).</p>
--- /dev/null
+@import url("/css/base_pieces.css");