From 1b56b73614509d1dca8c4353f18fb78349940cf8 Mon Sep 17 00:00:00 2001 From: Benjamin Auder Date: Wed, 27 May 2020 04:35:23 +0200 Subject: [PATCH] Experimental in-place reorientation for Eightpieces + small fixes in BaseGame --- client/src/components/BaseGame.vue | 65 ++++++----- .../src/translations/rules/Balaklava/en.pug | 3 +- .../src/translations/rules/Balaklava/es.pug | 1 + .../src/translations/rules/Balaklava/fr.pug | 1 + .../src/translations/rules/Eightpieces/en.pug | 5 + .../src/translations/rules/Eightpieces/es.pug | 5 + .../src/translations/rules/Eightpieces/fr.pug | 5 + client/src/variants/Eightpieces.js | 107 +++++++++++++++++- 8 files changed, 156 insertions(+), 36 deletions(-) diff --git a/client/src/components/BaseGame.vue b/client/src/components/BaseGame.vue index 87d18aba..61c67dec 100644 --- a/client/src/components/BaseGame.vue +++ b/client/src/components/BaseGame.vue @@ -230,33 +230,34 @@ export default { const firstMoveColor = parsedFen.turn; this.firstMoveNumber = Math.floor(parsedFen.movesCount / 2) + 1; let L = this.moves.length; - if (L == 0) { - // Could be started on a random position in analysis mode: - this.incheck = this.vr.getCheckSquares(); - this.score = this.vr.getCurrentScore(); - if (this.score != '*') { - // Show score on screen - const message = getScoreMessage(this.score); - this.showEndgameMsg(this.score + " . " + this.st.tr[message]); - } - } - else { - this.moves.forEach((move,idx) => { - // Strategy working also for multi-moves: - if (!Array.isArray(move)) move = [move]; - const Lm = move.length; - move.forEach((m,idxM) => { - m.notation = this.vr.getNotation(m); - m.unambiguous = V.GetUnambiguousNotation(m); - this.vr.play(m); - const checkSquares = this.vr.getCheckSquares(); - if (checkSquares.length > 0) m.notation += "+"; - if (idxM == Lm - 1) m.fen = this.vr.getFen(); - if (idx == L - 1 && idxM == Lm - 1) this.incheck = checkSquares; - }); - this.score = this.vr.getCurrentScore(); - if (["1-0", "0-1"].includes(this.score)) m.notation += "#"; + this.moves.forEach((move,idx) => { + // Strategy working also for multi-moves: + if (!Array.isArray(move)) move = [move]; + move.forEach(m => { + m.notation = this.vr.getNotation(m); + m.unambiguous = V.GetUnambiguousNotation(m); + this.vr.play(m); }); + const Lm = move.length; + move[Lm - 1].fen = this.vr.getFen(); + if (idx < L - 1 && this.vr.getCheckSquares().length > 0) + move[Lm - 1].notation += "+"; + }); + this.incheck = this.vr.getCheckSquares(); + this.score = this.vr.getCurrentScore(); + if (L >= 1) { + const move = + !Array.isArray(this.moves[L - 1]) + ? [this.moves[L - 1]] + : this.moves[L - 1]; + const Lm = move.length; + if (["1-0", "0-1"].includes(this.score)) move[Lm - 1].notation += "#"; + else if (this.incheck.length > 0) move[Lm - 1].notation += "+"; + } + if (this.score != '*') { + // Show score on screen + const message = getScoreMessage(this.score); + this.showEndgameMsg(this.score + " . " + this.st.tr[message]); } if (firstMoveColor == "b") { // 'start' & 'end' is required for Board component @@ -431,8 +432,11 @@ export default { }, clickSquare: function(square) { // Some variants make use of a single click at specific times: - const move = this.vr.doClick(square); - if (!!move) this.play(move); + const move_s = this.vr.doClick(square); + if (!!move_s) { + if (!Array.isArray(move_s)) this.play(move_s); + else this.$refs["board"].choices = move_s; + } }, // "light": if gotoMove() or gotoEnd() play: function(move, received, light, autoplay) { @@ -480,9 +484,6 @@ export default { this.lastMove = [this.lastMove, smove]; else this.lastMove.push(smove); } - // Is opponent (or me) in check? - this.incheck = this.vr.getCheckSquares(); - if (this.incheck.length > 0) smove.notation += "+"; if (!this.inMultimove) { // First sub-move: this.lastMove = smove; @@ -555,6 +556,8 @@ export default { smove.fen = this.vr.getFen(); this.emitFenIfAnalyze(); this.inMultimove = false; + this.incheck = this.vr.getCheckSquares(); + if (this.incheck.length > 0) smove.notation += "+"; this.score = computeScore(); if (this.autoplay) { if (this.cursor < this.moves.length - 1) diff --git a/client/src/translations/rules/Balaklava/en.pug b/client/src/translations/rules/Balaklava/en.pug index 6ed42f5b..aef3a7aa 100644 --- a/client/src/translations/rules/Balaklava/en.pug +++ b/client/src/translations/rules/Balaklava/en.pug @@ -2,8 +2,9 @@ p.boxed | Pieces can also move as a knight. The knight is replaced by a mammoth. p. - In addition to their usual abilities, pawns and non-royal pieces (eveything + In addition to their usual abilities, pawns and non-royal pieces (everything but the king) may make non-capturing knight moves. + Pawns move forward only. p. The new piece instead of the knight is a Mammoth: it leaps two squares in diff --git a/client/src/translations/rules/Balaklava/es.pug b/client/src/translations/rules/Balaklava/es.pug index 1218cf44..84079674 100644 --- a/client/src/translations/rules/Balaklava/es.pug +++ b/client/src/translations/rules/Balaklava/es.pug @@ -5,6 +5,7 @@ p.boxed p. Además de sus habilidades habituales, peones y piezas no reales (todo excepto el rey) puede hacer saltos de caballo non capturado. + Los peones solo avanzan. p. La nueva pieza reemplaza para el caballo es un Mamut: salta dos diff --git a/client/src/translations/rules/Balaklava/fr.pug b/client/src/translations/rules/Balaklava/fr.pug index 8b22d698..c5a155f3 100644 --- a/client/src/translations/rules/Balaklava/fr.pug +++ b/client/src/translations/rules/Balaklava/fr.pug @@ -5,6 +5,7 @@ p.boxed p. En plus de leurs capacités habituelles, les pions et pièces non royales (tout sauf le roi) peuvent effectuer des coups de cavalier non capturants. + Les pions ne se déplacent que vers l'avant. p. La nouvelle pièce remplaçant le cavalier est un Mammouth : il saute de deux diff --git a/client/src/translations/rules/Eightpieces/en.pug b/client/src/translations/rules/Eightpieces/en.pug index 66105525..c1d12abe 100644 --- a/client/src/translations/rules/Eightpieces/en.pug +++ b/client/src/translations/rules/Eightpieces/en.pug @@ -32,6 +32,11 @@ figure.diagram-container | fen:7k/8/8/8/Jm3S2/8/8/K7: figcaption Left: before white move S"push"f4. Right: after this move. +p To reorient a stuck lancer, +ul + li Just after being pushed: play a move which 'capture your king". + li Later in the game: click on the lancer. + h3 Complete rules p diff --git a/client/src/translations/rules/Eightpieces/es.pug b/client/src/translations/rules/Eightpieces/es.pug index 9ef6a66f..6299266e 100644 --- a/client/src/translations/rules/Eightpieces/es.pug +++ b/client/src/translations/rules/Eightpieces/es.pug @@ -38,6 +38,11 @@ figure.diagram-container Izquierda: antes del movimiento blanco S"empuja"f4. Derecha: después de esta jugada. +p Para redirigir una lanza atascada, +ul + li Justo después de ser empujado: haz un movimiento que "capture a tu rey". + li Más adelante en el juego: haz clic en la lanza. + h3 Reglas completas p diff --git a/client/src/translations/rules/Eightpieces/fr.pug b/client/src/translations/rules/Eightpieces/fr.pug index a91103b1..d03e5342 100644 --- a/client/src/translations/rules/Eightpieces/fr.pug +++ b/client/src/translations/rules/Eightpieces/fr.pug @@ -35,6 +35,11 @@ figure.diagram-container | fen:7k/8/8/8/Jm3S2/8/8/K7: figcaption Gauche : avant le coup blanc S"pousse"f4. Droite : après ce coup. +p Pour réorienter un lancier coincé, +ul + li Juste après avoir été poussé : jouez un coup qui "capture votre roi". + li Plus tard dans le jeu : cliquez sur le lancier. + h3 Règles complètes p diff --git a/client/src/variants/Eightpieces.js b/client/src/variants/Eightpieces.js index 8cf8747a..6efb182f 100644 --- a/client/src/variants/Eightpieces.js +++ b/client/src/variants/Eightpieces.js @@ -317,9 +317,9 @@ export class EightpiecesRules extends ChessRules { } getPotentialMovesFrom([x, y]) { - // At subTurn == 2, jailers aren't effective (Jeff K) const piece = this.getPiece(x, y); const L = this.sentryPush.length; + // At subTurn == 2, jailers aren't effective (Jeff K) if (this.subTurn == 1) { const jsq = this.isImmobilized([x, y]); if (!!jsq) { @@ -473,6 +473,60 @@ export class EightpiecesRules extends ChessRules { return moves; } + doClick(square) { + if (isNaN(square[0])) return null; + const L = this.sentryPush.length; + const [x, y] = [square[0], square[1]]; + const color = this.turn; + if ( + this.subTurn == 2 || + this.board[x][y] == V.EMPTY || + this.getPiece(x, y) != V.LANCER || + this.getColor(x, y) != color || + !!this.sentryPush[L-1] + ) { + return null; + } + // Stuck lancer? + const orientation = this.board[x][y][1]; + const step = V.LANCER_DIRS[orientation]; + if (!V.OnBoard(x + step[0], y + step[1])) { + let choices = []; + Object.keys(V.LANCER_DIRS).forEach(k => { + const dir = V.LANCER_DIRS[k]; + if ( + (dir[0] != step[0] || dir[1] != step[1]) && + V.OnBoard(x + dir[0], y + dir[1]) + ) { + choices.push( + new Move({ + vanish: [ + new PiPo({ + x: x, + y: y, + c: color, + p: orientation + }) + ], + appear: [ + new PiPo({ + x: x, + y: y, + c: color, + p: k + }) + ], + start: { x: x, y : y }, + end: { x: -1, y: -1 } + }) + ); + } + }); + return choices; + } + return null; + } + // Obtain all lancer moves in "step" direction getPotentialLancerMoves_aux([x, y], step, tr) { let moves = []; @@ -502,6 +556,7 @@ export class EightpiecesRules extends ChessRules { // Except if just after a push: allow all movements from init square then const L = this.sentryPush.length; const color = this.getColor(x, y); + const dirCode = this.board[x][y][1]; if (!!this.sentryPush[L-1]) { // Maybe I was pushed const pl = this.sentryPush[L-1].length; @@ -512,7 +567,43 @@ export class EightpiecesRules extends ChessRules { // I was pushed: allow all directions (for this move only), but // do not change direction after moving, *except* if I keep the // same orientation in which I was pushed. - const curDir = V.LANCER_DIRS[this.board[x][y].charAt(1)]; + const curDir = V.LANCER_DIRS[dirCode]; + // Also allow simple reorientation ("capturing king"): + if (!V.OnBoard(x + curDir[0], y + curDir[1])) { + const kp = this.kingPos[color]; + let reorientMoves = []; + Object.keys(V.LANCER_DIRS).forEach(k => { + const dir = V.LANCER_DIRS[k]; + if ( + (dir[0] != curDir[0] || dir[1] != curDir[1]) && + V.OnBoard(x + dir[0], y + dir[1]) + ) { + reorientMoves.push( + new Move({ + vanish: [ + new PiPo({ + x: x, + y: y, + c: color, + p: dirCode + }) + ], + appear: [ + new PiPo({ + x: x, + y: y, + c: color, + p: k + }) + ], + start: { x: x, y : y }, + end: { x: kp[0], y: kp[1] } + }) + ); + } + }); + Array.prototype.push.apply(moves, reorientMoves); + } Object.values(V.LANCER_DIRS).forEach(step => { const dirCode = Object.keys(V.LANCER_DIRS).find(k => { return ( @@ -543,7 +634,6 @@ export class EightpiecesRules extends ChessRules { } } // I wasn't pushed: standard lancer move - const dirCode = this.board[x][y][1]; const monodirMoves = this.getPotentialLancerMoves_aux([x, y], V.LANCER_DIRS[dirCode]); // Add all possible orientations aftermove except if I'm being pushed @@ -1052,7 +1142,16 @@ export class EightpiecesRules extends ChessRules { end: move.end }; notation = super.getNotation(simpleMove); - } else notation = super.getNotation(move); + } + else if ( + move.appear.length > 0 && + move.vanish[0].x == move.appear[0].x && + move.vanish[0].y == move.appear[0].y + ) { + // Lancer in-place reorientation: + notation = "L" + V.CoordsToSquare(move.start) + ":R"; + } + else notation = super.getNotation(move); if (Object.keys(V.LANCER_DIRNAMES).includes(move.vanish[0].p)) // Lancer: add direction info notation += "=" + V.LANCER_DIRNAMES[move.appear[0].p]; -- 2.44.0