## Requirements (dev)
-Global npm install: nodemon, livereload. <br>
-A static web server like "php -S localhost:8000".
+PHP + Node.js + npm.
+```npm i -g nodemon```
## Usage
```npm i```
Generate some pieces: <br>
-```python generateSVG.py``` in pieces/Avalam
+```python generateSVG.py``` in variants/Avalam/pieces
-```./start.sh``` (edit 'php -S ...' line if necessary) <br>
-... <br>
-```./stop.sh```
+```./start.sh``` (and later, ```./stop.sh```)
Baroque Berolina Bicolour Brotherhood
For Baroque (and Fugue and...) --> maybe a dedicated parent class ?
-Go game with option oneColor
+Go game with option oneColor (révélée à la fin phase counting -->).
+Endgame :: mode "counting", déplacements libres (indépendamment de chaque coté)
add variants :
Dark Racing Kings ? Checkered-Teleport ?
case "closerematch":
toggleVisible("newGame");
break;
+ case "filechange":
+ // TODO?: could be more subtle
+ location.reload();
+ break;
}
};
}
getStepSpec(color, x, y, piece) {
- return this.pieces(color, x, y)[piece || this.getPieceType(x, y)];
+ let pieceType = piece;
+ const allSpecs = this.pieces(color, x, y);
+ if (!piece)
+ pieceType = this.getPieceType(x, y);
+ else if (allSpecs[piece].moveas)
+ pieceType = allSpecs[piece].moveas;
+ return allSpecs[pieceType];
}
// Can thing on square1 capture thing on square2?
"": {
"dependencies": {
"ws": "^7.5.3"
+ },
+ "devDependencies": {
+ "chokidar": "^3.5.3"
+ }
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
+ "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
+ "dev": true,
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/binary-extensions": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dev": true,
+ "dependencies": {
+ "fill-range": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+ "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ ],
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dev": true,
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "dev": true,
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dev": true,
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
}
},
"node_modules/ws": {
}
},
"dependencies": {
+ "anymatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
+ "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
+ "dev": true,
+ "requires": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ }
+ },
+ "binary-extensions": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+ "dev": true
+ },
+ "braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dev": true,
+ "requires": {
+ "fill-range": "^7.0.1"
+ }
+ },
+ "chokidar": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+ "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+ "dev": true,
+ "requires": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "fsevents": "~2.3.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ }
+ },
+ "fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dev": true,
+ "requires": {
+ "to-regex-range": "^5.0.1"
+ }
+ },
+ "fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "dev": true,
+ "optional": true
+ },
+ "glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "requires": {
+ "is-glob": "^4.0.1"
+ }
+ },
+ "is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
+ "requires": {
+ "binary-extensions": "^2.0.0"
+ }
+ },
+ "is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true
+ },
+ "is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^2.1.1"
+ }
+ },
+ "is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true
+ },
+ "normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true
+ },
+ "picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true
+ },
+ "readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dev": true,
+ "requires": {
+ "picomatch": "^2.2.1"
+ }
+ },
+ "to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "requires": {
+ "is-number": "^7.0.0"
+ }
+ },
"ws": {
"version": "7.5.5",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz",
{
"dependencies": {
"ws": "^7.5.3"
+ },
+ "devDependencies": {
+ "chokidar": "^3.5.3"
+ },
+ "scripts": {
+ "start": "./start.sh",
+ "stop": "./stop.sh"
}
}
// Usage on (socket) server:
socket_port: 8080, //...
+ dev: true,
// Usage on both:
socket_path: "/ws",
sockets[sid] = socket;
socket.isAlive = true;
socket.on("pong", () => socket.isAlive = true);
-
+ if (params.dev == true) {
+ const chokidar = require("chokidar");
+ const watcher = chokidar.watch(
+ ["*.js", "*.css", "utils/", "variants/"],
+ {persistent: true});
+ watcher.on("change", path => send(sid, "filechange", {path: path}));
+ }
socket.on("message", (msg) => {
const obj = JSON.parse(msg);
switch (obj.code) {
#!/bin/sh
-nodemon -i index.js -i base_rules.js ./server.js &
-echo "NODE_PID=$!" > .pid
-
-# NOTE: require browser plugin + start it
-livereload -e 'html,js,css,png,jpg,jpeg,gif,svg' -w 1000 -d . &
-
-# I use 8080 for socket and 8000 for http server (arbitrary...)
+nodemon -i app.js -i base_rules.js ./server.js &
+echo $! > .pid
php -S localhost:8000 &
#!/bin/sh
# https://stackoverflow.com/questions/13939038/how-do-you-run-a-command-for-each-line-of-a-file
-source ./.pid
-kill -9 -`ps p $NODE_PID -o pgid | grep "[0-9]\+" | tr -d " "`
+while read pid; do
+ kill -9 -`ps p $pid -o pgid | grep "[0-9]\+" | tr -d " "`
+done <.pid
// {name: 'Balaklava', desc: 'Meet the Mammoth'},
{name: 'Bario', desc: 'A quantum story'},
{name: "Balanced", desc: "balanced chess"},
-// {name: 'Baroque', desc: 'Exotic captures'},*/
+ {name: 'Baroque', desc: 'Exotic captures'},
{name: "Benedict", desc: "Change colors"},
// {name: 'Berolina', desc: 'Pawns move diagonally'},
// {name: 'Bicolour', desc: 'Harassed kings'},
piece.black.rook {
- background-image: url('/pieces/Alapo/black_SQUARE.svg');
+ background-image: url('/variants/Alapo/pieces/black_SQUARE.svg');
}
piece.black.bishop {
- background-image: url('/pieces/Alapo/black_TRIANGLE.svg');
+ background-image: url('/variants/Alapo/pieces/black_TRIANGLE.svg');
}
piece.black.bishop_inv {
- background-image: url('/pieces/Alapo/black_TRIANGLE_inv.svg');
+ background-image: url('/variants/Alapo/pieces/black_TRIANGLE_inv.svg');
}
piece.black.queen {
- background-image: url('/pieces/Alapo/black_CIRCLE.svg');
+ background-image: url('/variants/Alapo/pieces/black_CIRCLE.svg');
}
piece.black.babyrook {
- background-image: url('/pieces/Alapo/black_square.svg');
+ background-image: url('/variants/Alapo/pieces/black_square.svg');
}
piece.black.babybishop {
- background-image: url('/pieces/Alapo/black_triangle.svg');
+ background-image: url('/variants/Alapo/pieces/black_triangle.svg');
}
piece.black.babybishop_inv {
- background-image: url('/pieces/Alapo/black_triangle_inv.svg');
+ background-image: url('/variants/Alapo/pieces/black_triangle_inv.svg');
}
piece.black.babyqueen {
- background-image: url('/pieces/Alapo/black_circle.svg');
+ background-image: url('/variants/Alapo/pieces/black_circle.svg');
}
piece.white.rook {
- background-image: url('/pieces/Alapo/white_SQUARE.svg');
+ background-image: url('/variants/Alapo/pieces/white_SQUARE.svg');
}
piece.white.bishop {
- background-image: url('/pieces/Alapo/white_TRIANGLE.svg');
+ background-image: url('/variants/Alapo/pieces/white_TRIANGLE.svg');
}
piece.white.bishop_inv {
- background-image: url('/pieces/Alapo/white_TRIANGLE_inv.svg');
+ background-image: url('/variants/Alapo/pieces/white_TRIANGLE_inv.svg');
}
piece.white.queen {
- background-image: url('/pieces/Alapo/white_CIRCLE.svg');
+ background-image: url('/variants/Alapo/pieces/white_CIRCLE.svg');
}
piece.white.babyrook {
- background-image: url('/pieces/Alapo/white_square.svg');
+ background-image: url('/variants/Alapo/pieces/white_square.svg');
}
piece.white.babybishop {
- background-image: url('/pieces/Alapo/white_triangle.svg');
+ background-image: url('/variants/Alapo/pieces/white_triangle.svg');
}
piece.white.babybishop_inv {
- background-image: url('/pieces/Alapo/white_triangle_inv.svg');
+ background-image: url('/variants/Alapo/pieces/white_triangle_inv.svg');
}
piece.white.babyqueen {
- background-image: url('/pieces/Alapo/white_circle.svg');
+ background-image: url('/variants/Alapo/pieces/white_circle.svg');
}
@import url("/variants/_Antiking/style.css");
piece.black.pawn {
- background-image: url('/pieces/Berolina/black_pawn.svg');
+ background-image: url('/variants/Berolina/pieces/black_pawn.svg');
}
piece.white.pawn {
- background-image: url('/pieces/Berolina/white_pawn.svg');
+ background-image: url('/variants/Berolina/pieces/white_pawn.svg');
}
<p>The goal is to eliminate all enemy pawns.</p>
-<a href="/variants/Apocalypse/complete_rules.html">Full rules description.</a>
+<a target="_blank" href="/variants/Apocalypse/complete_rules.html">
+ Full rules description.
+</a>
<p class="author">C.S. Elliott (1976).</p>
}
piece.white.stone {
- background-image: url('/pieces/Go/black_stone.svg');
+ background-image: url('/variants/Go/pieces/black_stone.svg');
}
piece.black.stone {
- background-image: url('/pieces/Go/white_stone.svg');
+ background-image: url('/variants/Go/pieces/white_stone.svg');
}
piece.white.stack {
- background-image: url('/pieces/Avalam/white_stack.svg');
+ background-image: url('/variants/Avalam/pieces/white_stack.svg');
}
piece.white.stack2 {
- background-image: url('/pieces/Avalam/white_stack2.svg');
+ background-image: url('/variants/Avalam/pieces/white_stack2.svg');
}
piece.white.stack3 {
- background-image: url('/pieces/Avalam/white_stack3.svg');
+ background-image: url('/variants/Avalam/pieces/white_stack3.svg');
}
piece.white.stack4 {
- background-image: url('/pieces/Avalam/white_stack4.svg');
+ background-image: url('/variants/Avalam/pieces/white_stack4.svg');
}
piece.white.stack5 {
- background-image: url('/pieces/Avalam/white_stack5.svg');
+ background-image: url('/variants/Avalam/pieces/white_stack5.svg');
}
piece.black.stack {
- background-image: url('/pieces/Avalam/black_stack.svg');
+ background-image: url('/variants/Avalam/pieces/black_stack.svg');
}
piece.black.stack2 {
- background-image: url('/pieces/Avalam/black_stack2.svg');
+ background-image: url('/variants/Avalam/pieces/black_stack2.svg');
}
piece.black.stack3 {
- background-image: url('/pieces/Avalam/black_stack3.svg');
+ background-image: url('/variants/Avalam/pieces/black_stack3.svg');
}
piece.black.stack4 {
- background-image: url('/pieces/Avalam/black_stack4.svg');
+ background-image: url('/variants/Avalam/pieces/black_stack4.svg');
}
piece.black.stack5 {
- background-image: url('/pieces/Avalam/black_stack5.svg');
+ background-image: url('/variants/Avalam/pieces/black_stack5.svg');
}
.board-sq {
static get Options() {
return {
- // TODO: Zen too?
+ select: C.Options.select,
+ input: C.Options.input,
styles: [
"atomic", "cannibal", "capture", "cylinder",
"dark", "madrasi", "rifle", "teleport"
--- /dev/null
+import ChessRules from "/base_rules.js";
+import GiveawayRules from "/variants/Giveaway/class.js";
+import {Random} from "/utils/alea.js";
+import PiPo from "/utils/PiPo.js";
+import Move from "/utils/Move.js";
+
+export default class BaroqueRules extends ChessRules {
+
+ static get Options() {
+ return {
+ select: C.Options.Select,
+ input: [
+ {
+ label: "Capture king",
+ variable: "taking",
+ type: "checkbox",
+ defaut: false
+ }
+ ],
+ styles: [
+ "balance",
+ "capture",
+ "crazyhouse",
+ "cylinder",
+ "doublemove",
+ "progressive",
+ "recycle",
+ "teleport"
+ ]
+ };
+ }
+
+ get hasFlags() {
+ return false;
+ }
+ get hasEnpassant() {
+ return false;
+ }
+
+ genRandInitBaseFen() {
+ if (this.options["randomness"] == 0)
+ return "rnbkqbnm/pppppppp/8/8/8/8/PPPPPPPP/MNBQKBNR";
+ const options = Object.assign({mode: "suicide"}, this.options);
+ const gr = new GiveawayRules({options: options, genFenOnly: true});
+ let res = gr.genRandInitBaseFen();
+ let immPos = {};
+ for (let c of ['w', 'b']) {
+ const rookChar = (c == 'w' ? 'R' : 'r');
+ switch (Random.randInt(2)) {
+ case 0:
+ immPos[c] = res.fen.indexOf(rookChar);
+ break;
+ case 1:
+ immPos[c] = res.fen.lastIndexOf(rookChar);
+ break;
+ }
+ }
+ res.fen = res.fen.substring(0, immPos['b']) + 'i' +
+ res.fen.substring(immPos['b'] + 1, immPos['w']) + 'I' +
+ res.fen.substring(immPos['w'] + 1);
+ return res;
+ }
+
+ // Although other pieces keep their names here for coding simplicity,
+ // keep in mind that:
+ // - a "rook" is a coordinator, capturing by coordinating with the king
+ // - a "knight" is a long-leaper, capturing as in draughts
+ // - a "bishop" is a chameleon, capturing as its prey
+ // - a "queen" is a withdrawer, capturing by moving away from pieces
+
+ pieces() {
+ return Object.assign({},
+ super.pieces(),
+ {
+ 'p': {
+ "class": "pawn",
+ moves: [
+ {steps: [[0, 1], [0, -1], [1, 0], [-1, 0]]}
+ ]
+ },
+ 'r': {
+ "class": "rook",
+ moves: [
+ {
+ steps: [
+ [1, 0], [0, 1], [-1, 0], [0, -1],
+ [1, 1], [1, -1], [-1, 1], [-1, -1]
+ ]
+ }
+ ]
+ },
+ 'n': {
+ "class": "knight",
+ moveas: 'r'
+ },
+ 'b': {
+ "class": "bishop",
+ moveas: 'r'
+ },
+ 'q': {
+ "class": "queen",
+ moveas: 'r'
+ },
+ 'i': {
+ "class": "immobilizer",
+ moveas: 'q'
+ }
+ }
+ );
+ }
+
+ // Is piece on square (x,y) immobilized?
+ isImmobilized([x, y]) {
+ const piece = this.getPiece(x, y);
+ const color = this.getColor(x, y);
+ const oppCol = C.GetOppCol(color);
+ const adjacentSteps = this.pieces()['k'].moves[0].steps;
+ for (let step of adjacentSteps) {
+ const [i, j] = [x + step[0], this.getY(y + step[1])];
+ if (
+ this.onBoard(i, j) &&
+ this.board[i][j] != "" &&
+ this.getColor(i, j) == oppCol
+ ) {
+ const oppPiece = this.getPiece(i, j);
+ if (oppPiece == 'i') {
+ // Moving is possible only if this immobilizer is neutralized
+ for (let step2 of adjacentSteps) {
+ const [i2, j2] = [i + step2[0], this.getY(j + step2[1])];
+ if (i2 == x && j2 == y)
+ continue; //skip initial piece!
+ if (
+ this.onBoard(i2, j2) &&
+ this.board[i2][j2] != "" &&
+ this.getColor(i2, j2) == color
+ ) {
+ if (['b', 'i'].includes(this.getPiece(i2, j2)))
+ return false;
+ }
+ }
+ return true; //immobilizer isn't neutralized
+ }
+ // Chameleons can't be immobilized twice,
+ // because there is only one immobilizer
+ if (oppPiece == 'b' && piece == 'i')
+ return true;
+ }
+ }
+ return false;
+ }
+
+ canTake([x1, y1], [x2, y2]) {
+ // Deactivate standard captures, except for king:
+ return (
+ this.getPiece(x1, y1) == 'k' &&
+ this.getColor(x1, y1) != this.getColor(x2, y2)
+ );
+ }
+
+ postProcessPotentialMoves(moves) {
+ if (moves.length == 0)
+ return [];
+ switch (moves[0].vanish[0].p) {
+ case 'p':
+ this.addPawnCaptures(moves);
+ break;
+ case 'r':
+ this.addRookCaptures(moves);
+ break;
+ case 'n':
+ const [x, y] = [moves[0].start.x, moves[0].start.y];
+ moves = moves.concat(this.getKnightCaptures([x, y]));
+ break;
+ case 'b':
+ moves = this.getBishopCaptures(moves);
+ break;
+ case 'q':
+ this.addPawnCaptures(moves);
+ break;
+ }
+ return moves;
+ }
+
+ // Modify capturing moves among listed pawn moves
+ addPawnCaptures(moves, byChameleon) {
+ const steps = this.pieces()['p'].moves[0].steps;
+ const color = this.turn;
+ const oppCol = C.GetOppCol(color);
+ moves.forEach(m => {
+ if (byChameleon && m.start.x != m.end.x && m.start.y != m.end.y)
+ // Chameleon not moving as pawn
+ return;
+ // Try capturing in every direction
+ for (let step of steps) {
+ const sq2 = [m.end.x + 2 * step[0], this.getY(m.end.y + 2 * step[1])];
+ if (
+ this.onBoard(sq2[0], sq2[1]) &&
+ this.board[sq2[0]][sq2[1]] != "" &&
+ this.getColor(sq2[0], sq2[1]) == color
+ ) {
+ // Potential capture
+ const sq1 = [m.end.x + step[0], this.getY(m.end.y + step[1])];
+ if (
+ this.board[sq1[0]][sq1[1]] != "" &&
+ this.getColor(sq1[0], sq1[1]) == oppCol
+ ) {
+ const piece1 = this.getPiece(sq1[0], sq1[1]);
+ if (!byChameleon || piece1 == 'p') {
+ m.vanish.push(
+ new PiPo({
+ x: sq1[0],
+ y: sq1[1],
+ c: oppCol,
+ p: piece1
+ })
+ );
+ }
+ }
+ }
+ }
+ });
+ }
+
+ addRookCaptures(moves, byChameleon) {
+ const color = this.turn;
+ const oppCol = V.GetOppCol(color);
+ const kp = this.searchKingPos(color)[0];
+ moves.forEach(m => {
+ // Check piece-king rectangle (if any) corners for enemy pieces
+ if (m.end.x == kp[0] || m.end.y == kp[1])
+ return; //"flat rectangle"
+ const corner1 = [m.end.x, kp[1]];
+ const corner2 = [kp[0], m.end.y];
+ for (let [i, j] of [corner1, corner2]) {
+ if (this.board[i][j] != "" && this.getColor(i, j) == oppCol) {
+ const piece = this.getPiece(i, j);
+ if (!byChameleon || piece == 'r') {
+ m.vanish.push(
+ new PiPo({
+ x: i,
+ y: j,
+ p: piece,
+ c: oppCol
+ })
+ );
+ }
+ }
+ }
+ });
+ }
+
+ getKnightCaptures(startSquare, byChameleon) {
+ // Look in every direction for captures
+ const steps = this.pieces()['r'].moves[0].steps;
+ const color = this.turn;
+ const oppCol = C.GetOppCol(color);
+ let moves = [];
+ const [x, y] = [startSquare[0], startSquare[1]];
+ const piece = this.getPiece(x, y); //might be a chameleon!
+ outerLoop: for (let step of steps) {
+ let [i, j] = [x + step[0], this.getY(y + step[1])];
+ while (this.onBoard(i, j) && this.board[i][j] == "")
+ [i, j] = [i + step[0], this.getY(j + step[1])];
+ if (
+ !this.onBoard(i, j) ||
+ this.getColor(i, j) == color ||
+ (byChameleon && this.getPiece(i, j) != 'n')
+ ) {
+ continue;
+ }
+ // last(thing), cur(thing) : stop if "cur" is our color,
+ // or beyond board limits, or if "last" isn't empty and cur neither.
+ // Otherwise, if cur is empty then add move until cur square;
+ // if cur is occupied then stop if !!byChameleon and the square not
+ // occupied by a leaper.
+ let last = [i, j];
+ let cur = [i + step[0], this.getY(j + step[1])];
+ let vanished = [new PiPo({x: x, y: y, c: color, p: piece})];
+ while (this.onBoard(cur[0], cur[1])) {
+ if (this.board[last[0]][last[1]] != "") {
+ const oppPiece = this.getPiece(last[0], last[1]);
+ if (!!byChameleon && oppPiece != 'n')
+ continue outerLoop;
+ // Something to eat:
+ vanished.push(
+ new PiPo({x: last[0], y: last[1], c: oppCol, p: oppPiece})
+ );
+ }
+ if (this.board[cur[0]][cur[1]] != "") {
+ if (
+ this.getColor(cur[0], cur[1]) == color ||
+ this.board[last[0]][last[1]] != ""
+ ) {
+ //TODO: redundant test
+ continue outerLoop;
+ }
+ }
+ else {
+ moves.push(
+ new Move({
+ appear: [new PiPo({x: cur[0], y: cur[1], c: color, p: piece})],
+ vanish: JSON.parse(JSON.stringify(vanished)), //TODO: required?
+ start: {x: x, y: y},
+ end: {x: cur[0], y: cur[1]}
+ })
+ );
+ }
+ last = [last[0] + step[0], this.getY(last[1] + step[1])];
+ cur = [cur[0] + step[0], this.getY(cur[1] + step[1])];
+ }
+ }
+ return moves;
+ }
+
+ // Chameleon
+ getBishopCaptures(moves) {
+ const [x, y] = [moves[0].start.x, moves[0].start.y];
+ moves = moves.concat(this.getKnightCaptures([x, y], "asChameleon"));
+ // No "king capture" because king cannot remain under check
+ this.addPawnCaptures(moves, "asChameleon");
+ this.addRookCaptures(moves, "asChameleon");
+ this.addQueenCaptures(moves, "asChameleon");
+ // Post-processing: merge similar moves, concatenating vanish arrays
+ let mergedMoves = {};
+ moves.forEach(m => {
+ const key = m.end.x + this.size.x * m.end.y;
+ if (!mergedMoves[key])
+ mergedMoves[key] = m;
+ else {
+ for (let i = 1; i < m.vanish.length; i++)
+ mergedMoves[key].vanish.push(m.vanish[i]);
+ }
+ });
+ return Object.values(mergedMoves);
+ }
+
+ addQueenCaptures(moves, byChameleon) {
+ if (moves.length == 0) return;
+ const [x, y] = [moves[0].start.x, moves[0].start.y];
+ const adjacentSteps = this.pieces()['r'].moves[0].steps;
+ let capturingDirections = [];
+ const color = this.turn;
+ const oppCol = C.GetOppCol(color);
+ adjacentSteps.forEach(step => {
+ const [i, j] = [x + step[0], this.getY(y + step[1])];
+ if (
+ this.onBoard(i, j) &&
+ this.board[i][j] != "" &&
+ this.getColor(i, j) == oppCol &&
+ (!byChameleon || this.getPiece(i, j) == 'q')
+ ) {
+ capturingDirections.push(step);
+ }
+ });
+ moves.forEach(m => {
+ const step = [
+ m.end.x != x ? (m.end.x - x) / Math.abs(m.end.x - x) : 0,
+ m.end.y != y ? (m.end.y - y) / Math.abs(m.end.y - y) : 0
+ ];
+ // NOTE: includes() and even _.isEqual() functions fail...
+ // TODO: this test should be done only once per direction
+ if (
+ capturingDirections.some(dir => {
+ return dir[0] == -step[0] && dir[1] == -step[1];
+ })
+ ) {
+ const [i, j] = [x - step[0], this.getY(y - step[1])];
+ m.vanish.push(
+ new PiPo({
+ x: i,
+ y: j,
+ p: this.getPiece(i, j),
+ c: oppCol
+ })
+ );
+ }
+ });
+ }
+
+ underAttack([x, y], oppCol) {
+ // Generate all potential opponent moves, check if king captured.
+ // TODO: do it more efficiently.
+ const color = this.getColor(x, y);
+ for (let i = 0; i < this.size.x; i++) {
+ for (let j = 0; j < this.size.y; j++) {
+ if (
+ this.board[i][j] != "" && this.getColor(i, j) == oppCol &&
+ this.getPotentialMovesFrom([i, j]).some(m => {
+ return (
+ m.vanish.length >= 2 &&
+ [1, m.vanish.length - 1].some(k => m.vanish[k].p == 'k')
+ );
+ })
+ ) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+};
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ height="100%"
+ width="100%"
+ version="1.1"
+ viewBox="0 0 2048 2048"
+ id="svg44"
+ sodipodi:docname="bu.svg"
+ inkscape:version="0.92.2 2405546, 2018-03-11">
+ <metadata
+ id="metadata50">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs48" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="960"
+ inkscape:window-height="1060"
+ id="namedview46"
+ showgrid="false"
+ inkscape:zoom="0.11523438"
+ inkscape:cx="1041.3559"
+ inkscape:cy="1024"
+ inkscape:window-x="0"
+ inkscape:window-y="20"
+ inkscape:window-maximized="0"
+ inkscape:current-layer="svg44" />
+ <path
+ style="color:#000000;display:block;fill:#000000;fill-rule:nonzero"
+ d="m 1161,1706 h 170 v 137 h 274 V 1468 L 1383,1297 V 819 L 1553,649 V 444 h 153 V 205 H 341 v 239 h 153 v 205 l 171,170 v 478 l -222,171 v 375 h 273 v -137 h 171 v 137 h 274 z M 564,460 V 358 h 920 v 102 z m 460,1092 H 512 v -46 l 73,-55 h 879 l 71,55 v 46 z m 0,-169 H 674 l 60,-47 v -57 h 580 v 57 l 60,47 z m 0,-546 H 734 v -46 l -60,-58 h 700 l -60,58 v 46 z m 0,-172 H 610 l -46,-43 v -58 h 920 v 58 l -46,43 z"
+ display="block"
+ id="path30"
+ inkscape:connector-curvature="0" />
+ <g
+ id="g42"
+ transform="matrix(1,0,0,-1,0,2048)"
+ style="fill:#ffffff;fill-rule:nonzero">
+ <path
+ style="color:#000000;display:block"
+ d="m 564,1588 v 102 h 920 v -102 z"
+ display="block"
+ id="path32"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;display:block"
+ d="M 1024,496 H 512 v 46 l 73,55 h 879 l 71,-55 v -46 z"
+ display="block"
+ id="path34"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;display:block"
+ d="M 1024,665 H 674 l 60,47 v 57 h 580 v -57 l 60,-47 z"
+ display="block"
+ id="path36"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;display:block"
+ d="M 1024,1211 H 734 v 46 l -60,58 h 700 l -60,-58 v -46 z"
+ display="block"
+ id="path38"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;display:block"
+ d="M 1024,1383 H 610 l -46,43 v 58 h 920 v -58 l -46,-43 z"
+ display="block"
+ id="path40"
+ inkscape:connector-curvature="0" />
+ </g>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ height="100%"
+ width="100%"
+ version="1.1"
+ viewBox="0 0 2048 2048"
+ id="svg70"
+ sodipodi:docname="wu.svg"
+ inkscape:version="0.92.2 2405546, 2018-03-11">
+ <metadata
+ id="metadata76">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs74" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="960"
+ inkscape:window-height="1060"
+ id="namedview72"
+ showgrid="false"
+ inkscape:zoom="0.11523438"
+ inkscape:cx="1041.3559"
+ inkscape:cy="1024"
+ inkscape:window-x="0"
+ inkscape:window-y="20"
+ inkscape:window-maximized="0"
+ inkscape:current-layer="svg70" />
+ <path
+ style="color:#000000;display:block;fill:#000000;fill-rule:nonzero"
+ d="m 1161,1706 h 170 v 137 h 274 V 1468 L 1383,1297 V 819 L 1553,649 V 444 h 153 V 205 H 341 v 239 h 153 v 205 l 171,170 v 478 l -222,171 v 375 h 273 v -137 h 171 v 137 h 274 z M 1639,376 H 409 V 273 H 1639 Z M 1484,580 H 564 V 444 h 920 z m -170,717 H 734 V 819 h 580 z m 222,239 v 239 h -137 v -137 h -308 v 137 H 956 V 1638 H 649 v 137 H 512 V 1536 Z M 1459,649 1356,751 H 693 L 588,649 Z m -110,716 127,103 H 572 l 128,-103 z"
+ display="block"
+ id="path54"
+ inkscape:connector-curvature="0" />
+ <g
+ id="g64"
+ transform="matrix(1,0,0,-1,0,2048)"
+ style="fill:#ffffff;fill-rule:nonzero">
+ <path
+ style="color:#000000;display:block"
+ d="M 1639,1672 H 409 v 103 h 1230 z"
+ display="block"
+ id="path56"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;display:block"
+ d="M 1484,1468 H 564 v 136 h 920 z"
+ display="block"
+ id="path58"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;display:block"
+ d="M 1314,751 H 734 v 478 h 580 z"
+ display="block"
+ id="path60"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;display:block"
+ d="M 1536,512 V 273 H 1399 V 410 H 1091 V 273 H 956 V 410 H 649 V 273 H 512 v 239 z"
+ display="block"
+ id="path62"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;display:block;fill:#ffffff;fill-rule:nonzero"
+ d="M 1459,649 1356,751 H 693 L 588,649 Z"
+ display="block"
+ id="path66"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;display:block;fill:#ffffff;fill-rule:nonzero"
+ d="m 1349,1365 127,103 H 572 l 128,-103 z"
+ display="block"
+ id="path68"
+ inkscape:connector-curvature="0" />
+</svg>
--- /dev/null
+<p>TODO</p>
--- /dev/null
+@import url("/base_pieces.css");
+
+piece.white.immobilizer {
+ background-image: url('/variants/Baroque/pieces/white_immobilizer.svg');
+}
+piece.black.immobilizer {
+ background-image: url('/variants/Baroque/pieces/black_immobilizer.svg');
+}
@import url("/base_pieces.css");
piece.black.cleopatra {
- background-image: url('/pieces/Benedict/black_cleopatra.svg');
+ background-image: url('/variants/Benedict/pieces/black_cleopatra.svg');
}
-
piece.white.cleopatra {
- background-image: url('/pieces/Benedict/white_cleopatra.svg');
+ background-image: url('/variants/Benedict/pieces/white_cleopatra.svg');
}
<li>Eggs hide either a bonus or malus: see full description.</li>
</ul>
-<a href="/variants/Chakart/complete_rules.html">Full rules description.</a>
+<a target="_blank" href="/variants/Chakart/complete_rules.html">
+ Full rules description.
+</a>
<p class="author">Charlotte Blard & Benjamin Auder (2020).</p>
@import url("/base_pieces.css");
piece.egg {
- background-image: url('/pieces/Chakart/egg.svg');
+ background-image: url('/variants/Chakart/pieces/egg.svg');
}
piece.mushroom {
- background-image: url('/pieces/Chakart/mushroom.svg');
+ background-image: url('/variants/Chakart/pieces/mushroom.svg');
}
piece.banana {
- background-image: url('/pieces/Chakart/banana.svg');
+ background-image: url('/variants/Chakart/pieces/banana.svg');
}
piece.bomb {
- background-image: url('/pieces/Chakart/bomb.svg');
+ background-image: url('/variants/Chakart/pieces/bomb.svg');
}
piece.white.invisible {
}
piece.remote-capture {
- background-image: url('/pieces/Chakart/shell.svg');
+ background-image: url('/variants/Chakart/pieces/shell.svg');
}
piece.white.mystery {
@import url("/base_pieces.css");
piece.black.antiking {
- background-image: url('/pieces/Antiking/black_antiking.svg');
+ background-image: url('/variants/_Antiking/pieces/black_antiking.svg');
}
piece.white.antiking {
- background-image: url('/pieces/Antiking/white_antiking.svg');
+ background-image: url('/variants/_Antiking/pieces/white_antiking.svg');
}