From 204e289bbcddc69e2d81aef492dbea6db9e31188 Mon Sep 17 00:00:00 2001 From: Benjamin Auder <benjamin.auder@somewhere> Date: Tue, 20 Nov 2018 14:59:19 +0100 Subject: [PATCH] Fist draft of Antiking variant (still being debugged) --- public/javascripts/base_rules.js | 2 +- public/javascripts/components/game.js | 26 +++--- public/javascripts/variants/Antiking.js | 102 ++++++++++++++++++------ variants.js | 2 +- views/rules/Antiking.pug | 43 ++++++++++ 5 files changed, 136 insertions(+), 39 deletions(-) create mode 100644 views/rules/Antiking.pug diff --git a/public/javascripts/base_rules.js b/public/javascripts/base_rules.js index a4001225..8626b888 100644 --- a/public/javascripts/base_rules.js +++ b/public/javascripts/base_rules.js @@ -621,7 +621,7 @@ class ChessRules getCheckSquares(move) { this.play(move); - const color = this.turn; + const color = this.turn; //opponent let res = this.isAttacked(this.kingPos[color], this.getOppCol(color)) ? [ JSON.parse(JSON.stringify(this.kingPos[color])) ] //need to duplicate! : [ ]; diff --git a/public/javascripts/components/game.js b/public/javascripts/components/game.js index 9364c8d9..18632858 100644 --- a/public/javascripts/components/game.js +++ b/public/javascripts/components/game.js @@ -217,18 +217,21 @@ Vue.component('my-game', { ); }), choices] ); - actionArray.push( - h('button', - { - on: { click: this.resign }, - attrs: { "aria-label": 'Resign' }, - 'class': { - "tooltip":true, - "bottom": true, + if (this.mode != "idle") + { + actionArray.push( + h('button', + { + on: { click: this.resign }, + attrs: { "aria-label": 'Resign' }, + 'class': { + "tooltip":true, + "bottom": true, + }, }, - }, - [h('i', { 'class': { "material-icons": true } }, "flag")]) - ); + [h('i', { 'class': { "material-icons": true } }, "flag")]) + ); + } elementArray.push(gameDiv); // if (!!vr.reserve) // { @@ -494,6 +497,7 @@ Vue.component('my-game', { this.score = score; let modalBox = document.getElementById("modal-eog"); modalBox.checked = true; + // Variants may have special PGN structure (so next function isn't defined here) this.pgnTxt = this.vr.getPGN(this.mycolor, this.score, this.fenStart, this.mode); setTimeout(() => { modalBox.checked = false; }, 2000); if (this.mode == "human") diff --git a/public/javascripts/variants/Antiking.js b/public/javascripts/variants/Antiking.js index 360deafa..2770261a 100644 --- a/public/javascripts/variants/Antiking.js +++ b/public/javascripts/variants/Antiking.js @@ -1,4 +1,4 @@ -class AntikingRules +class AntikingRules extends ChessRules { // Path to pieces static getPpath(b) @@ -11,30 +11,55 @@ class AntikingRules initVariables(fen) { super.initVariables(fen); - // TODO: initialize this.antikingPos[...] + this.antikingPos = {'w':[-1,-1], 'b':[-1,-1]}; + const position = fen.split(" ")[0].split("/"); + for (let i=0; i<position.length; i++) + { + let j = 0; + while (j < position[i].length) + { + switch (position[i].charAt(j)) + { + case 'a': + this.antikingPos['b'] = [i,j]; + break; + case 'A': + this.antikingPos['w'] = [i,j]; + break; + default: + let num = parseInt(position[i].charAt(j)); + if (!isNaN(num)) + j += (num-1); + } + j++; + } + } } - canTake(color1, color2, [x,y]) + canTake([x1,y1], [x2,y2]) { - const piece = this.getPiece(x,y); - return (piece != "a" && color1 != color2) || (piece == "a" && color1 == color2); + const piece1 = this.getPiece(x1,y1); + const piece2 = this.getPiece(x2,y2); + const color1 = this.getColor(x1,y1); + const color2 = this.getColor(x2,y2); + return !["a","A"].includes(piece2) && + ((piece1 != "a" && color1 != color2) || (piece1 == "a" && color1 == color2)); } getPotentialMovesFrom([x,y]) { - let c = this.getColor(x,y); switch (this.getPiece(x,y)) { case VariantRules.ANTIKING: - return this.getPotentialAntikingMoves(x,y,c); + return this.getPotentialAntikingMoves([x,y]); default: - return super.getPotentielMovesFrom([x,y]); + return super.getPotentialMovesFrom([x,y]); } } - getPotentialAntikingMoves([x,y]) + getPotentialAntikingMoves(sq) { - // TODO + return this.getSlideNJumpMoves(sq, VariantRules.steps[VariantRules.QUEEN], "oneStep"); } isAttacked(sq, colors) @@ -42,49 +67,67 @@ class AntikingRules return (super.isAttacked(sq, colors) || this.isAttackedByAntiking(sq, colors)); } - isAttackedByAntiking(sq, color) + isAttackedByAntiking([x,y], colors) { - // TODO + console.log(x + " " + y); //TODO: debug -1, -1 (wrong undo ?!) + if (this.getPiece(x,y) == VariantRules.KING) + return false; //king is not attacked by antiking + return super.isAttackedBySlideNJump([x,y], colors, + VariantRules.ANTIKING, VariantRules.steps[VariantRules.QUEEN], "oneStep"); } underCheck(move) { const c = this.turn; - this.play(move); - let res = this.isAttacked(this.kingPos[c], this.getOppCol(c)); - // TODO: also check that antiking is still in check + const oppCol = this.getOppCol(c); + this.play(move) + let res = this.isAttacked(this.kingPos[c], oppCol) + || !this.isAttacked(this.antikingPos[c], oppCol); this.undo(move); return res; } getCheckSquares(move) { + let res = super.getCheckSquares(move); this.play(move); const c = this.turn; - // TODO - let res = this.isAttacked(this.kingPos[c], this.getOppCol(c)) - ? [ JSON.parse(JSON.stringify(this.kingPos[c])) ] - : [ ]; + if (!this.isAttacked(this.antikingPos[c], this.getOppCol(c))) + res.push(JSON.parse(JSON.stringify(this.antikingPos[c]))); this.undo(move); return res; } - // TODO: need antikingPos as well updateVariables(move) { - // ... + super.updateVariables(move); + const piece = this.getPiece(move.start.x,move.start.y); + const c = this.getColor(move.start.x,move.start.y); + // Update antiking position + if (piece == VariantRules.ANTIKING) + { + this.antikingPos[c][0] = move.appear[0].x; + this.antikingPos[c][1] = move.appear[0].y; + } } unupdateVariables(move) { - // TODO + super.unupdateVariables(move); + const c = this.getColor(move.start.x,move.start.y); + if (this.getPiece(move.start.x,move.start.y) == VariantRules.ANTIKING) + this.antikingPos[c] = [move.start.x, move.start.y]; } - checkGameEnd(color) + checkGameEnd() { - // TODO - if (!this.isAttacked(this.kingPos[color], this.getOppCol(color))) + const color = this.turn; + const oppCol = this.getOppCol(color); + if (!this.isAttacked(this.kingPos[color], oppCol) + && this.isAttacked(this.antikingPos[color], oppCol)) + { return "1/2"; + } return color == "w" ? "0-1" : "1-0"; } @@ -104,7 +147,14 @@ class AntikingRules static GenRandInitFen() { let randFen = ChessRules.GenRandInitFen(); - // TODO: just add an antiking at random on 3rd ranks + // Black side + let antikingPos = _.random(7); + let ranks23 = "pppppppp/" + (antikingPos>0?antikingPos:"") + "A" + (antikingPos<7?7-antikingPos:""); + randFen = randFen.replace("pppppppp/8", ranks23); + // White side + antikingPos = _.random(7); + ranks23 = (antikingPos>0?antikingPos:"") + "a" + (antikingPos<7?7-antikingPos:"") + "/PPPPPPPP"; + randFen = randFen.replace("8/PPPPPPPP", ranks23); return randFen; } } diff --git a/variants.js b/variants.js index ed2b6bad..6c2f62cf 100644 --- a/variants.js +++ b/variants.js @@ -3,7 +3,7 @@ module.exports = [ { "name" : "Zen", "description" : "Reverse captures" }, { "name" : "Atomic", "description" : "Explosive captures" }, { "name" : "Chess960", "description" : "Standard rules" }, -// { "name" : "AntiKing", "description" : "Keep anti-king in check" }, + { "name" : "Antiking", "description" : "Keep antiking in check" }, // { "name" : "Magnetic", "description" : "Laws of attraction" }, // { "name" : "Alice", "description" : "Both sides of the mirror" }, // { "name" : "Grand", "description" : "Big board" }, diff --git a/views/rules/Antiking.pug b/views/rules/Antiking.pug new file mode 100644 index 00000000..eda7db44 --- /dev/null +++ b/views/rules/Antiking.pug @@ -0,0 +1,43 @@ +p.boxed + | You have a king and an antiking. King must stay away from checks, but antiking must always stay in check. + | Antiking captures his own kind. + +h3 Specifications + +ul + li Chessboard: standard. + li Material: additional antiking. + li Non-capturing moves: standard. + li Special moves: standard. + li Captures: special case of antiking (see below). + li End of game: Checkmate or anti-checkmate. + +h3 Basics + +p + | The additional piece is a royal figure, thus cannot be captured. + | It captures the pieces of his color (to help checkmate opponent antiking, but by doing so it also make standard checkmate more difficult...). + | It should always remains under check (if it cannot, game is over). + +figure.diagram-container + .diagram + | fen:rnbqkbnr/pppppppp/3A4/8/8/3a4/PPPPPPPP/RNBQKBNR: + figcaption Initial position (non-random). 1.Ae5 is forbidden. + +h3 End of the game + +p There are two ways to win: +ol + li Checkmate opponent king + li Anti-checkmate opponent antiking +p ...Or maybe do both at the same time? + +p Note 1: athough antiking captures his color, it doesn't check his king. + +p Note 2: since it would allow a basic tactic (keep antiking touching opponent's king), kings do not attack antikings. + +h3 Credits + +p + a(href="https://www.chessvariants.com/diffobjective.dir/anti-king-chess.html") Antiking chess + | on chessvariants.com. -- 2.44.0