{
let i = x + step[0];
let j = y + step[1];
- while (i>=0 && i<sizeX && j>=0 && j<sizeY && this.board[i][j] == VariantRules.EMPTY)
+ while (i>=0 && i<sizeX && j>=0 && j<sizeY
+ && this.board[i][j] == VariantRules.EMPTY)
{
moves.push(this.getBasicMove([x,y], [i,j]));
if (oneStep !== undefined)
const color = this.turn;
let moves = [];
const V = VariantRules;
- const [sizeX,sizeY] = VariantRules.size;
+ const [sizeX,sizeY] = V.size;
const shift = (color == "w" ? -1 : 1);
const firstRank = (color == 'w' ? sizeX-1 : 0);
const startRank = (color == "w" ? sizeX-2 : 1);
if (this.board[x+shift][y] == V.EMPTY)
{
moves.push(this.getBasicMove([x,y], [x+shift,y]));
- // Next condition because variants with pawns on 1st rank generally allow them to jump
+ // Next condition because variants with pawns on 1st rank allow them to jump
if ([startRank,firstRank].includes(x) && this.board[x+2*shift][y] == V.EMPTY)
{
// Two squares jump
}
}
// Captures
- if (y>0 && this.canTake([x,y], [x+shift,y-1]) && this.board[x+shift][y-1] != V.EMPTY)
+ if (y>0 && this.canTake([x,y], [x+shift,y-1])
+ && this.board[x+shift][y-1] != V.EMPTY)
+ {
moves.push(this.getBasicMove([x,y], [x+shift,y-1]));
- if (y<sizeY-1 && this.canTake([x,y], [x+shift,y+1]) && this.board[x+shift][y+1] != V.EMPTY)
+ }
+ if (y<sizeY-1 && this.canTake([x,y], [x+shift,y+1])
+ && this.board[x+shift][y+1] != V.EMPTY)
+ {
moves.push(this.getBasicMove([x,y], [x+shift,y+1]));
+ }
}
if (x+shift == lastRank)
if (this.board[x+shift][y] == V.EMPTY)
moves.push(this.getBasicMove([x,y], [x+shift,y], {c:color,p:p}));
// Captures
- if (y>0 && this.canTake([x,y], [x+shift,y-1]) && this.board[x+shift][y-1] != V.EMPTY)
+ if (y>0 && this.canTake([x,y], [x+shift,y-1])
+ && this.board[x+shift][y-1] != V.EMPTY)
+ {
moves.push(this.getBasicMove([x,y], [x+shift,y-1], {c:color,p:p}));
- if (y<sizeY-1 && this.canTake([x,y], [x+shift,y+1]) && this.board[x+shift][y+1] != V.EMPTY)
+ }
+ if (y<sizeY-1 && this.canTake([x,y], [x+shift,y+1])
+ && this.board[x+shift][y+1] != V.EMPTY)
+ {
moves.push(this.getBasicMove([x,y], [x+shift,y+1], {c:color,p:p}));
+ }
});
}
const oppCol = this.getOppCol(color);
let potentialMoves = [];
const [sizeX,sizeY] = VariantRules.size;
- for (var i=0; i<sizeX; i++)
+ for (let i=0; i<sizeX; i++)
{
- for (var j=0; j<sizeY; j++)
+ for (let j=0; j<sizeY; j++)
{
// Next condition ... != oppCol is a little HACK to work with checkered variant
if (this.board[i][j] != VariantRules.EMPTY && this.getColor(i,j) != oppCol)
V.steps[V.ROOK].concat(V.steps[V.BISHOP]), "oneStep");
}
- // Generic method for non-pawn pieces ("sliding or jumping"): is x,y attacked by piece != color ?
+ // Generic method for non-pawn pieces ("sliding or jumping"):
+ // is x,y attacked by piece !of color in colors?
isAttackedBySlideNJump([x,y], colors, piece, steps, oneStep)
{
const [sizeX,sizeY] = VariantRules.size;
// DEBUG:
// if (!this.states) this.states = [];
// if (!ingame) this.states.push(JSON.stringify(this.board));
+// if (!this.rstates) this.rstates = [];
+// if (!ingame) this.rstates.push(JSON.stringify(this.promoted)+"-"+JSON.stringify(this.reserve));
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);
// DEBUG:
// let state = this.states.pop();
-// if (JSON.stringify(this.board) != state)
+// let rstate = this.rstates.pop();
+// if (JSON.stringify(this.board) != state || JSON.stringify(this.promoted)+"-"+JSON.stringify(this.reserve) != rstate)
// debugger;
}
}
// Assumption: at least one legal move
- getComputerMove(moves1) //moves1 might be precomputed (Magnetic chess)
+ // NOTE: works also for extinction chess because depth is 3...
+ getComputerMove()
{
this.shouldReturn = false;
const maxeval = VariantRules.INFINITY;
const color = this.turn;
- if (!moves1)
- moves1 = this.getAllValidMoves();
+ let moves1 = this.getAllValidMoves();
+
+ // Can I mate in 1 ? (for Magnetic & Extinction)
+ for (let i of _.shuffle(_.range(moves1.length)))
+ {
+ this.play(moves1[i]);
+ const finish = (Math.abs(this.evalPosition()) >= VariantRules.THRESHOLD_MATE);
+ this.undo(moves1[i]);
+ if (finish)
+ return moves1[i];
+ }
// Rank moves using a min-max at depth 2
for (let i=0; i<moves1.length; i++)
candidates.push(j);
let currentBest = moves1[_.sample(candidates, 1)];
- // Skip depth 3 if we found a checkmate (or if we are checkmated in 1...)
+ // Skip depth 3+ if we found a checkmate (or if we are checkmated in 1...)
if (VariantRules.SEARCH_DEPTH >= 3
&& Math.abs(moves1[0].eval) < VariantRules.THRESHOLD_MATE)
{
- // TODO: show current analyzed move for depth 3, allow stopping eval (return moves1[0])
for (let i=0; i<moves1.length; i++)
{
if (this.shouldReturn)
{
const [sizeX,sizeY] = VariantRules.size;
let evaluation = 0;
- //Just count material for now
+ // Just count material for now
for (let i=0; i<sizeX; i++)
{
for (let j=0; j<sizeY; j++)
}
}
+ // 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;
}
}