- // Artifically change turn, for checkered pawns
- this.turn = V.GetOppCol(this.turn);
- const res = this.isAttacked(this.kingPos[color], [V.GetOppCol(color),'c'])
- ? (color == "w" ? "0-1" : "1-0")
- : "1/2";
- this.turn = V.GetOppCol(this.turn);
- return res;
- }
-
- evalPosition()
- {
- let evaluation = 0;
- //Just count material for now, considering checkered neutral (...)
- for (let i=0; i<V.size.x; i++)
- {
- for (let j=0; j<V.size.y; j++)
- {
- if (this.board[i][j] != V.EMPTY)
- {
- const sqColor = this.getColor(i,j);
- const sign = sqColor == "w" ? 1 : (sqColor=="b" ? -1 : 0);
- evaluation += sign * V.VALUES[this.getPiece(i,j)];
- }
- }
- }
- return evaluation;
- }
-
- static GenRandInitFen()
- {
- const randFen = ChessRules.GenRandInitFen();
- // Add 16 pawns flags + empty cmove:
- return randFen.replace(" w 0 1111", " w 0 11111111111111111111 -");
- }
-
- static ParseFen(fen)
- {
- const fenParsed = ChessRules.ParseFen(fen);
- return Object.assign({},
- ChessRules.ParseFen(fen),
- {cmove: fen.split(" ")[5]});
- }
-
- getFen()
- {
+ const L = this.cmoves.length; //at least 1: init from FEN
+ return moves.filter(m => {
+ if (this.oppositeMoves(this.cmoves[L - 1], m)) return false;
+ this.play(m);
+ const res = !this.underCheck(color);
+ this.undo(m);
+ return res;
+ });
+ }
+
+ getAllValidMoves() {
+ const oppCol = V.GetOppCol(this.turn);
+ let potentialMoves = [];
+ for (let i = 0; i < V.size.x; i++) {
+ for (let j = 0; j < V.size.y; j++) {
+ // NOTE: just testing == color isn't enough because of checkred pieces
+ if (this.board[i][j] != V.EMPTY && this.getColor(i, j) != oppCol) {
+ Array.prototype.push.apply(
+ potentialMoves,
+ this.getPotentialMovesFrom([i, j])
+ );
+ }
+ }
+ }
+ return this.filterValid(potentialMoves);
+ }
+
+ atLeastOneMove() {
+ const oppCol = V.GetOppCol(this.turn);
+ for (let i = 0; i < V.size.x; i++) {
+ for (let j = 0; j < V.size.y; j++) {
+ // NOTE: just testing == color isn't enough because of checkered pieces
+ if (this.board[i][j] != V.EMPTY && this.getColor(i, j) != oppCol) {
+ const moves = this.getPotentialMovesFrom([i, j]);
+ if (moves.length > 0) {
+ for (let k = 0; k < moves.length; k++) {
+ if (this.filterValid([moves[k]]).length > 0) return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ // colors: array, generally 'w' and 'c' or 'b' and 'c'
+ isAttacked(sq, colors) {
+ if (!Array.isArray(colors)) colors = [colors];
+ return (
+ this.isAttackedByPawn(sq, colors) ||
+ this.isAttackedByRook(sq, colors) ||
+ this.isAttackedByKnight(sq, colors) ||
+ this.isAttackedByBishop(sq, colors) ||
+ this.isAttackedByQueen(sq, colors) ||
+ this.isAttackedByKing(sq, colors)
+ );
+ }
+
+ isAttackedByPawn([x, y], colors) {
+ for (let c of colors) {
+ const color = (c == "c" ? this.turn : c);
+ let pawnShift = color == "w" ? 1 : -1;
+ if (x + pawnShift >= 0 && x + pawnShift < 8) {
+ for (let i of [-1, 1]) {
+ if (
+ y + i >= 0 &&
+ y + i < 8 &&
+ this.getPiece(x + pawnShift, y + i) == V.PAWN &&
+ this.getColor(x + pawnShift, y + i) == c
+ ) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ isAttackedBySlideNJump([x, y], colors, piece, steps, oneStep) {
+ for (let step of steps) {
+ let rx = x + step[0],
+ ry = y + step[1];
+ while (V.OnBoard(rx, ry) && this.board[rx][ry] == V.EMPTY && !oneStep) {
+ rx += step[0];
+ ry += step[1];
+ }
+ if (
+ V.OnBoard(rx, ry) &&
+ this.getPiece(rx, ry) === piece &&
+ colors.includes(this.getColor(rx, ry))
+ ) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ isAttackedByRook(sq, colors) {
+ return this.isAttackedBySlideNJump(sq, colors, V.ROOK, V.steps[V.ROOK]);
+ }
+
+ isAttackedByKnight(sq, colors) {
+ return this.isAttackedBySlideNJump(
+ sq,
+ colors,
+ V.KNIGHT,
+ V.steps[V.KNIGHT],
+ "oneStep"
+ );
+ }
+
+ isAttackedByBishop(sq, colors) {
+ return this.isAttackedBySlideNJump(sq, colors, V.BISHOP, V.steps[V.BISHOP]);
+ }
+
+ isAttackedByQueen(sq, colors) {
+ return this.isAttackedBySlideNJump(
+ sq,
+ colors,
+ V.QUEEN,
+ V.steps[V.ROOK].concat(V.steps[V.BISHOP])
+ );
+ }
+
+ isAttackedByKing(sq, colors) {
+ return this.isAttackedBySlideNJump(
+ sq,
+ colors,
+ V.KING,
+ V.steps[V.ROOK].concat(V.steps[V.BISHOP]),
+ "oneStep"
+ );
+ }
+
+ underCheck(color) {
+ return this.isAttacked(this.kingPos[color], [V.GetOppCol(color), "c"]);
+ }
+
+ getCheckSquares(color) {
+ // Artifically change turn, for checkered pawns
+ this.turn = V.GetOppCol(color);
+ const kingAttacked = this.isAttacked(this.kingPos[color], [
+ V.GetOppCol(color),
+ "c"
+ ]);
+ let res = kingAttacked
+ ? [JSON.parse(JSON.stringify(this.kingPos[color]))] //need to duplicate!
+ : [];
+ this.turn = color;
+ return res;
+ }
+
+ postPlay(move) {
+ super.postPlay(move);
+ // Does this move turn off a 2-squares pawn flag?
+ if ([1, 6].includes(move.start.x) && move.vanish[0].p == V.PAWN)
+ this.pawnFlags[move.start.x == 6 ? "w" : "b"][move.start.y] = false;
+ this.cmoves.push(this.getCmove(move));
+ }
+
+ postUndo(move) {
+ super.postUndo(move);
+ this.cmoves.pop();
+ }
+
+ getCurrentScore() {
+ if (this.atLeastOneMove()) return "*";
+ const color = this.turn;
+ // Artifically change turn, for checkered pawns
+ this.turn = V.GetOppCol(this.turn);
+ const res = this.isAttacked(this.kingPos[color], [V.GetOppCol(color), "c"])
+ ? color == "w"
+ ? "0-1"
+ : "1-0"
+ : "1/2";
+ this.turn = V.GetOppCol(this.turn);
+ return res;
+ }
+
+ evalPosition() {
+ let evaluation = 0;
+ // Just count material for now, considering checkered neutral (...)
+ for (let i = 0; i < V.size.x; i++) {
+ for (let j = 0; j < V.size.y; j++) {
+ if (this.board[i][j] != V.EMPTY) {
+ const sqColor = this.getColor(i, j);
+ if (["w","b"].includes(sqColor)) {
+ const sign = sqColor == "w" ? 1 : -1;
+ evaluation += sign * V.VALUES[this.getPiece(i, j)];
+ }
+ }
+ }
+ }
+ return evaluation;
+ }
+
+ static GenRandInitFen(randomness) {
+ // Add 16 pawns flags + empty cmove:
+ return ChessRules.GenRandInitFen(randomness)
+ .slice(0, -2) + "1111111111111111 - -";
+ }
+
+ static ParseFen(fen) {
+ return Object.assign({}, ChessRules.ParseFen(fen), {
+ cmove: fen.split(" ")[5]
+ });
+ }
+
+ getFen() {