--- /dev/null
+https://commons.wikimedia.org/wiki/File:Go_w.svg
+https://commons.wikimedia.org/wiki/File:Go_b.svg
+(EDITED: remove yellow background)
--- /dev/null
+<?xml version="1.0"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="500" height="500">
+<defs><radialGradient id="rg" cx=".47" cy=".49" r=".48">
+<stop offset=".7" stop-color="#FFF"/>
+<stop offset=".9" stop-color="#DDD"/>
+<stop offset="1" stop-color="#777"/>
+</radialGradient></defs>
+<circle cx="250" cy="250" r="235" fill="url(#rg)"/>
+</svg>
--- /dev/null
+<?xml version="1.0"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="500" height="500">
+<defs><radialGradient id="rg" cx=".3" cy=".3" r=".8">
+<stop offset="0" stop-color="#777"/>
+<stop offset=".3" stop-color="#222"/>
+<stop offset="1" stop-color="#000"/>
+</radialGradient></defs>
+<circle cx="250" cy="250" r="235" fill="url(#rg)"/>
+</svg>
return false;
}
+ // At some stages, some games could wait clicks only:
+ onlyClick() {
+ return false;
+ }
+
// Some variants use click infos:
doClick() {
return null;
// Emit the click event which could be used by some variants
const targetId =
(withPiece ? e.target.parentNode.id : e.target.id);
- this.$emit("click-square", getSquareFromId(targetId));
- if (withPiece) {
+ const sq = getSquareFromId(targetId);
+ this.$emit("click-square", sq);
+ if (withPiece && !this.vr.onlyClick(sq)) {
this.possibleMoves = this.vr.getPossibleMovesFrom(startSquare);
// For potential drag'n drop, remember start coordinates
// (to center the piece on mouse cursor)
"A quantum story": "A quantum story",
"A wizard in the corner": "A wizard in the corner",
"Absorb powers": "Absorb powers",
+ "African Draughts": "African Draughts",
+ "Align five stones": "Align five stones",
"All of the same color": "All of the same color",
"Ancient rules": "Ancient rules",
"As in the movie": "As in the movie",
"Get strong at self-mate": "Get strong at self-mate",
"Give three checks": "Give three checks",
"Harassed kings": "Harassed kings",
+ "Hawaiian Checkers": "Hawaiian Checkers",
"Japanese Chess": "Japanese Chess",
"Jump the borders": "Jump the borders",
"Keep antiking in check (v1)": "Keep antiking in check (v1)",
"Long jumps over pieces": "Long jumps over pieces",
"Long live the Queen": "Long live the Queen",
"Lose all pieces": "Lose all pieces",
- "Rearrange enemy pieces": "Rearrange enemy pieces",
+ "Malagasy Draughts": "Malagasy Draughts",
"Mandatory captures": "Mandatory captures",
"Mate any piece (v1)": "Mate any piece (v1)",
"Mate any piece (v2)": "Mate any piece (v2)",
"Queen versus pawns": "Queen versus pawns",
"Reach the last rank (v1)": "Reach the last rank (v1)",
"Reach the last rank (v2)": "Reach the last rank (v2)",
+ "Rearrange enemy pieces": "Rearrange enemy pieces",
"Replace pieces": "Replace pieces",
"Reposition pieces": "Reposition pieces",
"Reuse pieces": "Reuse pieces",
"Squares disappear": "Squares disappear",
"Squat last rank (v1)": "Squat last rank (v1)",
"Squat last rank (v2)": "Squat last rank (v2)",
+ "Stacking Checkers variant": "Stacking Checkers variant",
"Standard rules": "Standard rules",
"Stun & kick pieces": "Stun & kick pieces",
"Thai Chess (v1)": "Thai Chess (v1)",
"A quantum story": "Una historia cuántica",
"A wizard in the corner": "Un mago en la esquina",
"Absorb powers": "Absorber poderes",
+ "African Draughts": "Damas africanas",
+ "Align five stones": "Alinea cinco piedras",
"All of the same color": "Todo el mismo color",
"Ancient rules": "Viejas reglas",
"As in the movie": "Como en la pelicula",
"Get strong at self-mate": "Progreso en mates asistidos",
"Give three checks": "Dar tres jaques",
"Harassed kings": "Reyes acosados",
+ "Hawaiian Checkers": "Damas hawaianas",
"Japanese Chess": "Ajedrez japonés",
"Jump the borders": "Saltar las fronteras",
"Keep antiking in check (v1)": "Mantener el antirey en jaque (v1)",
"Long jumps over pieces": "Saltos largos sobre las piezas",
"Long live the Queen": "Larga vida a la reina",
"Lose all pieces": "Perder todas las piezas",
- "Rearrange enemy pieces": "Reorganizar piezas opuestas",
+ "Malagasy Draughts": "Damas malgaches",
"Mandatory captures": "Capturas obligatorias",
"Mate any piece (v1)": "Matar cualquier pieza (v1)",
"Mate any piece (v2)": "Matar cualquier pieza (v2)",
"Queen versus pawns": "Dama contra peones",
"Reach the last rank (v1)": "Llegar a la última fila (v1)",
"Reach the last rank (v2)": "Llegar a la última fila (v2)",
+ "Rearrange enemy pieces": "Reorganizar piezas opuestas",
"Replace pieces": "Reemplazar piezas",
"Reposition pieces": "Reposicionar las piezas",
"Reuse pieces": "Reutilizar piezas",
"Squares disappear": "Las casillas desaparecen",
"Squat last rank (v1)": "Ocupa la última fila (v1)",
"Squat last rank (v2)": "Ocupa la última fila (v2)",
+ "Stacking Checkers variant": "Variante de damas con pilas",
"Standard rules": "Reglas estandar",
"Stun & kick pieces": "Aturdir & patear piezas",
"Thai Chess (v1)": "Ajedrez tailandés (v1)",
"A quantum story": "Une histoire quantique",
"A wizard in the corner": "Un sorcier dans le coin",
"Absorb powers": "Absorber les pouvoirs",
+ "African Draughts": "Dames africaines",
+ "Align five stones": "Alignez cinq pierres",
"All of the same color": "Tout de la même couleur",
"Ancient rules": "Règles anciennes",
"As in the movie": "Comme dans le film",
"Get strong at self-mate": "Progressez en mats aidés",
"Give three checks": "Donnez trois échecs",
"Harassed kings": "Rois harcelés",
+ "Hawaiian Checkers": "Dames hawaïennes",
"Japanese Chess": "Échecs japonais",
"Jump the borders": "Sauter les frontières",
"Keep antiking in check (v1)": "Gardez l'antiroi en échec (v1)",
"Long jumps over pieces": "Sauts longs par dessus les pièces",
"Long live the Queen": "Long vie à la Reine",
"Lose all pieces": "Perdez toutes les pièces",
- "Rearrange enemy pieces": "Réorganisez les pièces adverses",
+ "Malagasy Draughts": "Dames malgaches",
"Mandatory captures": "Captures obligatoires",
"Mate any piece (v1)": "Matez n'importe quelle pièce (v1)",
"Mate any piece (v2)": "Matez n'importe quelle pièce (v2)",
"Queen versus pawns": "Dame contre pions",
"Reach the last rank (v1)": "Atteignez la dernière rangée (v1)",
"Reach the last rank (v2)": "Atteignez la dernière rangée (v2)",
+ "Rearrange enemy pieces": "Réorganisez les pièces adverses",
"Replace pieces": "Remplacer les pièces",
"Reposition pieces": "Replacer les pièces",
"Reuse pieces": "Réutiliser les pièces",
"Squares disappear": "Les cases disparaissent",
"Squat last rank (v1)": "Occupez la dernière rangée (v1)",
"Squat last rank (v2)": "Occupez la dernière rangée (v2)",
+ "Stacking Checkers variant": "Variante des Dames avec empilements",
"Standard rules": "Règles usuelles",
"Stun & kick pieces": "Étourdissez & frappez les pièces",
"Thai Chess (v1)": "Échecs thai (v1)",
--- /dev/null
+p.boxed
+ | TODO
--- /dev/null
+p.boxed
+ | TODO
--- /dev/null
+p.boxed
+ | TODO
--- /dev/null
+p.boxed
+ | TODO
--- /dev/null
+p.boxed
+ | TODO
--- /dev/null
+p.boxed
+ | TODO
--- /dev/null
+p.boxed
+ | TODO
--- /dev/null
+p.boxed
+ | TODO
--- /dev/null
+p.boxed
+ | TODO
--- /dev/null
+p.boxed
+ | Capture orthogonally at each turn, "as in Draughts".
+ | If you cannot capture, you lose.
+
+p.
+ To initiate the game, the first player (black) must remove one of his stones
+ either in the upper left or lower right corner, or in the center,
+ as marked on the illustration.
+ The second player (white) then removes a stone orthogonally adjacent to
+ the first removed one, and the game starts.
+ To remove a stone at this stage, click it.
+
+figure.diagram-container
+ .diagram
+ | fen:PpPpPpPp/pPpPpPpP/PpPpPpPp/pPpPpPpP/PpPpPpPp/pPpPpPpP/PpPpPpPp/pPpPpPpP a8,d5,e4,h1:
+ figcaption Allowed first "moves" (stone removal).
+
+p.
+ Every move then is necessary a capture of at least one enemy piece.
+ Capture by jumping orthogonally over an adjacent stone to land right after
+ on an empty square. The intermediate piece is thus removed.
+ You may continue capturing, but only in the same direction,
+ with the same stone.
+ To stop a chain of captures (while more are available), play a move from the
+ current capturer until the location of the last captured stone:
+ g4 on this example.
+
+figure.diagram-container
+ .diagram.diag12
+ | fen:PpPpPpPp/pPpPpPpP/PpPpP2p/pPpPp1pP/PpP1Pp1p/pPpPpP1P/PpPpPpPp/pPpPpPpP:
+ .diagram.diag22
+ | fen:PpPpPp1p/pPpPpP1P/PpPpP1Pp/pPpPp1pP/PpP1Pp1p/pPpPpP1P/PpPpPpPp/pPpPpPpP g4,g7:
+ figcaption.
+ Before and after a first capture g8xg7.
+ The available continuations are indicated.
+
+p If a player has no possible capture, he loses.
+
+h3 More information
+
+p
+ | See for example
+ a(href="https://hawaiiancheckers.com/") hawaiiancheckers.com
+ | , and an
+ a(href="https://www.youtube.com/watch?app=desktop&v=-_y-B2wAwyw")
+ | example game
+ | . Konane is also playable on
+ a(href="https://brainking.com/en/GameRules?tp=94") brainking.com
+ | .
--- /dev/null
+p.boxed
+ | Captura ortogonalmente en cada turno, "como a las Damas".
+ | Si no es posible la captura, ha perdido.
+
+p.
+ Para iniciar el juego, el primer jugador (negras) debe eliminar uno de
+ sus piedras en la esquina superior izquierda o inferior derecha,
+ ya sea en el centro, como se ilustra.
+ El segundo jugador (blancas) luego quita una piedra ortogonalmente
+ adyacente al primero eliminado, y comienza el juego.
+ Para quitar una piedra, haga clic en ella.
+
+figure.diagram-container
+ .diagram
+ | fen:PpPpPpPp/pPpPpPpP/PpPpPpPp/pPpPpPpP/PpPpPpPp/pPpPpPpP/PpPpPpPp/pPpPpPpP a8,d5,e4,h1:
+ figcaption Los primeros "movimientos" autorizado (eliminación de piedras).
+
+p.
+ Cada movimiento implica necesariamente la captura de al menos una pieza
+ enemiga. Captura saltando ortogonalmente sobre un obstáculo para aterrizar
+ en un cuadrado vacío justo detrás. Se quita así la pieza intermedia.
+ Tienes derecho a seguir capturando, pero solo en el mismo
+ dirección, con la misma piedra.
+ Para detener una cadena de capturas (mientras que otras son posibles),
+ hacer un movimiento de la captura actual a la ubicación de la última
+ pieza capturada: g4 en el ejemplo.
+
+figure.diagram-container
+ .diagram.diag12
+ | fen:PpPpPpPp/pPpPpPpP/PpPpP2p/pPpPp1pP/PpP1Pp1p/pPpPpP1P/PpPpPpPp/pPpPpPpP:
+ .diagram.diag22
+ | fen:PpPpPp1p/pPpPpP1P/PpPpP1Pp/pPpPp1pP/PpP1Pp1p/pPpPpP1P/PpPpPpPp/pPpPpPpP g4,g7:
+ figcaption.
+ Antes y después de una primera captura g8xg7.
+ Se indican las continuaciones disponibles.
+
+p Si un jugador no tiene más capturas disponibles, pierde.
+
+h3 Más información
+
+p
+ | Ver por ejemplo
+ a(href="https://hawaiiancheckers.com/") hawaiiancheckers.com
+ | , y una
+ a(href="https://www.youtube.com/watch?app=desktop&v=-_y-B2wAwyw")
+ | partida ejemplo
+ | . Konane también se puede jugar en
+ a(href="https://brainking.com/en/GameRules?tp=94") brainking.com
+ | .
--- /dev/null
+p.boxed
+ | Capturez orthogonalement à chaque tour, "comme aux Dames".
+ | Si aucune capture n'est possible, vous avez perdu.
+
+p.
+ Pour initialiser la partie, le premier joueur (noirs) doit retirer une de
+ ses pierres soit dans le coin supérieur gauche ou inférieur droit,
+ soit au centre, comme illustré.
+ Le second joueur (blancs) retire ensuite une pierre orthogonalement
+ adjacente à la première supprimée, et la partie commence.
+ Pour enlever une pierre, cliquez dessus.
+
+figure.diagram-container
+ .diagram
+ | fen:PpPpPpPp/pPpPpPpP/PpPpPpPp/pPpPpPpP/PpPpPpPp/pPpPpPpP/PpPpPpPp/pPpPpPpP a8,d5,e4,h1:
+ figcaption Premiers "coups" autorisés (suppression de pierre).
+
+p.
+ Chaque coup comporte nécessairement au moins une capture de pièce ennemie.
+ Capturez en sautant orthogonalement par dessus un obstacle pour atterrir
+ sur une case vide juste derrière. La pièce intermédiaire est ainsi retirée.
+ Vous avez le droit de continuer de capturer, mais seulement dans la même
+ direction, avec la même pierre.
+ Pour arrêter une chaîne de captures (alors que d'autres sont possibles),
+ jouez un coup depuis le capturant actuel vers l'emplacement de la dernière
+ pièce capturée : g4 sur l'exemple.
+
+figure.diagram-container
+ .diagram.diag12
+ | fen:PpPpPpPp/pPpPpPpP/PpPpP2p/pPpPp1pP/PpP1Pp1p/pPpPpP1P/PpPpPpPp/pPpPpPpP:
+ .diagram.diag22
+ | fen:PpPpPp1p/pPpPpP1P/PpPpP1Pp/pPpPp1pP/PpP1Pp1p/pPpPpP1P/PpPpPpPp/pPpPpPpP g4,g7:
+ figcaption.
+ Avant et après une première capture g8xg7.
+ Les continuations disponibles sont indiquées.
+
+p Si un joueur n'a plus de captures à disposition, il perd.
+
+h3 Plus d'informations
+
+p
+ | Voir par exemple
+ a(href="https://hawaiiancheckers.com/") hawaiiancheckers.com
+ | , et une
+ a(href="https://www.youtube.com/watch?app=desktop&v=-_y-B2wAwyw")
+ | partie exemple
+ | . Konane est aussi jouable sur
+ a(href="https://brainking.com/en/GameRules?tp=94") brainking.com
+ | .
--- /dev/null
+p.boxed
+ | TODO
--- /dev/null
+p.boxed
+ | TODO
--- /dev/null
+p.boxed
+ | TODO
for v in varlist
li #[a(href="/#/variants/"+v) #{v}]
+h3 Non-chess
+
+p Some games not chess related.
+-
+ var varlist = [
+ "Emergo",
+ "Fanorona",
+ "Gomoku",
+ "Konane",
+ "Yote"
+ ]
+ul
+ for v in varlist
+ li #[a(href="/#/variants/"+v) #{v}]
+
h3 Miscelleanous
p.
for v in varlist
li #[a(href="/#/variants/"+v) #{v}]
+h3 Aparte del Ajedrez
+
+p Algunos juegos no están relacionados con el ajedrez.
+-
+ var varlist = [
+ "Emergo",
+ "Fanorona",
+ "Gomoku",
+ "Konane",
+ "Yote"
+ ]
+ul
+ for v in varlist
+ li #[a(href="/#/variants/"+v) #{v}]
+
h3 Varios
p.
for v in varlist
li #[a(href="/#/variants/"+v) #{v}]
+h3 Hors Échecs
+
+p Quelques jeux non connectés aux échecs.
+-
+ var varlist = [
+ "Emergo",
+ "Fanorona",
+ "Gomoku",
+ "Konane",
+ "Yote"
+ ]
+ul
+ for v in varlist
+ li #[a(href="/#/variants/"+v) #{v}]
+
h3 Divers
p.
);
}
+ onlyClick([x, y]) {
+ return (
+ this.movesCount <= 1 ||
+ // TODO: next line theoretically shouldn't be required...
+ (this.movesCount == 2 && this.getColor(x, y) != this.turn)
+ );
+ }
+
// Initiate the game by choosing a square for the king:
doClick(square) {
const c = this.turn;
appear: [
new PiPo({ x: square[0], y: square[1], c: c, p: V.KING })
],
- vanish: [],
+ vanish: [
+ new PiPo({ x: square[0], y: square[1], c: c, p: V.UNDEFINED })
+ ],
start: { x: -1, y: -1 },
});
}
}
static GenRandInitFen() {
- return "8/pppppppp/8/8/8/8/PPPPPPPP/8 w 0 - 22212221 -";
+ return "uuuuuuuu/pppppppp/8/8/8/8/PPPPPPPP/UUUUUUUU w 0 - 22212221 -";
}
setOtherVariables(fen) {
appear: [
new PiPo({ x: firstRank, y: j, c: color, p: V.KING })
],
- vanish: [],
+ vanish: [
+ new PiPo({ x: firstRank, y: j, c: color, p: V.UNDEFINED })
+ ],
start: { x: -1, y: -1 }
});
});
return false;
}
+ getCheckSquares() {
+ if (this.movesCount <= 2) return [];
+ return super.getCheckSquares();
+ }
+
play(move) {
move.turn = [this.turn, this.subTurn]; //easier undo (TODO?)
const toNextPlayer = () => {
this.movesCount++;
this.postPlay(move);
};
- if (move.vanish.length == 0) {
- if (move.appear.length == 1) toNextPlayer();
- else {
- // Removal (subTurn == 0 --> 1)
- this.reserve[this.turn][move.start.p]--;
- this.subTurn++;
- }
- return;
- }
- const start = { x: move.vanish[0].x, y: move.vanish[0].y };
- const end = { x: move.appear[0].x, y: move.appear[0].y };
- if (start.x == end.x && start.y == end.y) {
- // Specialisation (subTurn == 1 before 2)
- this.reserve[this.turn][move.appear[0].p]--;
- V.PlayOnBoard(this.board, move);
- this.definitions.push(move.end);
+ if (this.movesCount <= 1) toNextPlayer();
+ else if (move.vanish.length == 0) {
+ // Removal (subTurn == 0 --> 1)
+ this.reserve[this.turn][move.start.p]--;
this.subTurn++;
}
else {
- // Normal move (subTurn 1 or 2: change turn)
- this.epSquares.push(this.getEpSquare(move));
- toNextPlayer();
+ const start = { x: move.vanish[0].x, y: move.vanish[0].y };
+ const end = { x: move.appear[0].x, y: move.appear[0].y };
+ if (start.x == end.x && start.y == end.y) {
+ // Specialisation (subTurn == 1 before 2)
+ this.reserve[this.turn][move.appear[0].p]--;
+ V.PlayOnBoard(this.board, move);
+ this.definitions.push(move.end);
+ this.subTurn++;
+ }
+ else {
+ // Normal move (subTurn 1 or 2: change turn)
+ this.epSquares.push(this.getEpSquare(move));
+ toNextPlayer();
+ }
}
}
postPlay(move) {
const color = V.GetOppCol(this.turn);
- if (move.vanish.length == 0) {
- this.kingPos[color] = [move.end.x, move.end.y];
- const firstRank = (color == 'w' ? 7 : 0);
- for (let j = 0; j < 8; j++) {
- if (j != move.end.y) this.board[firstRank][j] = color + V.UNDEFINED;
- }
- }
+ if (this.movesCount <= 2) this.kingPos[color] = [move.end.x, move.end.y];
else {
if (move.vanish.length == 2 && move.vanish[1].p == V.UNDEFINED)
this.captureUndefined.push(move.end);
this.movesCount--;
this.postUndo(move);
};
- if (move.vanish.length == 0) {
- if (move.appear.length == 1) toPrevPlayer();
- else {
- this.reserve[this.turn][move.start.p]++;
- this.subTurn = move.turn[1];
- }
- return;
- }
- const start = { x: move.vanish[0].x, y: move.vanish[0].y };
- const end = { x: move.appear[0].x, y: move.appear[0].y };
- if (start.x == end.x && start.y == end.y) {
- this.reserve[this.turn][move.appear[0].p]++;
- V.UndoOnBoard(this.board, move);
- this.definitions.pop();
+ if (this.movesCount <= 2) toPrevPlayer();
+ else if (move.vanish.length == 0) {
+ this.reserve[this.turn][move.start.p]++;
this.subTurn = move.turn[1];
}
else {
- this.epSquares.pop();
- toPrevPlayer();
+ const start = { x: move.vanish[0].x, y: move.vanish[0].y };
+ const end = { x: move.appear[0].x, y: move.appear[0].y };
+ if (start.x == end.x && start.y == end.y) {
+ this.reserve[this.turn][move.appear[0].p]++;
+ V.UndoOnBoard(this.board, move);
+ this.definitions.pop();
+ this.subTurn = move.turn[1];
+ }
+ else {
+ this.epSquares.pop();
+ toPrevPlayer();
+ }
}
}
postUndo(move) {
const color = this.turn;
- if (move.vanish.length == 0) {
- this.kingPos[color] = [-1, -1];
- const firstRank = (color == 'w' ? 7 : 0);
- for (let j = 0; j < 8; j++) this.board[firstRank][j] = "";
- }
+ if (this.movesCount <= 1) this.kingPos[color] = [-1, -1];
else {
this.captureUndefined.pop();
if (move.appear[0].p == V.KING) super.postUndo(move);
--- /dev/null
+import { ChessRules } from "@/base_rules";
+
+export class YoteRules extends ChessRules {
+
+ // TODO
+
+};
--- /dev/null
+import { ChessRules } from "@/base_rules";
+
+export class FanoronaRules extends ChessRules {
+
+ // TODO
+
+};
--- /dev/null
+import { ChessRules } from "@/base_rules";
+
+export class GomokuRules extends ChessRules {
+
+ // TODO
+
+};
--- /dev/null
+import { ChessRules, Move, PiPo } from "@/base_rules";
+
+// TODO: Maybe more flexible end of game messages (V.ColorsReversed ?!)
+
+export class KonaneRules extends ChessRules {
+
+ static get HasFlags() {
+ return false;
+ }
+
+ static get HasEnpassant() {
+ return false;
+ }
+
+ static get PIECES() {
+ return V.PAWN;
+ }
+
+ getPpath(b) {
+ return "Konane/" + b;
+ }
+
+ static IsGoodPosition(position) {
+ if (position.length == 0) return false;
+ const rows = position.split("/");
+ if (rows.length != V.size.x) return false;
+ for (let row of rows) {
+ let sumElts = 0;
+ for (let i = 0; i < row.length; i++) {
+ if (V.PIECES.includes(row[i].toLowerCase())) sumElts++;
+ else {
+ const num = parseInt(row[i], 10);
+ if (isNaN(num) || num <= 0) return false;
+ sumElts += num;
+ }
+ }
+ if (sumElts != V.size.y) return false;
+ }
+ return true;
+ }
+
+ static GenRandInitFen() {
+ return (
+ "PpPpPpPp/pPpPpPpP/PpPpPpPp/pPpPpPpP/" +
+ "PpPpPpPp/pPpPpPpP/PpPpPpPp/pPpPpPpP w 0"
+ );
+ }
+
+ setOtherVariables(fen) {
+ this.captures = []; //reinit for each move
+ }
+
+ hoverHighlight(x, y) {
+ if (this.movesCount >= 2) return false;
+ const c = this.turn;
+ if (c == 'w') return (x == y && [0, 3, 4, 7].includes(x));
+ // "Black": search for empty square and allow nearby
+ for (let i of [0, 3, 4, 7]) {
+ if (this.board[i][i] == V.EMPTY)
+ return (Math.abs(x - i) + Math.abs(y - i) == 1)
+ }
+ }
+
+ onlyClick([x, y]) {
+ return (
+ this.movesCount <= 1 ||
+ // TODO: next line theoretically shouldn't be required...
+ (this.movesCount == 2 && this.getColor(x, y) != this.turn)
+ );
+ }
+
+ doClick([x, y]) {
+ if (this.movesCount >= 2) return null;
+ const color = this.turn;
+ if (color == 'w') {
+ if (x != y || ![0, 3, 4, 7].includes(x)) return null;
+ return new Move({
+ appear: [],
+ vanish: [ new PiPo({ x: x, y: y, c: color, p: V.PAWN }) ],
+ end: { x: x, y: y }
+ });
+ }
+ // "Black": search for empty square and allow nearby
+ for (let i of [0, 3, 4, 7]) {
+ if (this.board[i][i] == V.EMPTY) {
+ if (Math.abs(x - i) + Math.abs(y - i) != 1) return null;
+ return new Move({
+ appear: [],
+ vanish: [ new PiPo({ x: x, y: y, c: color, p: V.PAWN }) ],
+ end: { x: x, y: y }
+ });
+ }
+ }
+ }
+
+ getPotentialMovesFrom([x, y]) {
+ if (this.movesCount <= 1) {
+ const mv = this.doClick([x, y]);
+ return (!!mv ? [mv] : []);
+ }
+ const L = this.captures.length;
+ const c = (L > 0 ? this.captures[L-1] : null);
+ const color = this.turn;
+ const oppCol = V.GetOppCol(color);
+ let step = null;
+ let moves = [];
+ if (!!c) {
+ if (x != c.end.x || y != c.end.y) return [];
+ step = [(c.end.x - c.start.x) / 2, (c.end.y - c.start.y) / 2];
+ // Add move to adjacent empty square to mark "end of capture"
+ moves.push(
+ new Move({
+ appear: [],
+ vanish: [],
+ start: { x: x, y: y },
+ end: { x: x - step[0], y: y - step[1] }
+ })
+ );
+ }
+ // Examine captures from here
+ for (let s of (!!step ? [step] : V.steps[V.ROOK])) {
+ let [i, j] = [x + 2*s[0], y + 2*s[1]];
+ if (
+ !!c || //avoid redundant checks if continuation
+ (
+ V.OnBoard(i, j) &&
+ this.board[i][j] == V.EMPTY &&
+ this.board[i - s[0]][j - s[1]] != V.EMPTY &&
+ this.getColor(i - s[0], j - s[1]) == oppCol
+ )
+ ) {
+ let mv = new Move({
+ appear: [
+ new PiPo({ x: i, y: j, c: color, p: V.PAWN })
+ ],
+ vanish: [
+ new PiPo({ x: x, y: y, c: color, p: V.PAWN }),
+ new PiPo({ x: i - s[0], y: j - s[1], c: oppCol, p: V.PAWN })
+ ]
+ });
+ // Is there another capture possible then?
+ [i, j] = [i + 2*s[0], j + 2*s[1]];
+ if (
+ V.OnBoard(i, j) &&
+ this.board[i][j] == V.EMPTY &&
+ this.board[i - s[0]][j - s[1]] != V.EMPTY &&
+ this.getColor(i - s[0], j - s[1]) == oppCol
+ ) {
+ mv.end.moreCapture = true;
+ }
+ moves.push(mv);
+ }
+ }
+ return moves;
+ }
+
+ filterValid(moves) {
+ return moves;
+ }
+
+ getCheckSquares() {
+ return [];
+ }
+
+ getCurrentScore() {
+ if (this.atLeastOneMove()) return "*";
+ return (this.turn == "w" ? "0-1" : "1-0");
+ }
+
+ play(move) {
+ V.PlayOnBoard(this.board, move);
+ if (!move.end.moreCapture) {
+ this.turn = V.GetOppCol(this.turn);
+ this.movesCount++;
+ this.captures = [];
+ }
+ else {
+ this.captures.push(
+ {
+ start: move.start,
+ end: { x: move.end.x, y: move.end.y }
+ }
+ );
+ }
+ }
+
+ undo(move) {
+ V.UndoOnBoard(this.board, move);
+ if (!move.end.moreCapture) {
+ this.turn = V.GetOppCol(this.turn);
+ this.movesCount--;
+ }
+ else this.captures.pop();
+ }
+
+ static get SEARCH_DEPTH() {
+ return 4;
+ }
+
+ getNotation(move) {
+ if (this.movesCount <= 1) return V.CoordsToSquare(move.start) + "X";
+ if (move.vanish.length == 0) return "end";
+ return V.CoordsToSquare(move.start) + "x" + V.CoordsToSquare(move.end);
+ }
+
+};
if (!m.end.released) return true;
// Check for repetitions:
V.PlayOnBoard(this.board, m);
- const newState = { piece: m.end.released, position: this.getBaseFen() };
+ const newState = {
+ piece: m.end.released,
+ square: { x: m.end.x, y: m.end.y },
+ position: this.getBaseFen()
+ };
const repet =
this.repetitions.some(r => {
return (
r.piece == newState.piece &&
+ (
+ r.square.x == newState.square.x &&
+ r.square.y == newState.square.y &&
+ ) &&
r.position == newState.position
);
});
this.repetitions.push(
{
piece: move.end.released,
+ square: { x: move.end.x, y: move.end.y },
position: this.getBaseFen()
}
);
if (!m.end.released) return true;
// Check for repetitions:
V.PlayOnBoard(this.board, m);
- const newState = { piece: m.end.released, position: this.getBaseFen() };
+ const newState = {
+ piece: m.end.released,
+ square: { x: m.end.x, y: m.end.y },
+ position: this.getBaseFen()
+ };
const repet =
this.repetitions.some(r => {
return (
r.piece == newState.piece &&
+ (
+ r.square.x == newState.square.x &&
+ r.square.y == newState.square.y &&
+ ) &&
r.position == newState.position
);
});
this.repetitions.push(
{
piece: move.end.released,
+ square: { x: move.end.x, y: move.end.y },
position: this.getBaseFen()
}
);
const p2 = this.getPiece(x2, y2);
return (
p1 != p2 &&
- [V.QUEEN, V.ROOK, V.KNIGHT, V.BISHOP].includes(p1) &&
- [V.QUEEN, V.ROOK, V.KNIGHT, V.BISHOP].includes(p2) &&
+ [V.QUEEN, V.RN, V.BN, V.ROOK, V.KNIGHT, V.BISHOP].includes(p1) &&
+ [V.QUEEN, V.RN, V.BN, V.ROOK, V.KNIGHT, V.BISHOP].includes(p2) &&
(p1 != V.QUEEN || p2 == V.KNIGHT) &&
- (p2 != V.QUEEN || p1 == V.KNIGHT)
+ (p2 != V.QUEEN || p1 == V.KNIGHT) &&
+ (p1 != V.RN || p2 == V.BISHOP) &&
+ (p2 != V.RN || p1 == V.BISHOP) &&
+ (p1 != V.BN || p2 == V.ROOK) &&
+ (p2 != V.BN || p1 == V.ROOK)
);
}
--- /dev/null
+import { ChessRules } from "@/base_rules";
+
+export class YoteRules extends ChessRules {
+
+ // TODO
+
+};
('Doublemove2', 'Double moves (v2)'),
('Dynamo', 'Push and pull'),
('Eightpieces', 'Each piece is unique'),
+ ('Emergo', 'Stacking Checkers variant'),
('Empire', 'Empire versus Kingdom'),
('Enpassant', 'Capture en passant'),
('Evolution', 'Faster development'),
('Extinction', 'Capture all of a kind'),
+ ('Fanorona', 'Malagasy Draughts'),
('Football', 'Score a goal'),
('Forward', 'Moving forward'),
('Freecapture', 'Capture both colors'),
('Fugue', 'Baroque Music'),
('Fullcavalry', 'Lancers everywhere'),
('Fusion', 'Fusion pieces (v1)'),
+ ('Gomoku', 'Align five stones'),
('Grand', 'Big board'),
('Grasshopper', 'Long jumps over pieces'),
('Gridolina', 'Jump the borders'),
('Knightpawns', 'Knight versus pawns'),
('Knightrelay1', 'Move like a knight (v1)'),
('Knightrelay2', 'Move like a knight (v2)'),
+ ('Konane', 'Hawaiian Checkers'),
('Koopa', 'Stun & kick pieces'),
('Koth', 'King of the Hill'),
('Losers', 'Get strong at self-mate'),
('Wildebeest', 'Balanced sliders & leapers'),
('Wormhole', 'Squares disappear'),
('Xiangqi', 'Chinese Chess'),
+ ('Yote', 'African Draughts'),
('Zen', 'Reverse captures');