From: Benjamin Auder Date: Wed, 22 Jun 2022 09:53:09 +0000 (+0200) Subject: Add Alice Chess, fix a few things in base_rules.js X-Git-Url: https://git.auder.net/?p=xogo.git;a=commitdiff_plain;h=65cf1690c6119c949e2ea8feba8835b6e90b79a2 Add Alice Chess, fix a few things in base_rules.js --- diff --git a/base_rules.js b/base_rules.js index 4b387b6..a48bd3d 100644 --- a/base_rules.js +++ b/base_rules.js @@ -1082,8 +1082,9 @@ export default class ChessRules { } // Piece type on square (i,j) - getPieceType(i, j) { - const p = this.getPiece(i, j); + getPieceType(i, j, p) { + if (!p) + p = this.getPiece(i, j); return C.CannibalKings[p] || p; //a cannibal king move as... } @@ -1092,7 +1093,7 @@ export default class ChessRules { return (color == "w" ? "b" : "w"); } - // Can thing on square1 capture (no return) thing on square2? + // Can thing on square1 capture (enemy) thing on square2? canTake([x1, y1], [x2, y2]) { return (this.getColor(x1, y1) !== this.getColor(x2, y2)); } @@ -1214,6 +1215,8 @@ export default class ChessRules { if (this.board[i][j] != "" && this.getColor(i, j) == color) { const allSpecs = this.pieces(color, i, j) let specs = allSpecs[this.getPieceType(i, j)]; + if (specs.moveas) + specs = allSpecs[specs.moveas]; const attacks = specs.attack || specs.moves; for (let a of attacks) { outerLoop: for (let step of a.steps) { @@ -1482,7 +1485,10 @@ export default class ChessRules { const color = this.getColor(x, y); const oppCol = C.GetOppCol(color); const piece = this.getPieceType(x, y); //ok not cannibal king - const stepSpec = this.pieces(color, x, y)[piece]; + const allSpecs = this.pieces(color, x, y); + let stepSpec = allSpecs[piece]; + if (stepSpec.moveas) + stepSpec = allSpecs[stepSpec.moveas]; const attacks = stepSpec.attack || stepSpec.moves; for (let a of attacks) { outerLoop: for (let step of a.steps) { @@ -1506,7 +1512,7 @@ export default class ChessRules { return false; } - canStepOver(i, j) { + canStepOver(i, j, p) { // In some variants, objects on boards don't stop movement (Chakart) return this.board[i][j] == ""; } @@ -1514,7 +1520,11 @@ export default class ChessRules { // Generic method to find possible moves of "sliding or jumping" pieces getPotentialMovesOf(piece, [x, y]) { const color = this.getColor(x, y); - const stepSpec = this.pieces(color, x, y)[piece]; + const apparentPiece = this.getPiece(x, y); //how it looks + const allSpecs = this.pieces(color, x, y); + let stepSpec = allSpecs[piece]; + if (stepSpec.moveas) + stepSpec = allSpecs[stepSpec.moveas]; let moves = []; // Next 3 for Cylinder mode: let explored = {}; @@ -1539,7 +1549,7 @@ export default class ChessRules { let stepCounter = 0; while ( this.onBoard(i, j) && - (this.canStepOver(i, j) || (i == x && j == y)) + ((i == x && j == y) || this.canStepOver(i, j, apparentPiece)) ) { if ( type != "attack" && @@ -1610,8 +1620,14 @@ export default class ChessRules { ) { if (args.zen && this.isKing(this.getPiece(i, j))) continue; //king not captured in this way - const stepSpec = - this.pieces(args.oppCol, i, j)[this.getPieceType(i, j)]; + const apparentPiece = this.getPiece(i, j); + // Quick check: does this potential attacker target x,y ? + if (this.canStepOver(x, y, apparentPiece)) + continue; + const allSpecs = this.pieces(args.oppCol, i, j); + let stepSpec = allSpecs[this.getPieceType(i, j)]; + if (stepSpec.moveas) + stepSpec = allSpecs[stepSpec.moveas]; const attacks = stepSpec.attack || stepSpec.moves; for (let a of attacks) { for (let s of a.steps) { @@ -1754,8 +1770,15 @@ export default class ChessRules { s.y == e.y && Math.abs(s.x - e.x) == 2 && // Next conditions for variants like Atomic or Rifle, Recycle... - (move.appear.length > 0 && move.appear[0].p == "p") && - (move.vanish.length > 0 && move.vanish[0].p == "p") + ( + move.appear.length > 0 && + this.getPieceType(0, 0, move.appear[0].p) == "p" + ) + && + ( + move.vanish.length > 0 && + this.getPieceType(0, 0, move.vanish[0].p) == "p" + ) ) { return { x: (s.x + e.x) / 2, @@ -1945,12 +1968,12 @@ export default class ChessRules { let square = kingPos, res = true; //a priori valid if (m.vanish.some(v => { - return C.CannibalKings[v.p] && v.c == color; + return this.isKing(v.p) && v.c == color; })) { // Search king in appear array: const newKingIdx = m.appear.findIndex(a => { - return C.CannibalKings[a.p] && a.c == color; + return this.isKing(a.p) && a.c == color; }); if (newKingIdx >= 0) square = [m.appear[newKingIdx].x, m.appear[newKingIdx].y]; diff --git a/pieces/Ambiguous/red_target.svg b/pieces/Ambiguous/red_target.svg new file mode 100644 index 0000000..2f7bb8c --- /dev/null +++ b/pieces/Ambiguous/red_target.svg @@ -0,0 +1,78 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/pieces/Ambiguous/target.svg b/pieces/Ambiguous/target.svg deleted file mode 100644 index 53f0ccc..0000000 --- a/pieces/Ambiguous/target.svg +++ /dev/null @@ -1,191 +0,0 @@ - - - - Target - - - - - - - - - - - - - - image/svg+xml - - - - - Openclipart - - - Target - 2012-02-15T07:37:04 - Target symbol - https://openclipart.org/detail/168253/target-by-fanda@cz - - - Fanda@CZ - - - - - target - - - - - - - - - - - diff --git a/pieces/Ambiguous/yellow_target.svg b/pieces/Ambiguous/yellow_target.svg new file mode 100644 index 0000000..400b872 --- /dev/null +++ b/pieces/Ambiguous/yellow_target.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/pieces/Benedict/CREDITS b/pieces/Benedict/CREDITS new file mode 100644 index 0000000..7844bd6 --- /dev/null +++ b/pieces/Benedict/CREDITS @@ -0,0 +1,7 @@ +Unusable? +https://game-icons.net/1x1/delapouite/cleopatra.html +https://www.svgrepo.com/svg/322047/cleopatra + +PNG? or paying... +https://www.flaticon.com/free-icon/cleopatra_1393471 +https://www.flaticon.com/fr/icone-gratuite/cleopatre_1929899 diff --git a/pieces/Benedict/black_cleopatra.svg b/pieces/Benedict/black_cleopatra.svg deleted file mode 100644 index 4360044..0000000 --- a/pieces/Benedict/black_cleopatra.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/pieces/Benedict/black_cleopatra.svg b/pieces/Benedict/black_cleopatra.svg new file mode 120000 index 0000000..1669cd3 --- /dev/null +++ b/pieces/Benedict/black_cleopatra.svg @@ -0,0 +1 @@ +../black_queen.svg \ No newline at end of file diff --git a/pieces/Benedict/black_cleopatra_TODO.svg b/pieces/Benedict/black_cleopatra_TODO.svg new file mode 100644 index 0000000..4360044 --- /dev/null +++ b/pieces/Benedict/black_cleopatra_TODO.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pieces/Benedict/white_cleopatra.svg b/pieces/Benedict/white_cleopatra.svg deleted file mode 100644 index fd7f323..0000000 --- a/pieces/Benedict/white_cleopatra.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/pieces/Benedict/white_cleopatra.svg b/pieces/Benedict/white_cleopatra.svg new file mode 120000 index 0000000..e31fd1d --- /dev/null +++ b/pieces/Benedict/white_cleopatra.svg @@ -0,0 +1 @@ +../white_queen.svg \ No newline at end of file diff --git a/pieces/Benedict/white_cleopatra_TODO.svg b/pieces/Benedict/white_cleopatra_TODO.svg new file mode 100644 index 0000000..fd7f323 --- /dev/null +++ b/pieces/Benedict/white_cleopatra_TODO.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/variants/Chakart/CREDITS b/pieces/Chakart/CREDITS similarity index 97% rename from variants/Chakart/CREDITS rename to pieces/Chakart/CREDITS index 53a9181..11b0bb7 100644 --- a/variants/Chakart/CREDITS +++ b/pieces/Chakart/CREDITS @@ -1,5 +1,3 @@ -Images: - https://fr.m.wikiversity.org/wiki/Fichier:Tango_Style_Mushroom_icon.svg https://commons.wikimedia.org/wiki/File:Tux_Paint_banana.svg https://www.onlinewebfonts.com/icon/425540 diff --git a/variants.js b/variants.js index 59a69c0..8918f47 100644 --- a/variants.js +++ b/variants.js @@ -1,7 +1,7 @@ const variants = [ {name: 'Absorption', desc: 'Absorb powers'}, {name: 'Alapo', desc: 'Geometric Chess'}, -// {name: 'Alice', desc: 'Both sides of the mirror'}, + {name: 'Alice', desc: 'Both sides of the mirror'}, // {name: 'Align4', desc: 'Align four pawns'}, // {name: 'Allmate', desc: 'Mate any piece'}, {name: 'Ambiguous', desc: "Play opponent's pieces"}, diff --git a/variants/Alapo/class.js b/variants/Alapo/class.js index eb0e73f..540747d 100644 --- a/variants/Alapo/class.js +++ b/variants/Alapo/class.js @@ -81,15 +81,14 @@ export default class AlapoRules extends ChessRules { ); } + // Triangles are rotated from opponent viewpoint (=> suffix "_inv") pieces(color, x, y) { + const allSpecs = super.pieces(color, x, y); return { - 'r': super.pieces(color, x, y)['r'], - 'q': super.pieces(color, x, y)['q'], - 'b': { - // Triangle is rotated from opponent viewpoint - "class": "bishop" + (this.playerColor != color ? "_inv" : ""), - moves: [ { steps: [[1, 1], [1, -1], [-1, 1], [-1, -1]] } ] - }, + 'r': allSpecs['r'], + 'q': allSpecs['q'], + 'b': Object.assign({}, allSpecs['b'], + {"class": "bishop" + (this.playerColor != color ? "_inv" : "")}), 's': { //"square" "class": "babyrook", moves: [ diff --git a/variants/Alapo/rules.html b/variants/Alapo/rules.html index 252699c..9ec57e0 100644 --- a/variants/Alapo/rules.html +++ b/variants/Alapo/rules.html @@ -5,3 +5,5 @@ chessvariants page. + +

Johannes Tranelis (1982).

diff --git a/variants/Alice/class.js b/variants/Alice/class.js new file mode 100644 index 0000000..1957383 --- /dev/null +++ b/variants/Alice/class.js @@ -0,0 +1,126 @@ +import ChessRules from "/base_rules.js"; +import { ArrayFun } from "/utils/array.js"; + +export default class AliceRules extends ChessRules { + + static get Options() { + return { + select: C.Options.select, + input: C.Options.input, + styles: [ + "balance", + "capture", + "cylinder", + "dark", + "doublemove", + "progressive", + "zen" + ] + }; + } + + // To the other side of the mirror and back... + static get ALICE_PIECES() { + return { + s: "p", + u: "r", + o: "n", + c: "b", + t: "q", + l: "k" + }; + } + static get ALICE_CODES() { + return { + p: "s", + r: "u", + n: "o", + b: "c", + q: "t", + k: "l" + }; + } + + getPieceType(x, y, p) { + if (!p) + p = super.getPiece(x, y); + return V.ALICE_PIECES[p] || p; + } + + pieces(color, x, y) { + let alices = { + 's': {"class": "alice-pawn", "moveas": "p"}, + 'u': {"class": "alice-rook", "moveas": "r"}, + 'o': {"class": "alice-knight", "moveas": "n"}, + 'c': {"class": "alice-bishop", "moveas": "b"}, + 't': {"class": "alice-queen", "moveas": "q"}, + 'l': {"class": "alice-king", "moveas": "k"} + }; + return Object.assign(alices, super.pieces(color, x, y)); + } + + fromSameWorld(p1, p2) { + return ( + (V.ALICE_PIECES[p1] && V.ALICE_PIECES[p2]) || + (V.ALICE_CODES[p1] && V.ALICE_CODES[p2]) + ); + } + + // Step of p over i,j ? + canStepOver(i, j, p) { + return ( + this.board[i][j] == "" || !this.fromSameWorld(this.getPiece(i, j), p)); + } + + // NOTE: castle & enPassant + // https://www.chessvariants.com/other.dir/alice.html + getPotentialMovesFrom([x, y]) { + return super.getPotentialMovesFrom([x, y]).filter(m => { + // Remove moves landing on occupied square on other board + return ( + this.board[m.end.x][m.end.y] == "" || + this.fromSameWorld(m.vanish[0].p, m.vanish[1].p) + ); + }).map(m => { + // Apply Alice rule: go to the other side of the mirror + if (Object.keys(V.ALICE_CODES).includes(m.vanish[0].p)) + // Board 1 + m.appear.forEach(a => a.p = V.ALICE_CODES[a.p]) + else + // Board 2 + m.appear.forEach(a => a.p = V.ALICE_PIECES[a.p]) + return m; + }); + } + + isKing(symbol) { + return ['k', 'l'].includes(symbol); + } + + getCurrentScore() { + const color = this.turn; + const inCheck = this.underCheck(this.searchKingPos(color)); + let someLegalMove = false; + // Search for legal moves: if any is found and + // does not change king world (if under check), then game not over. + for (let i=0; i= 1 && + ( + !inCheck || + moves.some(m => m.vanish.every(v => !this.isKing(v.p))) + ) + ) { + return "*"; + } + } + } + } + // Couldn't find any legal move + return (inCheck ? "1/2" : (color == 'w' ? "0-1" : "1-0")); + } + +}; diff --git a/variants/Alice/rules.html b/variants/Alice/rules.html new file mode 100644 index 0000000..98659ea --- /dev/null +++ b/variants/Alice/rules.html @@ -0,0 +1,7 @@ +

Pieces move to the next board after playing (other side of the mirror).

+ + + chessvariants page. + + +

Vernon R. Parton (1953).

diff --git a/variants/Alice/style.css b/variants/Alice/style.css new file mode 100644 index 0000000..2683462 --- /dev/null +++ b/variants/Alice/style.css @@ -0,0 +1,39 @@ +@import url("/base_pieces.css"); + +piece.white.alice-pawn { + background-image: url('/pieces/yellow_pawn.svg'); +} +piece.white.alice-rook { + background-image: url('/pieces/yellow_rook.svg'); +} +piece.white.alice-knight { + background-image: url('/pieces/yellow_knight.svg'); +} +piece.white.alice-bishop { + background-image: url('/pieces/yellow_bishop.svg'); +} +piece.white.alice-queen { + background-image: url('/pieces/yellow_queen.svg'); +} +piece.white.alice-king { + background-image: url('/pieces/yellow_king.svg'); +} + +piece.black.alice-pawn { + background-image: url('/pieces/red_pawn.svg'); +} +piece.black.alice-rook { + background-image: url('/pieces/red_rook.svg'); +} +piece.black.alice-knight { + background-image: url('/pieces/red_knight.svg'); +} +piece.black.alice-bishop { + background-image: url('/pieces/red_bishop.svg'); +} +piece.black.alice-queen { + background-image: url('/pieces/red_queen.svg'); +} +piece.black.alice-king { + background-image: url('/pieces/red_king.svg'); +} diff --git a/variants/Ambiguous/CREDITS b/variants/Ambiguous/CREDITS deleted file mode 100644 index 68ab598..0000000 --- a/variants/Ambiguous/CREDITS +++ /dev/null @@ -1,3 +0,0 @@ -Images: - -https://freesvg.org/black-target diff --git a/variants/Ambiguous/class.js b/variants/Ambiguous/class.js index 6a001a6..58458b6 100644 --- a/variants/Ambiguous/class.js +++ b/variants/Ambiguous/class.js @@ -55,14 +55,10 @@ export default class AmbiguousRules extends ChessRules { return true; }) .map(m => { - if (m.vanish.length == 1) { - m.appear[0].c = 'a'; //a-color + if (m.vanish.length == 1) m.appear[0].p = V.GOAL; - } - else { + else m.appear[0].p = V.TARGET_CODE[m.vanish[1].p]; - m.appear[0].c = oppCol; - } m.vanish.shift(); return m; }) @@ -133,8 +129,8 @@ export default class AmbiguousRules extends ChessRules { 't': {"class": "target-queen", moves: []}, 'l': {"class": "target-king", moves: []} }; - return Object.assign( - { 'g': {"class": "target"} }, targets, super.pieces(color, x, y)); + return Object.assign({ 'g': {"class": "target", moves: []} }, + targets, super.pieces(color, x, y)); } atLeastOneMove() { diff --git a/variants/Ambiguous/style.css b/variants/Ambiguous/style.css index db300f7..f8dac72 100644 --- a/variants/Ambiguous/style.css +++ b/variants/Ambiguous/style.css @@ -1,7 +1,10 @@ @import url("/base_pieces.css"); -piece.target { - background-image: url('/pieces/Ambiguous/target.svg'); +piece.white.target { + background-image: url('/pieces/Ambiguous/yellow_target.svg'); +} +piece.black.target { + background-image: url('/pieces/Ambiguous/red_target.svg'); } piece.white.target-pawn { diff --git a/variants/Benedict/CREDITS b/variants/Benedict/CREDITS deleted file mode 100644 index e936f02..0000000 --- a/variants/Benedict/CREDITS +++ /dev/null @@ -1,4 +0,0 @@ -Images: - -https://game-icons.net/1x1/delapouite/cleopatra.html -https://www.svgrepo.com/svg/322047/cleopatra diff --git a/variants/Benedict/class.js b/variants/Benedict/class.js index 2bc60e7..e055e86 100644 --- a/variants/Benedict/class.js +++ b/variants/Benedict/class.js @@ -36,19 +36,11 @@ export default class BenedictRules extends ChessRules { pieces(color, x, y) { if (!this.options["cleopatra"]) return super.pieces(color, x, y); - return Object.assign({}, super.pieces(color, x, y), { - 'q': { - "class": "cleopatra", - moves: [ - { - steps: [ - [0, 1], [0, -1], [1, 0], [-1, 0], - [1, 1], [1, -1], [-1, 1], [-1, -1] - ] - } - ] - }, - }); + const allSpecs = super.pieces(color, x, y); + return Object.assign({}, + allSpecs, + {'q': Object.assign({}, allSpecs['q'], {"class": "cleopatra"})} + ); } // Find potential captures from a square