(But it's really just for Magnetic chess)
setInterval "CRON" task in sockets.js to check connected clients
(every 1hour maybe, or more)
-Systematically show init+dest squares in PGN, maybe after short notation
-(2 moves list, second for de-ambiguification)
Button to show all pieces that can move (next to expert mode; change icons)
-
-Bugs, limitations:
- - switching chess when castling: show 2 promotion kings (??)
- - Crazyhouse: TODO = keep track of promoted pawns.
- - Checkered: implement stage 2 ?!
+Style (crazyhouse): ghost image of reserve pieces are initially translated
// if (!ingame) this.states.push(JSON.stringify(this.board));
if (!!ingame)
- move.notation = this.getNotation(move);
+ move.notation = [this.getNotation(move), this.getLongNotation(move)];
move.flags = JSON.stringify(this.flags); //save flags (for undo)
this.updateVariables(move);
}
}
+ // Complete the usual notation, may be required for de-ambiguification
+ getLongNotation(move)
+ {
+ const startSquare =
+ String.fromCharCode(97 + move.start.y) + (VariantRules.size[0]-move.start.x);
+ const finalSquare =
+ String.fromCharCode(97 + move.end.y) + (VariantRules.size[0]-move.end.x);
+ return startSquare + finalSquare; //not encoding move. But short+long is enough
+ }
+
// The score is already computed when calling this function
getPGN(mycolor, score, fenStart, mode)
{
pgn += '[Fen "' + fenStart + '"]<br>';
pgn += '[Result "' + score + '"]<br><br>';
+ // Standard PGN
for (let i=0; i<this.moves.length; i++)
{
if (i % 2 == 0)
pgn += ((i/2)+1) + ".";
- pgn += this.moves[i].notation + " ";
+ pgn += this.moves[i].notation[0] + " ";
}
+ pgn += score + "<br><br>";
+ // "Complete moves" PGN (helping in ambiguous cases)
+ for (let i=0; i<this.moves.length; i++)
+ {
+ if (i % 2 == 0)
+ pgn += ((i/2)+1) + ".";
+ pgn += this.moves[i].notation[1] + " ";
+ }
pgn += score;
+
return pgn;
}
}
elementArray.push(gameDiv);
if (!!this.vr.reserve)
{
+ const shiftIdx = (this.mycolor=="w" ? 0 : 1);
let myReservePiecesArray = [];
for (let i=0; i<VariantRules.RESERVE_PIECES.length; i++)
{
myReservePiecesArray.push(h('div',
{
'class': {'board':true, ['board'+sizeY]:true},
- attrs: { id: this.getSquareId({x:sizeX,y:i}) }
+ attrs: { id: this.getSquareId({x:sizeX+shiftIdx,y:i}) }
},
[
h('img',
oppReservePiecesArray.push(h('div',
{
'class': {'board':true, ['board'+sizeY]:true},
- attrs: { id: this.getSquareId({x:sizeX,y:i}) }
+ attrs: { id: this.getSquareId({x:sizeX+(1-shiftIdx),y:i}) }
},
[
h('img',
this.possibleMoves = this.mode!="idle" && this.vr.canIplay(this.mycolor,startSquare)
? this.vr.getPossibleMovesFrom(startSquare)
: [];
+ console.log(this.possibleMoves);
+ console.log(this.vr.promoted);
e.target.parentNode.appendChild(this.selectedPiece);
}
},
[V.QUEEN]: 0,
}
};
- // May be a continuation: adjust numbers of pieces according to captures + rebirths
- this.moves.forEach(m => {
- if (m.vanish.length == 2)
- this.reserve[m.appear[0].c][m.vanish[1].p]++;
- else if (m.vanish.length == 0)
- this.reserve[m.appear[0].c][m.appear[0].p]--;
- });
- // TODO: keep track of promoted pawns ==> give a pawn if captured.
+ const [sizeX,sizeY] = VariantRules.size;
+ this.promoted = doubleArray(sizeX, sizeY, false);
+ // May be a continuation: adjust numbers of pieces in reserve + promoted pieces
+ this.moves.forEach(m => { this.updateVariables(m); });
}
getColor(i,j)
})
],
vanish: [],
- start: {x:sizeX, y:y}, //a bit artificial...
+ start: {x:x, y:y}, //a bit artificial...
end: {x:i, y:j}
});
moves.push(mv);
getPotentialMovesFrom([x,y])
{
const sizeX = VariantRules.size[0];
- if (x < sizeX)
- return super.getPotentialMovesFrom([x,y]);
- // Reserves, outside of board: x == sizeX
- return this.getReserveMoves([x,y]);
+ if (x >= sizeX)
+ {
+ // Reserves, outside of board: x == sizeX
+ return this.getReserveMoves([x,y]);
+ }
+ // Standard moves
+ return super.getPotentialMovesFrom([x,y]);
}
getAllValidMoves()
const color = this.turn;
const sizeX = VariantRules.size[0];
for (let i=0; i<VariantRules.RESERVE_PIECES.length; i++)
- moves = moves.concat(this.getReserveMoves([sizeX,i]));
+ moves = moves.concat(this.getReserveMoves([sizeX+(color=="w"?0:1),i]));
return this.filterValid(moves);
}
updateVariables(move)
{
super.updateVariables(move);
+ if (move.vanish.length == 2 && move.appear.length == 2)
+ return; //skip castle
const color = this.turn;
- if (move.vanish.length==2)
- this.reserve[color][move.vanish[1].p]++;
- if (move.vanish.length==0)
+ const V = VariantRules;
+ // Three types of move:
+ // 1. Rebirth: just update material
+ // 2. Standard move:
+ // a. check if a promoted piece is moving
+ // b. check if it's a promotion (mutually exclusive)
+ // 3. Capture:
+ // a. check if a promoted piece is captured (and mark move)
+ // b. check if a promoted piece is moving
+ // c. check if it's a promotion (mutually exclusive with b)
+ if (move.vanish.length == 0)
this.reserve[color][move.appear[0].p]--;
+ else if (move.vanish.length == 1)
+ {
+ if (this.promoted[move.start.x][move.start.y])
+ {
+ this.promoted[move.start.x][move.start.y] = false;
+ this.promoted[move.end.x][move.end.y] = true;
+ }
+ else if (move.vanish[0].p == V.PAWN && move.appear[0].p != V.PAWN)
+ this.promoted[move.end.x][move.end.y] = true;
+ }
+ else //capture
+ {
+ if (this.promoted[move.end.x][move.end.y])
+ {
+ move.capturePromoted = true; //required for undo
+ this.reserve[color][VariantRules.PAWN]++;
+ this.promoted[move.end.x][move.end.y] = false;
+ }
+ else
+ this.reserve[color][move.vanish[1].p]++;
+ if (this.promoted[move.start.x][move.start.y])
+ {
+ this.promoted[move.start.x][move.start.y] = false;
+ this.promoted[move.end.x][move.end.y] = true;
+ }
+ else if (move.vanish[0].p == V.PAWN && move.appear[0].p != V.PAWN)
+ this.promoted[move.end.x][move.end.y] = true;
+ }
}
unupdateVariables(move)
{
super.unupdateVariables(move);
const color = this.turn;
- if (move.vanish.length==2)
- this.reserve[color][move.vanish[1].p]--;
- if (move.vanish.length==0)
+ const V = VariantRules;
+ if (move.vanish.length == 0)
this.reserve[color][move.appear[0].p]++;
+ else if (move.vanish.length == 1)
+ {
+ if (this.promoted[move.end.x][move.end.y])
+ {
+ this.promoted[move.end.x][move.end.y] = false;
+ if (move.vanish[0].p != V.PAWN || move.appear[0].p == V.PAWN)
+ {
+ // Not a promotion (= promoted piece creation)
+ this.promoted[move.start.x][move.start.y] = true;
+ }
+ }
+ }
+ else //capture
+ {
+ if (this.promoted[move.end.x][move.end.y])
+ {
+ this.promoted[move.end.x][move.end.y] = !!move.capturePromoted;
+ if (move.vanish[0].p != V.PAWN || move.appear[0].p == V.PAWN)
+ this.promoted[move.start.x][move.start.y] = true;
+ }
+ // Un-update material:
+ if (move.capturePromoted)
+ this.reserve[color][VariantRules.PAWN]--;
+ else
+ this.reserve[color][move.vanish[1].p]--;
+ }
}
static get SEARCH_DEPTH() { return 2; } //high branching factor
+ evalPosition()
+ {
+ let evaluation = super.evalPosition();
+ // Add reserves:
+ for (let i=0; i<VariantRules.RESERVE_PIECES.length; i++)
+ {
+ const p = VariantRules.RESERVE_PIECES[i];
+ evaluation += this.reserve["w"][p] * VariantRules.VALUES[p];
+ evaluation -= this.reserve["b"][p] * VariantRules.VALUES[p];
+ }
+ return evaluation;
+ }
+
getNotation(move)
{
if (move.vanish.length > 0)
String.fromCharCode(97 + move.end.y) + (VariantRules.size[0]-move.end.x);
return piece + "@" + finalSquare;
}
+
+ getLongNotation(move)
+ {
+ if (move.vanish.length > 0)
+ return super.getLongNotation(move);
+ const finalSquare =
+ String.fromCharCode(97 + move.end.y) + (VariantRules.size[0]-move.end.x);
+ return "@" + finalSquare;
+ }
}
{
initVariables(fen)
{
- // No castling, hence no flags
+ // No castling, hence no flags; but flags defined for compatibility
+ this.flags = "-";
const epSq = this.moves.length > 0 ? this.getEpSquare(this.lastMove) : undefined;
this.epSquares = [ epSq ];
}
return [];
}
- play(move, ingame)
- {
- if (!!ingame)
- move.notation = this.getNotation(move);
- this.moves.push(move);
- this.epSquares.push( this.getEpSquare(move) );
- VariantRules.PlayOnBoard(this.board, move);
- }
-
- undo(move)
- {
- VariantRules.UndoOnBoard(this.board, move);
- this.epSquares.pop();
- this.moves.pop();
- }
+ // Unused:
+ updateVariables(move) { }
+ unupdateVariables(move) { }
+ parseFlags(flags) { }
checkGameEnd()
{
const c = this.getColor(x1,y1); //same as color at square 2
const p1 = this.getPiece(x1,y1);
const p2 = this.getPiece(x2,y2);
+ const V = VariantRules;
+ if (p1 == V.KING && p2 == V.ROOK)
+ return []; //avoid duplicate moves (potential conflict with castle)
let move = new Move({
appear: [
new PiPo({x:x2,y:y2,c:c,p:p1}),
// Move completion: promote switched pawns (as in Magnetic)
const sizeX = VariantRules.size[0];
const lastRank = (c == "w" ? 0 : sizeX-1);
- const V = VariantRules;
let moves = [];
if ((p1==V.PAWN && x2==lastRank) || (p2==V.PAWN && x1==lastRank))
{
h2.stageDelimiter Stage 2
-p.warn This stage is unimplemented for now.
+p.warn This stage is not (and probably will never be) implemented.
p.
During the game one of the two players can decide to take control of the checkered pieces.
They thus become autonomous and vulnerable to being captured - stage 2 begins.
- The other player is in charge of both the white and black pieces, and tries to eliminate checkered pieces.
+ The other player is in charge of both the white and black pieces, and tries to
+ eliminate checkered pieces.
The checkered side wins by checkmating either the white or black king.
+h4 Variant of stage 2
+p.
+ An observer could decide to join the game by taking the checkered pieces at any moment.
+ It then becomes a chess game with three players, with some subtelties to be resolved.
+ It was tested in some (real life) games organised by the variant creator.
+
h3 Special moves
span Checkered pawns can...
h3 Credits
ul
- li The rules of Checkered Chess were thought up by Patrick Bernier and developed with the help of Benjamin Auder.
- li Thanks also to Olive Martin, Christian Poisson, Bevis Martin, Laurent Nouhaud and Frédéric Fradet.
+ li.
+ The rules of Checkered Chess were thought up by Patrick Bernier and developed
+ with the help of Benjamin Auder.
+ li.
+ Thanks also to Olive Martin, Christian Poisson, Bevis Martin, Laurent Nouhaud
+ and Frédéric Fradet.