return "all";
}
- // Path to pieces
- static getPpath(b) {
- return b; //usual pieces in pieces/ folder
- }
-
// Turn "wb" into "B" (for FEN)
static board2fen(b) {
return b[0] == "w" ? b[1].toUpperCase() : b[1];
return V.CoordToColumn(coords.y) + (V.size.x - coords.x);
}
+ // Path to pieces
+ getPpath(b) {
+ return b; //usual pieces in pieces/ folder
+ }
+
// Aggregates flags into one object
aggregateFlags() {
return this.castleFlags;
// INITIALIZATION
constructor(fen) {
- this.re_init(fen);
+ // In printDiagram() fen isn't supply because only getPpath() is used
+ if (fen)
+ this.re_init(fen);
}
// Fen string fully describes the game state
attrs: {
src:
"/images/pieces/" +
- V.getPpath(this.vr.board[ci][cj]) +
+ this.vr.getPpath(this.vr.board[ci][cj], this.userColor, this.score) +
".svg"
}
})
attrs: {
src:
"/images/pieces/" +
- this.vr.getReservePpath(playingColor, i) +
+ this.vr.getReservePpath(i, playingColor) +
".svg"
}
}),
attrs: {
src:
"/images/pieces/" +
- this.vr.getReservePpath(oppCol, i) +
+ this.vr.getReservePpath(i, oppCol) +
".svg"
}
}),
attrs: {
src:
"/images/pieces/" +
- V.getPpath(m.appear[0].c + m.appear[0].p) +
+ this.vr.getPpath(m.appear[0].c + m.appear[0].p) +
".svg"
},
class: { "choice-piece": true },
"Reuse pieces": "Reuse pieces",
"Reverse captures": "Reverse captures",
"Shared pieces": "Shared pieces",
- "Standard rules": "Standard rules"
+ "Standard rules": "Standard rules",
+ "Unidentified pieces": "Unidentified pieces"
};
"Reuse pieces": "Reutilizar piezas",
"Reverse captures": "Capturas invertidas",
"Shared pieces": "Piezas compartidas",
- "Standard rules": "Reglas estandar"
+ "Standard rules": "Reglas estandar",
+ "Unidentified pieces": "Piezas no identificadas"
};
"Reuse pieces": "Réutiliser les pièces",
"Reverse captures": "Captures inversées",
"Shared pieces": "Pièces partagées",
- "Standard rules": "Règles usuelles"
+ "Standard rules": "Règles usuelles",
+ "Unidentified pieces": "Pièces non identifiées"
};
--- /dev/null
+p.boxed
+ | If a piece captures one of the same kind, both disappear.
+
+// TODO:
+ // Due to random 2 ranks: no castling (would reveal too much)
+ // To not reveal much, also no en passant
+
+p.
+ The defensive power of pawns is thus increased, because they don't fear
+ captures (by other pawns).
+
+p.
+ Endings are also affected quite a lot, and sometimes new threats occur:
+ on the diagram, 3.Bxg7 wins a pawn because 3...Bxg7 would make both
+ bishops disappear.
+
+figure.diagram-container
+ .diagram
+ | fen:r1bqkbnr/pp1ppppp/2n5/2p5/8/1P6/PBPPPPPP/RN1QKBNR:
+ figcaption After 1.b3 c5 2.Bb2 Nc6
+
+h3 Source
+
+p
+ a(href="https://www.chessvariants.com/rules/strate-go-chess") Strate-Go chess
+ | on chessvariants.com.
--- /dev/null
+p.boxed
+ | Si una pieza captura otra del mismo tipo, las dos desaparecen.
+
+p.
+ El poder defensivo de los peones aumenta así, ya que no temen
+ más capturas (por otros peones).
+
+p.
+ Las finales también se ven muy afectadas y, a veces, nuevas amenazas
+ ocurren: en el diagrama, 3.Bxg7 gana un peón porque 3...Bxg7 causaría
+ la desaparición de los dos alfiles.
+
+figure.diagram-container
+ .diagram
+ | fen:r1bqkbnr/pp1ppppp/2n5/2p5/8/1P6/PBPPPPPP/RN1QKBNR:
+ figcaption Después de 1.b3 c5 2.Bb2 Nc6
+
+h3 Fuente
+
+p
+ | La
+ a(href="https://www.chessvariants.com/rules/antimatter-chess") variante Antimateria
+ | en chessvariants.com.
--- /dev/null
+p.boxed
+ | Si une pièce en capture une autre du même type, les deux disparaissent.
+
+p.
+ Le pouvoir défensif des pions est ainsi augmenté, puisqu'ils ne craignent
+ plus les captures (par d'autres pions).
+
+p.
+ Les finales sont aussi beaucoup affectées, et parfois de nouvelles menaces
+ surviennent : sur le diagramme, 3.Bxg7 gagne un pion car 3...Bxg7 provoquerait
+ la disparition des deux fous.
+
+figure.diagram-container
+ .diagram
+ | fen:r1bqkbnr/pp1ppppp/2n5/2p5/8/1P6/PBPPPPPP/RN1QKBNR:
+ figcaption After 1.b3 c5 2.Bb2 Nc6
+
+h3 Source
+
+p
+ | La
+ a(href="https://www.chessvariants.com/rules/antimatter-chess") variante Antimatière
+ | sur chessvariants.com.
When a piece is taken it is not removed from the board, but moved instead
to the square that was initially occupied by the capturing piece.
+p.
+ It is forbidden to "un-do" a capture right after it was played:
+ in the diagram position, 3...Bxg7 is not allowed.
+
figure.diagram-container
.diagram
- | fen:rnbqkb1r/ppp1pppp/5B2/3p4/8/1P6/PnPPPPPP/RN1QKBNR:
- figcaption After 1.b3 d5 2.Bb2 Nf6 3.Bxf6
+ | fen:rnbqk1nr/ppppppBp/6p1/8/8/1P6/PbPPPPPP/RN1QKBNR:
+ figcaption After 1.b3 g6 2.Bb2 Bg7 3.Bxg7
ul
li.
Cuando se captura una pieza, no se retira del tablero, sino
solo se movió a la casilla originalmente ocupada por la pieza que capturó.
+p.
+ Está prohibido "deshacer" una captura inmediatamente después de que se
+ haya jugado: en la posición del diagrama, 3...Bxg7 no está permitido.
+
figure.diagram-container
.diagram
- | fen:rnbqkb1r/ppp1pppp/5B2/3p4/8/1P6/PnPPPPPP/RN1QKBNR:
- figcaption Después de 1.b3 d5 2.Bb2 Nf6 3.Bxf6
+ | fen:rnbqk1nr/ppppppBp/6p1/8/8/1P6/PbPPPPPP/RN1QKBNR:
+ figcaption Después de 1.b3 g6 2.Bb2 Bg7 3.Bxg7
ul
li.
Quand une pièce est capturée elle n'est pas retirée de l'échiquier, mais
seulement déplacée sur la case initialement occupée par la pièce capturante.
+p.
+ Il est interdit de "défaire" une capture juste après qu'elle a été jouée :
+ dans la position du diagramme, 3...Bxg7 n'est pas autorisé.
+
figure.diagram-container
.diagram
- | fen:rnbqkb1r/ppp1pppp/5B2/3p4/8/1P6/PnPPPPPP/RN1QKBNR:
- figcaption Après 1.b3 d5 2.Bb2 Nf6 3.Bxf6
+ | fen:rnbqk1nr/ppppppBp/6p1/8/8/1P6/PbPPPPPP/RN1QKBNR:
+ figcaption Après 1.b3 g6 2.Bb2 Bg7 3.Bxg7
ul
li.
const orientation = args.orientation || "w";
const markArray = getMarkArray(args.marks);
const shadowArray = getShadowArray(args.shadow);
+ const vr = new V(); //just for pieces images paths
let boardDiv = "";
const [startX, startY, inc] =
orientation == "w" ? [0, 0, 1] : [V.size.x - 1, V.size.y - 1, -1];
boardDiv +=
"<img " +
"src='/images/pieces/" +
- V.getPpath(board[i][j]) +
+ vr.getPpath(board[i][j]) +
".svg' " +
"class='piece'/>";
}
};
}
- static getPpath(b) {
- return (Object.keys(this.ALICE_PIECES).includes(b[1]) ? "Alice/" : "") + b;
- }
-
static get PIECES() {
return ChessRules.PIECES.concat(Object.keys(V.ALICE_PIECES));
}
+ getPpath(b) {
+ return (Object.keys(this.ALICE_PIECES).includes(b[1]) ? "Alice/" : "") + b;
+ }
+
setOtherVariables(fen) {
super.setOtherVariables(fen);
const rows = V.ParseFen(fen).position.split("/");
import { randInt } from "@/utils/alea";
export const VariantRules = class AntikingRules extends ChessRules {
- static getPpath(b) {
- return b[1] == "a" ? "Antiking/" + b : b;
- }
-
static get ANTIKING() {
return "a";
}
return ChessRules.PIECES.concat([V.ANTIKING]);
}
+ getPpath(b) {
+ return b[1] == "a" ? "Antiking/" + b : b;
+ }
+
setOtherVariables(fen) {
super.setOtherVariables(fen);
this.antikingPos = { w: [-1, -1], b: [-1, -1] };
return false;
}
- static getPpath(b) {
+ static get PIECES() {
+ return ChessRules.PIECES.concat([V.IMMOBILIZER]);
+ }
+
+ getPpath(b) {
if (b[1] == "m")
//'m' for Immobilizer (I is too similar to 1)
return "Baroque/" + b;
return b; //usual piece
}
- static get PIECES() {
- return ChessRules.PIECES.concat([V.IMMOBILIZER]);
- }
-
// No castling, but checks, so keep track of kings
setOtherVariables(fen) {
this.kingPos = { w: [-1, -1], b: [-1, -1] };
import { ChessRules } from "@/base_rules";
export const VariantRules = class CheckeredRules extends ChessRules {
- static getPpath(b) {
- return b[0] == "c" ? "Checkered/" + b : b;
- }
-
static board2fen(b) {
const checkered_codes = {
p: "s",
return ChessRules.PIECES.concat(["s", "t", "u", "c", "o"]);
}
+ getPpath(b) {
+ return b[0] == "c" ? "Checkered/" + b : b;
+ }
+
setOtherVariables(fen) {
super.setOtherVariables(fen);
// Local stack of non-capturing checkered moves:
}
}
if (m.vanish.length == 1) moves.push(m);
- //no capture
+ // No capture
else {
// A capture occured (m.vanish.length == 2)
m.appear[0].c = "c";
// Does m2 un-do m1 ? (to disallow undoing checkered moves)
oppositeMoves(m1, m2) {
return (
- !!m1 &&
+ m1 &&
m2.appear[0].c == "c" &&
m2.appear.length == 1 &&
m2.vanish.length == 1 &&
filterValid(moves) {
if (moves.length == 0) return [];
const color = this.turn;
+ const L = this.cmoves.length; //at least 1: init from FEN
return moves.filter(m => {
- const L = this.cmoves.length; //at least 1: init from FEN
if (this.oppositeMoves(this.cmoves[L - 1], m)) return false;
this.play(m);
const res = !this.underCheck(color);
}
// Used by the interface:
- getReservePpath(color, index) {
+ getReservePpath(index, color) {
return color + V.RESERVE_PIECES[index];
}
V.OnBoard(i + pawnShift[color], j + shiftY) &&
this.board[i + pawnShift[color]][j + shiftY] == V.EMPTY
) {
- this.enlightened[color][i + pawnShift[color]][
- j + shiftY
- ] = true;
+ this.enlightened[color][i + pawnShift[color]][j + shiftY] = true;
}
}
}
return potentialMoves; //because there are no checks
}
- atLeastOneMove() {
- if (this.kingPos[this.turn][0] < 0) return false;
- return true; //TODO: is it right?
- }
-
- underCheck() {
- return false; //there is no check
- }
-
getCheckSquares() {
return [];
}
updateVariables(move) {
super.updateVariables(move);
- if (move.vanish.length >= 2 && move.vanish[1].p == V.KING) {
- // We took opponent king ! (because if castle vanish[1] is a rook)
+ if (move.vanish.length >= 2 && move.vanish[1].p == V.KING)
+ // We took opponent king (because if castle vanish[1] is a rook)
this.kingPos[this.turn] = [-1, -1];
- }
// Update lights for both colors:
this.updateEnlightened();
super.unupdateVariables(move);
const c = move.vanish[0].c;
const oppCol = V.GetOppCol(c);
- if (this.kingPos[oppCol][0] < 0) {
- // Last move took opponent's king
- for (let psq of move.vanish) {
- if (psq.p == "k") {
- this.kingPos[oppCol] = [psq.x, psq.y];
- break;
- }
- }
- }
+ if (this.kingPos[oppCol][0] < 0)
+ // Last move took opponent's king:
+ this.kingPos[oppCol] = [move.vanish[1].x, move.vanish[1].y];
// Update lights for both colors:
this.updateEnlightened();
const color = this.turn;
const kp = this.kingPos[color];
if (kp[0] < 0)
- //king disappeared
+ // King disappeared
return color == "w" ? "0-1" : "1-0";
- if (this.atLeastOneMove())
- // game not over
- return "*";
- return "1/2"; //no moves but kings still there (seems impossible)
+ // Assume that stalemate is impossible (I think so. Would need proof...)
+ return "*";
}
static get THRESHOLD_MATE() {
// NOTE: initial setup differs from the original; see
// https://www.chessvariants.com/large.dir/freeling.html
export const VariantRules = class GrandRules extends ChessRules {
- static getPpath(b) {
- return ([V.MARSHALL, V.CARDINAL].includes(b[1]) ? "Grand/" : "") + b;
- }
-
static IsGoodFen(fen) {
if (!ChessRules.IsGoodFen(fen)) return false;
const fenParsed = V.ParseFen(fen);
return Object.assign(ChessRules.ParseFen(fen), { captured: fenParts[5] });
}
+ getPpath(b) {
+ return ([V.MARSHALL, V.CARDINAL].includes(b[1]) ? "Grand/" : "") + b;
+ }
+
getFen() {
return super.getFen() + " " + this.getCapturedFen();
}
--- /dev/null
+import { ChessRules } from "@/base_rules";
+import { ArrayFun } from "@/utils/array";
+import { randInt } from "@/utils/alea";
+
+export const VariantRules = class HiddenRules extends ChessRules {
+ static get HasFlags() {
+ return false;
+ }
+
+ static get HasEnpassant() {
+ return false;
+ }
+
+ // Analyse in Hidden mode makes no sense
+ static get CanAnalyze() {
+ return false;
+ }
+
+ // Moves are revealed only when game ends
+ static get ShowMoves() {
+ return "none";
+ }
+
+ static get HIDDEN_DECODE() {
+ return {
+ s: "p",
+ t: "q",
+ u: "r",
+ c: "b",
+ o: "n",
+ l: "k"
+ };
+ }
+ static get HIDDEN_CODE() {
+ return {
+ p: "s",
+ q: "t",
+ r: "u",
+ b: "c",
+ n: "o",
+ k: "l"
+ };
+ }
+
+ static get PIECES() {
+ return ChessRules.PIECES.concat(Object.values(V.HIDDEN_CODE));
+ }
+
+ // Scan board for kings positions (no castling)
+ scanKingsRooks(fen) {
+ this.kingPos = { w: [-1, -1], b: [-1, -1] };
+ const fenRows = V.ParseFen(fen).position.split("/");
+ for (let i = 0; i < fenRows.length; i++) {
+ let k = 0; //column index on board
+ for (let j = 0; j < fenRows[i].length; j++) {
+ switch (fenRows[i].charAt(j)) {
+ case "k":
+ case "l":
+ this.kingPos["b"] = [i, k];
+ break;
+ case "K":
+ case "L":
+ this.kingPos["w"] = [i, k];
+ break;
+ default: {
+ const num = parseInt(fenRows[i].charAt(j));
+ if (!isNaN(num)) k += num - 1;
+ }
+ }
+ k++;
+ }
+ }
+ }
+
+ getPpath(b, color, score) {
+ if (Object.keys(V.HIDDEN_DECODE).includes(b[1])) {
+ // Supposed to be hidden.
+ if (score == "*" && (!color || color != b[0]))
+ return "Hidden/" + b[0] + "p";
+ // Else: condition OK to show the piece
+ return b[0] + V.HIDDEN_DECODE[b[1]];
+ }
+ // The piece is already not supposed to be hidden:
+ return b;
+ }
+
+ //getPotentialMovesFrom: TODO: write
+
+ // TODO: bishops on different colors, a1 --> h1, h2 --> a2 ?
+ static GenRandInitFen() {
+ let pieces = { w: new Array(8), b: new Array(8) };
+ // Shuffle pieces + pawns on two first ranks
+ for (let c of ["w", "b"]) {
+ let positions = ArrayFun.range(16);
+
+ // Get random squares for bishops
+ let randIndex = 2 * randInt(8);
+ const bishop1Pos = positions[randIndex];
+ // The second bishop must be on a square of different color
+ let randIndex_tmp = 2 * randInt(8) + 1;
+ const bishop2Pos = positions[randIndex_tmp];
+ // Remove chosen squares
+ positions.splice(Math.max(randIndex, randIndex_tmp), 1);
+ positions.splice(Math.min(randIndex, randIndex_tmp), 1);
+
+ // Get random squares for knights
+ randIndex = randInt(14);
+ const knight1Pos = positions[randIndex];
+ positions.splice(randIndex, 1);
+ randIndex = randInt(13);
+ const knight2Pos = positions[randIndex];
+ positions.splice(randIndex, 1);
+
+ // Get random square for queen
+ randIndex = randInt(12);
+ const queenPos = positions[randIndex];
+ positions.splice(randIndex, 1);
+
+ // Get random squares for pawns
+ // TODO...
+
+ // Rooks and king positions are now fixed,
+ // because of the ordering rook-king-rook
+ const rook1Pos = positions[0];
+ const kingPos = positions[1];
+ const rook2Pos = positions[2];
+
+ // Finally put the shuffled pieces in the board array
+ pieces[c][rook1Pos] = "r";
+ pieces[c][knight1Pos] = "n";
+ pieces[c][bishop1Pos] = "b";
+ pieces[c][queenPos] = "q";
+ pieces[c][kingPos] = "k";
+ pieces[c][bishop2Pos] = "b";
+ pieces[c][knight2Pos] = "n";
+ pieces[c][rook2Pos] = "r";
+ }
+ return (
+ pieces["b"].join("") +
+ "/pppppppp/8/8/8/8/PPPPPPPP/" +
+ pieces["w"].join("").toUpperCase() +
+ " w 0"
+ );
+ }
+
+ getCheckSquares() {
+ return [];
+ }
+
+ updateVariables(move) {
+ super.updateVariables(move);
+ if (
+ move.vanish.length >= 2 &&
+ [V.KING,V.HIDDEN_CODE[V.KING]].includes(move.vanish[1].p)
+ ) {
+ // We took opponent king
+ this.kingPos[this.turn] = [-1, -1];
+ }
+ }
+
+ unupdateVariables(move) {
+ super.unupdateVariables(move);
+ const c = move.vanish[0].c;
+ const oppCol = V.GetOppCol(c);
+ if (this.kingPos[oppCol][0] < 0)
+ // Last move took opponent's king:
+ this.kingPos[oppCol] = [move.vanish[1].x, move.vanish[1].y];
+ }
+
+ getCurrentScore() {
+ const color = this.turn;
+ const kp = this.kingPos[color];
+ if (kp[0] < 0)
+ // King disappeared
+ return color == "w" ? "0-1" : "1-0";
+ // Assume that stalemate is impossible:
+ return "*";
+ }
+
+ getComputerMove() {
+ // Just return a random move. TODO: something smarter...
+ const moves = this.getAllValidMoves();
+ return moves[randInt(moves.length)];
+ }
+};
}
// Used by the interface:
- getReservePpath(color, index) {
+ getReservePpath(index, color) {
return color + V.RESERVE_PIECES[index];
}
import { ChessRules, PiPo, Move } from "@/base_rules";
-export const VariantRules = class AntimatterRules extends ChessRules {
+export const VariantRules = class SuctionRules extends ChessRules {
+ setOtherVariables(fen) {
+ super.setOtherVariables(fen);
+ // Local stack of captures
+ this.cmoves = [];
+ const cmove = fen.split(" ")[5];
+ if (cmove == "-") this.cmoves.push(null);
+ else {
+ this.cmoves.push({
+ start: ChessRules.SquareToCoords(cmove.substr(0, 2)),
+ end: ChessRules.SquareToCoords(cmove.substr(2))
+ });
+ }
+ }
+
+ static IsGoodFen(fen) {
+ if (!ChessRules.IsGoodFen(fen)) return false;
+ const fenParts = fen.split(" ");
+ if (fenParts.length != 6) return false;
+ if (fenParts[5] != "-" && !fenParts[5].match(/^([a-h][1-8]){2}$/))
+ return false;
+ return true;
+ }
+
+ getCmove(move) {
+ if (move.vanish.length == 2)
+ return { start: move.start, end: move.end };
+ return null;
+ }
+
getBasicMove([sx, sy], [ex, ey]) {
const startColor = this.getColor(sx, sy);
const startPiece = this.getPiece(sx, sy);
return [];
}
+ // Does m2 un-do m1 ? (to disallow undoing captures)
+ oppositeMoves(m1, m2) {
+ return (
+ m1 &&
+ m2.vanish.length == 2 &&
+ m1.start.x == m2.start.x &&
+ m1.end.x == m2.end.x &&
+ m1.start.y == m2.start.y &&
+ m1.end.y == m2.end.y
+ );
+ }
+
+ filterValid(moves) {
+ if (moves.length == 0) return [];
+ const color = this.turn;
+ return moves.filter(m => {
+ const L = this.cmoves.length; //at least 1: init from FEN
+ return !this.oppositeMoves(this.cmoves[L - 1], m);
+ });
+ }
+
updateVariables(move) {
super.updateVariables(move);
if (move.vanish.length == 2) {
}
}
- atLeastOneMove() {
- return true;
+ static GenRandInitFen() {
+ // Add empty cmove:
+ return ChessRules.GenRandInitFen() + " -";
}
- filterValid(moves) {
- return moves;
+ getFen() {
+ const L = this.cmoves.length;
+ const cmoveFen = !this.cmoves[L - 1]
+ ? "-"
+ : ChessRules.CoordsToSquare(this.cmoves[L - 1].start) +
+ ChessRules.CoordsToSquare(this.cmoves[L - 1].end);
+ return super.getFen() + " " + cmoveFen;
+ }
+
+ play(move) {
+ this.cmoves.push(this.getCmove(move));
+ super.play(move);
+ }
+
+ undo(move) {
+ this.cmoves.pop();
+ super.undo(move);
+ }
+
+ atLeastOneMove() {
+ return true;
}
getCheckSquares() {
import { sample, randInt } from "@/utils/alea";
export const VariantRules = class WildebeestRules extends ChessRules {
- static getPpath(b) {
- return ([V.CAMEL, V.WILDEBEEST].includes(b[1]) ? "Wildebeest/" : "") + b;
- }
-
static get size() {
return { x: 10, y: 11 };
}
return true;
}
+ getPpath(b) {
+ return ([V.CAMEL, V.WILDEBEEST].includes(b[1]) ? "Wildebeest/" : "") + b;
+ }
+
// There may be 2 enPassant squares (if pawn jump 3 squares)
getEnpassantFen() {
const L = this.epSquares.length;
('Enpassant', 'Capture en passant'),
('Extinction', 'Capture all of a kind'),
('Grand', 'Big board'),
+ ('Hidden', 'Unidentified pieces'),
('Losers', 'Lose all pieces'),
('Magnetic', 'Laws of attraction'),
('Marseille', 'Move twice'),