const variants = [
-// { name: 'Absorption', desc: 'Absorb powers' },
-// { name: 'Alapo', desc: 'Geometric Chess' },
+ // TODO: https://mancala.fandom.com/wiki/William_Daniel_Troyka Cleopatra chess
+ { name: 'Absorption', desc: 'Absorb powers' },
+// { name: 'Alapo', desc: 'Geometric Chess' }, //TODO
// { name: 'Alice', desc: 'Both sides of the mirror' },
// { name: 'Align4', desc: 'Align four pawns' },
// { name: 'Allmate', desc: 'Mate any piece' },
{ name: "Benedict", desc: "Change colors" },
// { name: 'Berolina', desc: 'Pawns move diagonally' },
// { name: 'Bicolour', desc: 'Harassed kings' },
-// { name: 'Bishopawns', desc: 'Bishop versus pawns', disp: 'Bishop-Pawns' },
// { name: 'Brotherhood', desc: 'Friendly pieces' },
{ name: 'Cannibal', desc: 'Capture powers' },
// { name: 'Capablanca', desc: 'Capablanca Chess', disp: 'Capablanca Chess' },
// { name: 'Kinglet', desc: 'Protect your pawns' },
// { name: 'Kingsmaker', desc: 'Promote into kings' },
// { name: 'Knightmate', desc: 'Mate the knight' },
-// { name: 'Knightpawns', desc: 'Knight versus pawns', disp: 'Knight-Pawns' },
// { name: 'Knightrelay', desc: 'Move like a knight' },
// { name: 'Konane', desc: 'Hawaiian Checkers' },
// { name: 'Koopa', desc: 'Stun & kick pieces' },
// { name: 'Perfect', desc: 'Powerful pieces' },
// { name: 'Pocketknight', desc: 'Knight in pocket', disp: 'Pocket Knight' },
// { name: 'Progressive', desc: 'Play more and more moves' },
-// { name: 'Queenpawns', desc: 'Queen versus pawns', disp: 'Queen-Pawns' },
// { name: 'Racingkings', desc: 'Kings cross the 8x8 board', disp: 'Racing Kings' },
// { name: 'Rampage', desc: 'Move under cover' },
// { name: 'Relayup', desc: 'Upgrade pieces', disp: 'Relay-up' },
// { name: 'Refusal', desc: 'Do not play that!' },
// { name: 'Rollerball', desc: 'As in the movie' },
// { name: 'Rococo', desc: 'Capture on the edge' },
-// { name: 'Rookpawns', desc: 'Rook versus pawns', disp: 'Rook-Pawns' },
// { name: 'Royalrace', desc: 'Kings cross the 11x11 board', disp: 'Royal Race' },
// { name: 'Rugby', desc: 'Transform an essay' },
-// { name: 'Schess', desc: 'Seirawan-Harper Chess', disp: 'Seirawan-Harper Chess' },
+// { name: 'Schess', desc: 'Seirawan-Harper Chess', disp: 'S-Chess' },
// { name: 'Screen', desc: 'Free initial setup' },
// { name: 'Selfabsorb', desc: 'Fusion pieces (v2)', disp: 'Self-Absorption' },
// { name: 'Shako', desc: 'Non-conformism and utopia' },
--- /dev/null
+import ChessRules from "/base_rules.js";
+
+export default class AbsorptionRules extends ChessRules {
+
+ static get Options() {
+ return {
+ select: C.Options.select,
+ check: [],
+ styles: [
+ "balance",
+ "capture",
+ "cylinder",
+ "dark",
+ "doublemove",
+ "progressive",
+ "recycle",
+ "rifle", //TODO? absorb powers from afar?
+ "teleport",
+ "zen"
+ ]
+ };
+ }
+
+ pieces(color) {
+ const fusions = {{
+ // amazon
+ 'a': {
+ "class": "amazon",
+ steps: [
+ [0, 1], [0, -1], [1, 0], [-1, 0],
+ [1, 1], [1, -1], [-1, 1], [-1, -1]
+ ]
+
+//TODO: steps object avec range + steps... "moving"?
+
+ steps: [
+ [1, 2], [1, -2], [-1, 2], [-1, -2],
+ [2, 1], [-2, 1], [2, -1], [-2, -1]
+ ],
+ steps: [[0, 1], [0, -1], [1, 0], [-1, 0]]
+ },
+ // empress
+ 'e': {
+ "class": "empress",
+ steps: [
+ [1, 2], [1, -2], [-1, 2], [-1, -2],
+ [2, 1], [-2, 1], [2, -1], [-2, -1]
+ ],
+ },
+ // princess
+ 'b': {
+ "class": "bishop",
+ steps: [[1, 1], [1, -1], [-1, 1], [-1, -1]]
+ },
+ // queen
+ 'q': {
+ "class": "queen",
+ },
+
+ },
+ return (
+ Object.assign(
+ super.pieces(color)
+ )
+ );
+ }
+
+ static get MergeComposed() {
+ return {
+ "be": "a",
+ "bs": "s",
+ "er": "e",
+ "rs": "a",
+ "eq": "a",
+ "qs": "a",
+ "ee": "e",
+ "es": "a",
+ "ss": "s"
+ };
+ }
+
+ static Fusion(p1, p2) {
+ if (p1 == V.KING) return p1;
+ if (p1 == V.PAWN) return p2;
+ if (p2 == V.PAWN) return p1;
+ if ([p1, p2].includes(V.KNIGHT)) {
+ if ([p1, p2].includes(V.QUEEN)) return V.QN;
+ if ([p1, p2].includes(V.ROOK)) return V.RN;
+ if ([p1, p2].includes(V.BISHOP)) return V.BN;
+ // p1 or p2 already have knight + other piece
+ return (p1 == V.KNIGHT ? p2 : p1);
+ }
+ if ([p1, p2].includes(V.QN)) return V.QN;
+ for (let p of [p1, p2]) {
+ if ([V.BN, V.RN].includes(p))
+ return V.MergeComposed[[p1, p2].sort().join("")];
+ }
+ // bishop + rook, or queen + [bishop or rook]
+ return V.QUEEN;
+ }
+
+ getPotentialMovesFrom(sq) {
+ let moves = [];
+ const piece = this.getPiece(sq[0], sq[1]);
+ switch (piece) {
+ case V.RN:
+ moves =
+ super.getPotentialRookMoves(sq).concat(
+ super.getPotentialKnightMoves(sq));
+ break;
+ case V.BN:
+ moves =
+ super.getPotentialBishopMoves(sq).concat(
+ super.getPotentialKnightMoves(sq));
+ break;
+ case V.QN:
+ moves =
+ super.getPotentialQueenMoves(sq).concat(
+ super.getPotentialKnightMoves(sq));
+ break;
+ default:
+ moves = super.getPotentialMovesFrom(sq);
+ }
+ // Filter out capturing promotions (except one),
+ // because they are all the same.
+ moves = moves.filter(m => {
+ return (
+ m.vanish.length == 1 ||
+ m.vanish[0].p != V.PAWN ||
+ [V.PAWN, V.QUEEN].includes(m.appear[0].p)
+ );
+ });
+ moves.forEach(m => {
+ if (
+ m.vanish.length == 2 &&
+ m.appear.length == 1 &&
+ piece != m.vanish[1].p
+ ) {
+ // Augment pieces abilities in case of captures
+ m.appear[0].p = V.Fusion(piece, m.vanish[1].p);
+ }
+ });
+ return moves;
+ }
+
+ isAttacked(sq, color) {
+ return (
+ super.isAttacked(sq, color) ||
+ this.isAttackedByBN(sq, color) ||
+ this.isAttackedByRN(sq, color) ||
+ this.isAttackedByQN(sq, color)
+ );
+ }
+
+ isAttackedByBN(sq, color) {
+ return (
+ this.isAttackedBySlideNJump(sq, color, V.BN, V.steps[V.BISHOP]) ||
+ this.isAttackedBySlideNJump(
+ sq, color, V.BN, V.steps[V.KNIGHT], 1)
+ );
+ }
+
+ isAttackedByRN(sq, color) {
+ return (
+ this.isAttackedBySlideNJump(sq, color, V.RN, V.steps[V.ROOK]) ||
+ this.isAttackedBySlideNJump(
+ sq, color, V.RN, V.steps[V.KNIGHT], 1)
+ );
+ }
+
+ isAttackedByQN(sq, color) {
+ return (
+ this.isAttackedBySlideNJump(
+ sq, color, V.QN, V.steps[V.BISHOP].concat(V.steps[V.ROOK])) ||
+ this.isAttackedBySlideNJump(
+ sq, color, V.QN, V.steps[V.KNIGHT], 1)
+ );
+ }
+
+ static get VALUES() {
+ return Object.assign(
+ { a: 12, e: 7, s: 5 },
+ ChessRules.VALUES
+ );
+ }
+
+ getNotation(move) {
+ let notation = super.getNotation(move);
+ if (move.vanish[0].p != V.PAWN && move.appear[0].p != move.vanish[0].p)
+ // Fusion (not from a pawn: handled in ChessRules)
+ notation += "=" + move.appear[0].p.toUpperCase();
+ return notation;
+ }
+
+};