return (this.turn == side && this.getColor(x,y) == side);
}
- // On which squares is opponent under check after our move ? (for interface)
- getCheckSquares(move)
+ // On which squares is color under check ? (for interface)
+ getCheckSquares(color)
{
- this.play(move);
- const color = this.turn; //opponent
- let res = this.isAttacked(this.kingPos[color], [this.getOppCol(color)])
+ return this.isAttacked(this.kingPos[color], [this.getOppCol(color)])
? [JSON.parse(JSON.stringify(this.kingPos[color]))] //need to duplicate!
: [];
- this.undo(move);
- return res;
}
/////////////
////////////////////
// MOVES VALIDATION
+ // For the interface: possible moves for the current turn from square sq
getPossibleMovesFrom(sq)
{
- // Assuming color is right (already checked)
return this.filterValid( this.getPotentialMovesFrom(sq) );
}
{
if (moves.length == 0)
return [];
- return moves.filter(m => { return !this.underCheck(m); });
+ const color = this.turn;
+ return moves.filter(m => {
+ this.play(m);
+ const res = !this.underCheck(color);
+ this.undo(m);
+ return res;
+ });
}
// Search for all valid moves considering current turn (for engine and game end)
return false;
}
- // Is current player under check after his move ?
- underCheck(move)
+ // Is color under check after his move ?
+ underCheck(color)
{
- const color = this.turn;
- this.play(move);
- let res = this.isAttacked(this.kingPos[color], [this.getOppCol(color)]);
- this.undo(move);
- return res;
+ return this.isAttacked(this.kingPos[color], [this.getOppCol(color)]);
}
/////////////////
// Before move is played, update variables + flags
updateVariables(move)
{
- const piece = this.getPiece(move.start.x,move.start.y);
- const c = this.turn;
+ const piece = move.vanish[0].p;
+ const c = move.vanish[0].c;
const firstRank = (c == "w" ? V.size.x-1 : 0);
// Update king position + flags
play(move, ingame)
{
// DEBUG:
+// console.log("DO");
// if (!this.states) this.states = [];
// if (!ingame) this.states.push(this.getFen());
this.unupdateVariables(move);
// DEBUG:
+// console.log("UNDO "+this.getNotation(move));
// if (this.getFen() != this.states[this.states.length-1])
// debugger;
// this.states.pop();
incheck: [],
pgnTxt: "",
hints: (!localStorage["hints"] ? true : localStorage["hints"] === "1"),
- color: localStorage["color"] || "lichess", //lichess, chesscom or chesstempo
+ bcolor: localStorage["bcolor"] || "lichess", //lichess, chesscom or chesstempo
// sound level: 0 = no sound, 1 = sound only on newgame, 2 = always
sound: parseInt(localStorage["sound"] || "2"),
// Web worker to play computer moves without freezing interface:
['board'+sizeY]: true,
'light-square': (i+j)%2==0,
'dark-square': (i+j)%2==1,
- [this.color]: true,
+ [this.bcolor]: true,
'in-shadow': variant=="Dark" && this.score=="*"
&& !this.vr.enlightened[this.mycolor][ci][cj],
'highlight': showLight && !!lm && _.isMatch(lm.end, {x:ci,y:cj}),
h("select",
{
attrs: { "id": "selectColor" },
- on: { "change": this.setColor },
+ on: { "change": this.setBoardColor },
},
[
h("option",
this.hints = !this.hints;
localStorage["hints"] = (this.hints ? "1" : "0");
},
- setColor: function(e) {
- this.color = e.target.options[e.target.selectedIndex].value;
- localStorage["color"] = this.color;
+ setBoardColor: function(e) {
+ this.bcolor = e.target.options[e.target.selectedIndex].value;
+ localStorage["bcolor"] = this.bcolor;
},
setSound: function(e) {
this.sound = parseInt(e.target.options[e.target.selectedIndex].value);
this.endGame(this.mycolor=="w"?"0-1":"1-0");
},
newGame: function(mode, fenInit, color, oppId) {
- let fen = fenInit || VariantRules.GenRandInitFen();
+ const fen = fenInit || VariantRules.GenRandInitFen();
console.log(fen); //DEBUG
if (mode=="human" && !oppId)
{
if (this.mycolor != this.vr.turn)
this.playComputerMove();
}
- //else: against a (IRL) friend or problem solving: nothing more to do
+ else if (mode == "friend")
+ this.mycolor = "w"; //convention...
+ //else: problem solving: nothing more to do
},
continueGame: function(mode) {
this.mode = mode;
const score = localStorage.getItem(prefix+"score"); //set in "endGame()"
this.fenStart = localStorage.getItem(prefix+"fenStart");
this.vr = new VariantRules(fen, moves);
+ this.incheck = this.vr.getCheckSquares(this.vr.turn);
if (mode == "human")
{
this.gameId = localStorage.getItem("gameId");
if (this.mycolor != this.vr.turn)
this.playComputerMove();
}
- if (moves.length > 0)
- {
- const lastMove = moves[moves.length-1];
- this.vr.undo(lastMove);
- this.incheck = this.vr.getCheckSquares(lastMove);
- this.vr.play(lastMove, "ingame");
- }
if (score != "*")
{
// Small delay required when continuation run faster than drawing page
if (this.vr.canIplay(color,startSquare))
this.possibleMoves = this.vr.getPossibleMovesFrom(startSquare);
}
+ console.log(this.possibleMoves);
// Next line add moving piece just after current image
// (required for Crazyhouse reserve)
e.target.parentNode.insertBefore(this.selectedPiece, e.target.nextSibling);
// TODO: robustify this...
if (this.mode == "human" && !!move.computer)
return;
- this.incheck = this.vr.getCheckSquares(move); //is opponent in check?
this.vr.play(move, "ingame");
+ // Is opponent in check?
+ this.incheck = this.vr.getCheckSquares(this.vr.turn);
if (this.sound == 2)
new Audio("/sounds/move.mp3").play().catch(err => {});
if (this.mode == "computer")
this.vr.undo(lm);
if (this.sound == 2)
new Audio("/sounds/undo.mp3").play().catch(err => {});
- const lmBefore = this.vr.lastMove;
- if (!!lmBefore)
- {
- this.vr.undo(lmBefore);
- this.incheck = this.vr.getCheckSquares(lmBefore);
- this.vr.play(lmBefore, "ingame");
- }
- else
- this.incheck = [];
+ this.incheck = this.vr.getCheckSquares(this.vr.turn);
}
},
},
if (moves.length == 0)
return [];
let sideBoard = [this.getSideBoard(1), this.getSideBoard(2)];
- return moves.filter(m => { return !this.underCheck(m, sideBoard); });
+ const color = this.turn;
+ return moves.filter(m => {
+ this.playSide(m, sideBoard); //no need to track flags
+ const res = !this.underCheck(color, sideBoard);
+ this.undoSide(m, sideBoard);
+ return res;
+ });
}
getAllValidMoves()
});
}
- underCheck(move, sideBoard) //sideBoard arg always provided
+ underCheck(color, sideBoard) //sideBoard arg always provided
{
- const color = this.turn;
- this.playSide(move, sideBoard); //no need to track flags
const kp = this.kingPos[color];
const mirrorSide = (sideBoard[0][kp[0]][kp[1]] != V.EMPTY ? 1 : 2);
let saveBoard = this.board;
this.board = sideBoard[mirrorSide-1];
let res = this.isAttacked(kp, [this.getOppCol(color)]);
this.board = saveBoard;
- this.undoSide(move, sideBoard);
return res;
}
- getCheckSquares(move)
+ getCheckSquares(color)
{
- this.play(move);
- const color = this.turn; //opponent
const pieces = Object.keys(V.ALICE_CODES);
const kp = this.kingPos[color];
const mirrorSide = (pieces.includes(this.getPiece(kp[0],kp[1])) ? 1 : 2);
? [ JSON.parse(JSON.stringify(this.kingPos[color])) ]
: [ ];
this.board = saveBoard;
- this.undo(move);
return res;
}
V.steps[V.ROOK].concat(V.steps[V.BISHOP]), "oneStep");
}
- underCheck(move)
+ underCheck(color)
{
- const c = this.turn;
- const oppCol = this.getOppCol(c);
- this.play(move)
- let res = this.isAttacked(this.kingPos[c], [oppCol])
- || !this.isAttacked(this.antikingPos[c], [oppCol]);
- this.undo(move);
+ const oppCol = this.getOppCol(color);
+ let res = this.isAttacked(this.kingPos[color], [oppCol])
+ || !this.isAttacked(this.antikingPos[color], [oppCol]);
return res;
}
- getCheckSquares(move)
+ getCheckSquares(color)
{
- let res = super.getCheckSquares(move);
- this.play(move);
- const c = this.turn;
- if (!this.isAttacked(this.antikingPos[c], [this.getOppCol(c)]))
- res.push(JSON.parse(JSON.stringify(this.antikingPos[c])));
- this.undo(move);
+ let res = super.getCheckSquares(color);
+ if (!this.isAttacked(this.antikingPos[color], [this.getOppCol(color)]))
+ res.push(JSON.parse(JSON.stringify(this.antikingPos[color])));
return res;
}
}
}
- underCheck(move)
+ underCheck(color)
{
- const c = this.turn;
- const oppCol = this.getOppCol(c);
- this.play(move);
+ const oppCol = this.getOppCol(color);
let res = undefined;
// If our king disappeared, move is not valid
- if (this.kingPos[c][0] < 0)
+ if (this.kingPos[color][0] < 0)
res = true;
// If opponent king disappeared, move is valid
else if (this.kingPos[oppCol][0] < 0)
res = false;
// Otherwise, if we remain under check, move is not valid
else
- res = this.isAttacked(this.kingPos[c], [oppCol]);
- this.undo(move);
+ res = this.isAttacked(this.kingPos[color], [oppCol]);
return res;
}
- getCheckSquares(move)
+ getCheckSquares(color)
{
- const c = this.getOppCol(this.turn);
- // King might explode:
- const saveKingPos = JSON.parse(JSON.stringify(this.kingPos[c]));
- this.play(move);
let res = [ ];
- if (this.kingPos[c][0] < 0)
- res = [saveKingPos];
- else if (this.isAttacked(this.kingPos[c], [this.getOppCol(c)]))
- res = [ JSON.parse(JSON.stringify(this.kingPos[c])) ]
- this.undo(move);
+ if (this.kingPos[color][0] >= 0 //king might have exploded
+ && this.isAttacked(this.kingPos[color], [this.getOppCol(color)]))
+ {
+ res = [ JSON.parse(JSON.stringify(this.kingPos[color])) ]
+ }
return res;
}
if (this.getPiece(sx,sy) == V.PAWN && Math.abs(sx - ex) == 2)
{
return {
- x: ex,
+ x: (ex + sx)/2,
y: (move.end.y + sy)/2
};
}
return undefined; //default
}
- // Special pawn rules: promotions to captured friendly pieces,
- // optional on ranks 8-9 and mandatory on rank 10.
+ // Special pawns movements
getPotentialPawnMoves([x,y])
{
const color = this.turn;
if (this.board[x+shiftX][y+shiftY] == V.EMPTY)
{
for (let piece of finalPieces)
- {
- moves.push(this.getBasicMove([x,y], [x+shiftX,y+shiftY],
- {c:pawnColor,p:piece}));
- }
- if (x == startRank && this.board[x+2*shiftX][y] == V.EMPTY)
+ moves.push(this.getBasicMove([x,y], [x+shiftX,y+shiftY], {c:color,p:piece}));
+ if (x == startRank && y+2*shiftY>=0 && y+2*shiftY<sizeY
+ && this.board[x+2*shiftX][y+2*shiftY] == V.EMPTY)
{
// Two squares jump
- moves.push(this.getBasicMove([x,y], [x+2*shiftX,y+2*shiftY]);
+ moves.push(this.getBasicMove([x,y], [x+2*shiftX,y+2*shiftY]));
}
}
}
&& this.canTake([x,y], [x+shiftX,y]))
{
for (let piece of finalPieces)
- {
- moves.push(this.getBasicMove([x,y], [x+shiftX,y+shiftY],
- {c:pawnColor,p:piece}));
- }
+ moves.push(this.getBasicMove([x,y], [x+shiftX,y], {c:color,p:piece}));
}
}
const epSquare = this.epSquares[Lep-1]; //always at least one element
if (!!epSquare && epSquare.x == x+shiftX && epSquare.y == y)
{
- let enpassantMove = this.getBasicMove([x,y], [x+shift,y]);
+ let enpassantMove = this.getBasicMove([x,y], [x+shiftX,y]);
enpassantMove.vanish.push({
x: epSquare.x,
- y: y,
+ y: epSquare.y,
p: 'p',
- c: this.getColor(epSquare.x,y)
+ c: this.getColor(epSquare.x,epSquare.y)
});
moves.push(enpassantMove);
}
return moves;
}
+
+ isAttackedByPawn([x,y], colors)
+ {
+ for (let c of colors)
+ {
+ let pawnShift = (c=="w" ? 1 : -1);
+ if (x+pawnShift>=0 && x+pawnShift<V.size.x)
+ {
+ if (this.getPiece(x+pawnShift,y)==V.PAWN && this.getColor(x+pawnShift,y)==c)
+ return true;
+ }
+ }
+ return false;
+ }
}
const VariantRules = BerolinaRules;
const L = this.moves.length;
if (L > 0 && this.oppositeMoves(this.moves[L-1], m))
return false;
- return !this.underCheck(m);
+ this.play(m);
+ const res = !this.underCheck(color);
+ this.undo(m);
+ return res;
});
}
return false;
}
- underCheck(move)
+ underCheck(color)
{
- const color = this.turn;
- this.play(move);
- let res = this.isAttacked(this.kingPos[color], [this.getOppCol(color),'c']);
- this.undo(move);
- return res;
+ return this.isAttacked(this.kingPos[color], [this.getOppCol(color),'c']);
}
- getCheckSquares(move)
+ getCheckSquares(color)
{
- this.play(move);
- const color = this.turn;
// Artifically change turn, for checkered pawns
this.turn = this.getOppCol(color);
const kingAttacked = this.isAttacked(
? [JSON.parse(JSON.stringify(this.kingPos[color]))] //need to duplicate!
: [];
this.turn = color;
- this.undo(move);
return res;
}
this.enlightened["b"][move.end.x][move.end.y] = true;
}
+ // Has to be redefined to avoid an infinite loop
+ getAllValidMoves()
+ {
+ const color = this.turn;
+ const oppCol = this.getOppCol(color);
+ let potentialMoves = [];
+ 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 && this.getColor(i,j) == color)
+ Array.prototype.push.apply(potentialMoves, this.getPotentialMovesFrom([i,j]));
+ }
+ }
+ return potentialMoves; //because there are no checks
+ }
+
atLeastOneMove()
{
if (this.kingPos[this.turn][0] < 0)
return true; //TODO: is it right?
}
- underCheck(move)
+ underCheck(color)
{
return false; //there is no check
}
- getCheckSquares(move)
+ getCheckSquares(color)
{
- const c = this.getOppCol(this.turn); //opponent
- const saveKingPos = this.kingPos[c]; //king might be taken
- this.play(move);
- // The only way to be "under check" is to have lost the king (thus game over)
- let res = this.kingPos[c][0] < 0
- ? [JSON.parse(JSON.stringify(saveKingPos))]
- : [];
- this.undo(move);
- return res;
+ return [];
}
updateVariables(move)
return true; //always at least one possible move
}
- underCheck(move)
+ underCheck(color)
{
return false; //there is no check
}
- getCheckSquares(move)
+ getCheckSquares(color)
{
return [];
}
return moves;
}
- underCheck(move)
+ underCheck(color)
{
return false; //No notion of check
}
return true; //TODO: is it right?
}
- underCheck(move)
+ underCheck(color)
{
return false; //there is no check
}
getCheckSquares(move)
{
- const c = this.getOppCol(this.turn); //opponent
- const saveKingPos = this.kingPos[c]; //king might be taken
- this.play(move);
- // The only way to be "under check" is to have lost the king (thus game over)
- let res = this.kingPos[c][0] < 0
- ? [JSON.parse(JSON.stringify(saveKingPos))]
- : [];
- this.undo(move);
- return res;
+ return [];
}
updateVariables(move)
-class UpsidedownRules extends ChessRUles
+class UpsidedownRules extends ChessRules
{
static HasFlags() { return false; }
+ // Forbid two knights moves in a row at moves 1 and 2
+ getPotentialKnightMoves(sq)
+ {
+ // But this will also affect FEN for problems, and...
+ // does it really solve the problem ?
+ //if (this.moves. ...)
+ }
+
getPotentialKingMoves(sq)
{
// No castle
pieces[c][knight2Pos] = 'n';
pieces[c][rook2Pos] = 'r';
}
- return pieces["w"].join("") +
+ return pieces["w"].join("").toUpperCase() +
"/PPPPPPPP/8/8/8/8/pppppppp/" +
- pieces["b"].join("").toUpperCase() +
+ pieces["b"].join("") +
" w 1111 -"; //add turn + flags + enpassant
}
}