From de1421be3ee53cb4ea8f112834d3de7a863fdd40 Mon Sep 17 00:00:00 2001 From: Benjamin Auder Date: Fri, 17 Feb 2023 09:18:56 +0100 Subject: [PATCH] Draft Checkless. Add 'trackKingWrap' method, untested. Use 'canSelfTake' --- README.md | 2 +- base_rules.js | 63 ++++++++++++++++++++++--------------- nodemon.json | 26 +++++++++++++++ package-lock.json | 12 +++---- package.json | 6 ++-- start.sh | 2 +- variants.js | 2 +- variants/Checkless/class.js | 46 +++++++++++++++++++++++++++ variants/Teleport/class.js | 12 +++++-- 9 files changed, 132 insertions(+), 39 deletions(-) create mode 100644 nodemon.json create mode 100644 variants/Checkless/class.js diff --git a/README.md b/README.md index 5f60c1d..b0517cd 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,6 @@ Rename parameters.js.dist → parameters.js, and edit file.
```npm i``` Generate some pieces:
-```python generateSVG.py``` in variants/Avalam/pieces +```python generateSVG.py``` in pieces/Avalam ```./start.sh``` (and later, ```./stop.sh```) diff --git a/base_rules.js b/base_rules.js index e127b74..0c316eb 100644 --- a/base_rules.js +++ b/base_rules.js @@ -1321,9 +1321,9 @@ export default class ChessRules { return this.getColor(x1, y1) !== this.getColor(x2, y2); } - // TODO: currently unused, but makes sense? + // Teleport & Recycle. Assumption: color(x1,y1) == color(x2,y2) canSelfTake([x1, y1], [x2, y2]) { - return true; + return !this.isKing(x2, y2); } canStepOver(i, j, p) { @@ -1488,6 +1488,7 @@ export default class ChessRules { } // All possible moves from selected square + // TODO: generalize usage if arg "color" (e.g. Checkered) getPotentialMovesFrom([x, y], color) { if (this.subTurnTeleport == 2) return []; @@ -1722,8 +1723,12 @@ export default class ChessRules { segments: this.options["cylinder"], stepSpec: stepSpec }, - ([i1, j1], [i2, j2]) => - this.getColor(i2, j2) == color && !this.isKing(i2, j2) + ([i1, j1], [i2, j2]) => { + return ( + this.getColor(i2, j2) == color && + this.canSelfTake([i1, j1], [i2, j2]) + ); + } ); Array.prototype.push.apply(squares, selfCaptures); } @@ -2164,6 +2169,31 @@ export default class ChessRules { return res; } + // cb: callback returning a boolean (false if king missing) + trackKingWrap(move, kingPos, cb) { + let newKingPP = null, + sqIdx = 0, + res = true; //a priori valid + const oldKingPP = + move.vanish.find(v => this.isKing(0, 0, v.p) && v.c == color); + if (oldKingPP) { + // Search king in appear array: + newKingPP = + move.appear.find(a => this.isKing(0, 0, a.p) && a.c == color); + if (newKingPP) { + sqIdx = kingPos.findIndex(kp => + kp[0] == oldKingPP.x && kp[1] == oldKingPP.y); + kingPos[sqIdx] = [newKingPP.x, newKingPP.y]; + } + else + res = false; //king vanished + } + res &&= cb(kingPos); + if (oldKingPP && newKingPP) + kingPos[sqIdx] = [oldKingPP.x, oldKingPP.y]; + return res; + } + // 'color' arg because some variants (e.g. Refusal) check opponent moves filterValid(moves, color) { if (!color) @@ -2172,26 +2202,9 @@ export default class ChessRules { let kingPos = this.searchKingPos(color); return moves.filter(m => { this.playOnBoard(m); - let newKingPP = null, - sqIdx = 0, - res = true; //a priori valid - const oldKingPP = - m.vanish.find(v => this.isKing(0, 0, v.p) && v.c == color); - if (oldKingPP) { - // Search king in appear array: - newKingPP = - m.appear.find(a => this.isKing(0, 0, a.p) && a.c == color); - if (newKingPP) { - sqIdx = kingPos.findIndex(kp => - kp[0] == oldKingPP.x && kp[1] == oldKingPP.y); - kingPos[sqIdx] = [newKingPP.x, newKingPP.y]; - } - else - res = false; //king vanished - } - res &&= !this.underCheck(kingPos, oppCols); - if (oldKingPP && newKingPP) - kingPos[sqIdx] = [oldKingPP.x, oldKingPP.y]; + const res = this.trackKingWrap(m, kingPos, (kp) => { + return !this.underCheck(kp, oppCols); + }); this.undoOnBoard(m); return res; }); @@ -2367,7 +2380,7 @@ export default class ChessRules { if (this.board[i][j] != "" && this.getColor(i, j) == color) { // NOTE: in fact searching for all potential moves from i,j. // I don't believe this is an issue, for now at least. - const moves = this.getPotentialMovesFrom([i, j]); + const moves = this.getPotentialMovesFrom([i, j], color); if (moves.some(m => this.filterValid([m]).length >= 1)) return true; } diff --git a/nodemon.json b/nodemon.json new file mode 100644 index 0000000..d9ffb96 --- /dev/null +++ b/nodemon.json @@ -0,0 +1,26 @@ +{ + "ignore": [ + "app.js", + "assets/", + "assets.zip"," + "base_pieces.css", + "base_rules.js", + "common.css", + "favicon.ico", + "index.html", + "LICENSE", + "parameters.js", + "parameters.js.dist", + "pieces/", + "README.md", + "start.sh", + "stop.sh", + "utils/", + "TODO", + "variants/", + "variants.js" + ], + "watch": [ + "server.js" + ] +} diff --git a/package-lock.json b/package-lock.json index d553246..4f5febd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,9 +12,9 @@ } }, "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "dependencies": { "normalize-path": "^3.0.0", @@ -220,9 +220,9 @@ }, "dependencies": { "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "requires": { "normalize-path": "^3.0.0", diff --git a/package.json b/package.json index 79387df..e1c96d5 100644 --- a/package.json +++ b/package.json @@ -2,11 +2,11 @@ "dependencies": { "ws": "^7.5.3" }, - "devDependencies": { - "chokidar": "^3.5.3" - }, "scripts": { "start": "./start.sh", "stop": "./stop.sh" + }, + "devDependencies": { + "chokidar": "^3.5.3" } } diff --git a/start.sh b/start.sh index 8434097..35e6b41 100755 --- a/start.sh +++ b/start.sh @@ -1,5 +1,5 @@ #!/bin/sh -nodemon -i app.js -i base_rules.js ./server.js & +nodemon ./server.js & echo $! > .pid php -S localhost:8000 & diff --git a/variants.js b/variants.js index db500f5..8353853 100644 --- a/variants.js +++ b/variants.js @@ -27,7 +27,7 @@ const variants = [ {name: 'Capture', desc: 'Mandatory captures'}, {name: 'Chakart', desc: 'Capture the princess'}, {name: 'Checkered', desc: 'Shared pieces'}, -// {name: 'Checkless', desc: 'No-check mode'}, + {name: 'Checkless', desc: 'No-check mode'}, {name: 'Chess960', disp: "Chess 960", desc: "Standard rules"}, // {name: 'Circular', desc: 'Run forward'}, // {name: 'Clorange', desc: 'A Clockwork Orange', disp: 'Clockwork Orange'}, diff --git a/variants/Checkless/class.js b/variants/Checkless/class.js new file mode 100644 index 0000000..bc85184 --- /dev/null +++ b/variants/Checkless/class.js @@ -0,0 +1,46 @@ +import ChessRules from "/base_rules.js"; + +export default class ChecklessRules extends ChessRules { + + // Cannot use super.atLeastOneMove: lead to infinite recursion + atLeastOneMove_aux(kingPos, oppKingPos, color, oppCol) { + for (let i = 0; i < this.size.x; i++) { + for (let j = 0; j < this.size.y; j++) { + if (this.getColor(i, j) == color) { + const moves = this.getPotentialMovesFrom([i, j]); + for (let m of moves) { + this.playOnBoard(m); + const res = this.trackKingWrap(m, kingPos, (kp) => { + return !this.underCheck(kp, [oppCol]); + }); + this.undoOnBoard(m); + if (res) + return true; + } + } + } + } + return false; + } + + filterValid(moves) { + fmoves = super.filterValid(moves); + // Filter out moves giving check but not checkmate + const color = this.turn; + const oppCol = C.GetOppTurn(color); + let kingPos = this.searchKingPos(color), + oppKingPos = this.searchKingPos(oppCol); + return fmoves.filter(m => { + this.playOnBoard(m); + const res = this.trackKingWrap(m, oppKingPos, (oppKp) => { + return ( + !this.underCheck(oppKp, [color]) || + this.atLeastOneMove_aux(oppKp, kingPos, oppCol, color) + ); + }); + this.undoOnBoard(m); + return res; + }); + } + +}; diff --git a/variants/Teleport/class.js b/variants/Teleport/class.js index 2698eaf..7ac3b34 100644 --- a/variants/Teleport/class.js +++ b/variants/Teleport/class.js @@ -5,8 +5,12 @@ export default class TeleportRules extends ChessRules { static get Options() { return { select: C.Options.select, - // TODO? option "teleport king"? - input: C.Options.input, + input: C.Options.input.concat({ + label: "Teleport king", + variable: "tpking", + type: "checkbox", + defaut: false + }), styles: C.Options.styles.filter(s => s != "teleport") }; } @@ -16,4 +20,8 @@ export default class TeleportRules extends ChessRules { super(o); } + canSelfTake([x1, y1], [x2, y2]) { + return (this.options["tpking"] || !this.isKing(x2, y2)); + } + }; -- 2.44.0