From 554e3ad3773a3123701bd894db1df4c1843283b8 Mon Sep 17 00:00:00 2001 From: Benjamin Auder Date: Tue, 21 Jun 2022 14:25:59 +0200 Subject: [PATCH] Add Ambiguous. Fix a few issues with FEN generation / options --- app.js | 5 +- pieces/ambiguous_target.svg | 191 ++++++++++++++++++++++++++++++++++ server.js | 16 ++- variants.js | 2 +- variants/Ambiguous/class.js | 107 ++++++++++--------- variants/Ambiguous/rules.html | 11 ++ variants/Ambiguous/style.css | 43 ++++++++ variants/Chakart/class.js | 6 +- variants/Suction/class.js | 4 +- 9 files changed, 316 insertions(+), 69 deletions(-) create mode 100644 pieces/ambiguous_target.svg create mode 100644 variants/Ambiguous/rules.html create mode 100644 variants/Ambiguous/style.css diff --git a/app.js b/app.js index 7d387c5..4c0b5e4 100644 --- a/app.js +++ b/app.js @@ -545,8 +545,9 @@ function initializeGame(obj) { break; } } - fillGameInfos(obj, playerColor == "w" ? 1 : 0); - if (obj.randvar) + const playerIndex = (playerColor == "w" ? 0 : 1); + fillGameInfos(obj, 1 - playerIndex); + if (obj.players[playerIndex].randvar) toggleVisible("gameInfos"); else toggleVisible("boardContainer"); diff --git a/pieces/ambiguous_target.svg b/pieces/ambiguous_target.svg new file mode 100644 index 0000000..53f0ccc --- /dev/null +++ b/pieces/ambiguous_target.svg @@ -0,0 +1,191 @@ + + + + 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/server.js b/server.js index 7e1a99b..dc8bd97 100644 --- a/server.js +++ b/server.js @@ -37,15 +37,12 @@ function initializeGame(vname, players, options) { function launchGame(gid) { moveHash[gid] = {}; const gameInfo = Object.assign( - {seed: Math.floor(Math.random() * 1984), gid: gid}, + {seed: Math.floor(Math.random() * 19840), gid: gid}, games[gid] ); // players array is supposed to be full: - for (const p of games[gid].players) { - send(p.sid, - "gamestart", - Object.assign({randvar: p.randvar}, gameInfo)); - } + for (const p of games[gid].players) + send(p.sid, "gamestart", gameInfo); } function getRandomVariant() { @@ -137,11 +134,10 @@ wss.on("connection", (socket, req) => { const allrand = games[obj.gid].rematch.every(r => r == 2); if (allrand) vname = getRandomVariant(); - games[obj.gid].players.forEach(p => - p.randvar = allrand ? true : false); + games[obj.gid].players.forEach(p => p.randvar = allrand); const gid = initializeGame(vname, - games[obj.gid].players.reverse(), - games[obj.gid].options); + games[obj.gid].players.reverse(), + games[obj.gid].options); launchGame(gid); } } diff --git a/variants.js b/variants.js index aafd02a..c9af9e4 100644 --- a/variants.js +++ b/variants.js @@ -5,7 +5,7 @@ const variants = [ // {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"}, + {name: 'Ambiguous', desc: "Play opponent's pieces"}, // {name: 'Antiking1', desc: 'Keep antiking in check', disp: 'Anti-King'}, // {name: 'Antimatter', desc: 'Dangerous collisions'}, // {name: 'Apocalypse', desc: 'The end of the world'}, diff --git a/variants/Ambiguous/class.js b/variants/Ambiguous/class.js index 78d3d63..6a001a6 100644 --- a/variants/Ambiguous/class.js +++ b/variants/Ambiguous/class.js @@ -1,10 +1,14 @@ import ChessRules from "/base_rules.js"; -import { randInt, shuffle } from "@/utils/alea"; -import { ArrayFun } from "@/utils/array"; +import GiveawayRules from "/variants/Giveaway/class.js"; export default class AmbiguousRules extends ChessRules { - // TODO: options + static get Options() { + return { + select: C.Options.select, + styles: ["cylinder"] + }; + } get hasFlags() { return false; @@ -19,25 +23,29 @@ export default class AmbiguousRules extends ChessRules { } genRandInitFen(seed) { - const gr = new GiveawayRules( - {mode: "suicide", options: this.options, genFenOnly: true}); + const options = Object.assign({mode: "suicide"}, this.options); + const gr = new GiveawayRules({options: options, genFenOnly: true}); return gr.genRandInitFen(seed); } + canStepOver(x, y) { + return this.board[x][y] == "" || this.getPiece(x, y) == V.GOAL; + } + // Subturn 1: play a move for the opponent on the designated square. // Subturn 2: play a move for me (which just indicate a square). getPotentialMovesFrom([x, y]) { const color = this.turn; - const oppCol = V.GetOppCol(color); + const oppCol = C.GetOppCol(color); if (this.subTurn == 2) { // Just play a normal move (which in fact only indicate a square) let movesHash = {}; return ( super.getPotentialMovesFrom([x, y]) .filter(m => { - // Filter promotions: keep only one, since no choice now. + // Filter promotions: keep only one, since no choice for now. if (m.appear[0].p != m.vanish[0].p) { - const hash = V.CoordsToSquare(m.start) + V.CoordsToSquare(m.end); + const hash = C.CoordsToSquare(m.start) + C.CoordsToSquare(m.end); if (!movesHash[hash]) { movesHash[hash] = true; return true; @@ -47,48 +55,37 @@ export default class AmbiguousRules extends ChessRules { return true; }) .map(m => { - if (m.vanish.length == 1) m.appear[0].p = V.GOAL; - else m.appear[0].p = V.TARGET_CODE[m.vanish[1].p]; - m.appear[0].c = oppCol; + if (m.vanish.length == 1) { + m.appear[0].c = 'a'; //a-color + m.appear[0].p = V.GOAL; + } + else { + m.appear[0].p = V.TARGET_CODE[m.vanish[1].p]; + m.appear[0].c = oppCol; + } m.vanish.shift(); return m; }) ); } - // At subTurn == 1, play a targeted move for opponent + // At subTurn == 1, play a targeted move for the opponent. // Search for target (we could also have it in a stack...) - let target = { x: -1, y: -1 }; - outerLoop: for (let i = 0; i < V.size.x; i++) { - for (let j = 0; j < V.size.y; j++) { - if (this.board[i][j] != V.EMPTY) { - const piece = this.board[i][j][1]; + let target = {x: -1, y: -1}; + outerLoop: for (let i = 0; i < this.size.x; i++) { + for (let j = 0; j < this.size.y; j++) { + if (this.board[i][j] != "") { + const piece = this.getPiece(i, j); if ( piece == V.GOAL || Object.keys(V.TARGET_DECODE).includes(piece) ) { - target = { x: i, y: j}; + target = {x: i, y:j}; break outerLoop; } } } } - // TODO: could be more efficient than generating all moves. - this.turn = oppCol; - const emptyTarget = (this.board[target.x][target.y][1] == V.GOAL); - if (emptyTarget) this.board[target.x][target.y] = V.EMPTY; - let moves = super.getPotentialMovesFrom([x, y]); - if (emptyTarget) { - this.board[target.x][target.y] = color + V.GOAL; - moves.forEach(m => { - m.vanish.push({ - x: target.x, - y: target.y, - c: color, - p: V.GOAL - }); - }); - } - this.turn = color; + const moves = super.getPotentialMovesFrom([x, y], oppCol); return moves.filter(m => m.end.x == target.x && m.end.y == target.y); } @@ -127,8 +124,17 @@ export default class AmbiguousRules extends ChessRules { }; } - pieces() { - // ......... + pieces(color, x, y) { + const targets = { + 's': {"class": "target-pawn", moves: []}, + 'u': {"class": "target-rook", moves: []}, + 'o': {"class": "target-knight", moves: []}, + 'c': {"class": "target-bishop", moves: []}, + 't': {"class": "target-queen", moves: []}, + 'l': {"class": "target-king", moves: []} + }; + return Object.assign( + { 'g': {"class": "target"} }, targets, super.pieces(color, x, y)); } atLeastOneMove() { @@ -140,27 +146,26 @@ export default class AmbiguousRules extends ChessRules { return moves; } + isKing(symbol) { + return ['k', 'l'].includes(symbol); + } + getCurrentScore() { // This function is only called at subTurn 1 - const color = V.GetOppCol(this.turn); - if (this.kingPos[color][0] < 0) return (color == 'w' ? "0-1" : "1-0"); + const color = C.GetOppCol(this.turn); + const kingPos = this.searchKingPos(color); + if (kingPos[0] < 0) + return (color == 'w' ? "0-1" : "1-0"); return "*"; } - play(move) { - let kingCaptured = false; - if (this.subTurn == 1) { - this.prePlay(move); - this.epSquares.push(this.getEpSquare(move)); - kingCaptured = this.kingPos[this.turn][0] < 0; - } - if (kingCaptured) move.kingCaptured = true; - V.PlayOnBoard(this.board, move); - if (this.subTurn == 2 || kingCaptured) { - this.turn = V.GetOppCol(this.turn); + postPlay(move) { + const color = this.turn; + if (this.subTurn == 2 || this.searchKingPos(color)[0] < 0) { + this.turn = C.GetOppCol(color); this.movesCount++; } - if (!kingCaptured) this.subTurn = 3 - this.subTurn; + this.subTurn = 3 - this.subTurn; } }; diff --git a/variants/Ambiguous/rules.html b/variants/Ambiguous/rules.html new file mode 100644 index 0000000..b51c747 --- /dev/null +++ b/variants/Ambiguous/rules.html @@ -0,0 +1,11 @@ +

+ Every move you play can be changed by your opponent by a move arriving + on the same square. +

+ +

+ Consequently, you play twice on each turn: first to select a move for + your opponent, then to choose one for you - which could be altered. +

+ +

Fabrice Liardet (2005).

diff --git a/variants/Ambiguous/style.css b/variants/Ambiguous/style.css new file mode 100644 index 0000000..e31d810 --- /dev/null +++ b/variants/Ambiguous/style.css @@ -0,0 +1,43 @@ +@import url("/base_pieces.css"); + +piece.target { + background-image: url('/pieces/ambiguous_target.svg'); +} + +piece.white.target-pawn { + background-image: url('/pieces/yellow_pawn.svg'); +} +piece.white.target-rook { + background-image: url('/pieces/yellow_rook.svg'); +} +piece.white.target-knight { + background-image: url('/pieces/yellow_knight.svg'); +} +piece.white.target-bishop { + background-image: url('/pieces/yellow_bishop.svg'); +} +piece.white.target-queen { + background-image: url('/pieces/yellow_queen.svg'); +} +piece.white.target-king { + background-image: url('/pieces/yellow_king.svg'); +} + +piece.black.target-pawn { + background-image: url('/pieces/red_pawn.svg'); +} +piece.black.target-rook { + background-image: url('/pieces/red_rook.svg'); +} +piece.black.target-knight { + background-image: url('/pieces/red_knight.svg'); +} +piece.black.target-bishop { + background-image: url('/pieces/red_bishop.svg'); +} +piece.black.target-queen { + background-image: url('/pieces/red_queen.svg'); +} +piece.black.target-king { + background-image: url('/pieces/red_king.svg'); +} diff --git a/variants/Chakart/class.js b/variants/Chakart/class.js index 29fdee9..37261e4 100644 --- a/variants/Chakart/class.js +++ b/variants/Chakart/class.js @@ -131,8 +131,8 @@ export default class ChakartRules extends ChessRules { } genRandInitFen(seed) { - const gr = new GiveawayRules( - {mode: "suicide", options: this.options, genFenOnly: true}); + const options = Object.assign({mode: "suicide"}, this.options); + const gr = new GiveawayRules({options: options, genFenOnly: true}); // Add Peach + mario flags return gr.genRandInitFen(seed).slice(0, -17) + '{"flags":"1111"}'; } @@ -180,7 +180,7 @@ export default class ChakartRules extends ChessRules { this.moveStack = []; // Change seed (after FEN generation!!) // so that further calls differ between players: - Random.setSeed(Math.floor(10000 * Math.random())); + Random.setSeed(Math.floor(19840 * Math.random())); } // For Toadette bonus diff --git a/variants/Suction/class.js b/variants/Suction/class.js index f9cf26d..e2e36c8 100644 --- a/variants/Suction/class.js +++ b/variants/Suction/class.js @@ -42,8 +42,8 @@ export default class SuctionRules extends ChessRules { } genRandInitFen(seed) { - const gr = new GiveawayRules( - {mode: "suicide", options: this.options, genFenOnly: true}); + const options = Object.assign({mode: "suicide"}, this.options); + const gr = new GiveawayRules({options: options, genFenOnly: true}); // Add empty cmove: return ( gr.genRandInitFen(seed).slice(0, -17) + '{"enpassant":"-","cmove":"-"}'); -- 2.44.0