From 7379efc5a40788dbf093a4dd5613ca9fbe73cbcf Mon Sep 17 00:00:00 2001 From: Benjamin Auder Date: Sat, 23 Dec 2023 23:35:15 +0100 Subject: [PATCH] update --- TODO | 3 + variants.js | 4 +- variants/Coronation/class.js | 40 ++++ variants/Coronation/rules.html | 10 + variants/Coronation/style.css | 1 + variants/Crossing/class.js | 34 ++++ variants/Crossing/rules.html | 1 + variants/Crossing/style.css | 1 + variants/Cwda/class.js | 360 +++++++++++++++++++++++++++++++++ 9 files changed, 452 insertions(+), 2 deletions(-) create mode 100644 variants/Coronation/class.js create mode 100644 variants/Coronation/rules.html create mode 100644 variants/Coronation/style.css create mode 100644 variants/Crossing/class.js create mode 100644 variants/Crossing/rules.html create mode 100644 variants/Crossing/style.css create mode 100644 variants/Cwda/class.js diff --git a/TODO b/TODO index 275ed22..fac46e3 100644 --- a/TODO +++ b/TODO @@ -4,3 +4,6 @@ Dark Racing Kings ? Checkered-Teleport ? Hmm... non ? --> Otage, Emergo, Pacosako : fonction "buildPiece(arg1, arg2)" returns HTML element with 2 SVG or SVG + number ==> plus simple : deux classes, images superposées. + +https://fr.wikipedia.org/wiki/Unlur +Yoxii ? diff --git a/variants.js b/variants.js index bc77daf..9ff40a7 100644 --- a/variants.js +++ b/variants.js @@ -35,9 +35,9 @@ const variants = [ {name: 'Convert', desc: 'Convert enemy pieces'}, {name: 'Copycat', desc: 'Borrow powers'}, {name: 'Coregal', desc: 'Two royal pieces'}, -// {name: 'Coronation', desc: 'Long live the Queen'}, + {name: 'Coronation', desc: 'Long live the Queen'}, {name: 'Crazyhouse', desc: 'Captures reborn'}, -// {name: 'Crossing', desc: 'Cross the river'}, + {name: 'Crossing', desc: 'Cross the river'}, {name: 'Cylinder', desc: 'Neverending rows'}, // {name: 'Cwda', desc: 'New teams', disp: 'Different armies'}, {name: 'Dark', desc: 'In the shadow'}, diff --git a/variants/Coronation/class.js b/variants/Coronation/class.js new file mode 100644 index 0000000..bf3684a --- /dev/null +++ b/variants/Coronation/class.js @@ -0,0 +1,40 @@ +import ChessRules from "/base_rules.js"; + +export default class CoronationRules extends ChessRules { + + get hasSelfCaptures() { + return true; + } + + canSelfTake([x1, y1], [x2, y2]) { + const c = this.getColor(x1, y1); + if ( + this.board.some(row => + row.some(square => + square[0] == c && square[1] == 'q') + ) + ) { + // Already a queen on the board: no coronation + return false; + } + const [p1, p2] = [this.getPiece(x1, y1), this.getPiece(x2, y2)]; + return ((p1 == 'r' && p2 == 'b') || (p1 == 'b' && p2 == 'r')); + } + + getPotentialMovesOf(piece, [x, y]) { + const res = super.getPotentialMovesOf(piece, [x, y]); + if (['r', 'b'].includes(piece)) { + res.forEach(m => { + if ( + m.vanish.length == 2 && + m.appear.length == 1 && + m.vanish[1].c == m.vanish[0].c + ) { + m.appear[0].p = 'q'; + } + }); + } + return res; + } + +}; diff --git a/variants/Coronation/rules.html b/variants/Coronation/rules.html new file mode 100644 index 0000000..a050dcb --- /dev/null +++ b/variants/Coronation/rules.html @@ -0,0 +1,10 @@ +

+ If a side lacks a queen, then a special fusion move is allowed by + "capturing" a rook with a bishop (and conversely). The result of the + capture is a queen. +

+ +

+ Variant mentioned + here. +

diff --git a/variants/Coronation/style.css b/variants/Coronation/style.css new file mode 100644 index 0000000..290a6f4 --- /dev/null +++ b/variants/Coronation/style.css @@ -0,0 +1 @@ +@import url("/base_pieces.css") diff --git a/variants/Crossing/class.js b/variants/Crossing/class.js new file mode 100644 index 0000000..75665a5 --- /dev/null +++ b/variants/Crossing/class.js @@ -0,0 +1,34 @@ +import ChessRules from "/base_rules.js"; + +export default class CrossingRules extends ChessRules { + + getSvgChessboard() { + let svg = super.getSvgChessboard(); + return ( + svg.slice(0, -6) + + '' + ); + } + + getCurrentScore(move_s) { + const res = super.getCurrentScore(move_s); + if (res != "*") + return res; + // Turn has changed: + const color = V.GetOppTurn(this.turn); + const secondHalf = (color == 'w' ? [0, 1, 2, 3] : [4, 5, 6, 7]); + for (let move of move_s) { + if ( + move.appear.length >= 1 && + move.appear[0].p == 'k' && + secondHalf.includes(move.appear[0].x) + ) { + // Half-board is crossed + return color == "w" ? "1-0" : "0-1"; + } + } + return "*"; + } + +}; diff --git a/variants/Crossing/rules.html b/variants/Crossing/rules.html new file mode 100644 index 0000000..c5bb1ab --- /dev/null +++ b/variants/Crossing/rules.html @@ -0,0 +1 @@ +

Win by reaching the fifth rank with the king.

diff --git a/variants/Crossing/style.css b/variants/Crossing/style.css new file mode 100644 index 0000000..a3550bc --- /dev/null +++ b/variants/Crossing/style.css @@ -0,0 +1 @@ +@import url("/base_pieces.css"); diff --git a/variants/Cwda/class.js b/variants/Cwda/class.js new file mode 100644 index 0000000..393e407 --- /dev/null +++ b/variants/Cwda/class.js @@ -0,0 +1,360 @@ +import ChessRules from "/base_rules.js"; + +export default class CwdaRules extends ChessRules { + + static get Options() { + return { + select: ChessRules.Options.select.concat([ + { + label: "Army 1", + variable: "army1", + defaut: 'C', + options: [ + { label: "Colorbound Clobberers", value: 'C' }, + { label: "Nutty Knights", value: 'N' }, + { label: "Remarkable Rookies", value: 'R' }, + { label: "Fide", value: 'F' } + ] + }, + { + label: "Army 2", + variable: "army2", + defaut: 'C', + options: [ + { label: "Colorbound Clobberers", value: 'C' }, + { label: "Nutty Knights", value: 'N' }, + { label: "Remarkable Rookies", value: 'R' }, + { label: "Fide", value: 'F' } + ] + } + ]), + input: ChessRules.Options.input, + styles: ChessRules.Options.styles + }; + } + + static get PiecesMap() { + return { + // Colorbound Clobberers + 'C': { + 'r': 'd', + 'n': 'w', + 'b': 'f', + 'q': 'c', + 'k': 'm', + 'p': 'z' + }, + // Nutty Knights + 'N': { + 'r': 'g', + 'n': 'i', + 'b': 't', + 'q': 'l', + 'k': 'e', + 'p': 'v' + }, + // Remarkable Rookies + 'R': { + 'r': 's', + 'n': 'y', + 'b': 'h', + 'q': 'o', + 'k': 'a', + 'p': 'u' + } + }; + } + + genRandInitBaseFen() { + let s = FenUtil.setupPieces( + ['r', 'n', 'b', 'q', 'k', 'b', 'n', 'r'], + { + randomness: this.options["randomness"], + between: [{p1: 'k', p2: 'r'}], + diffCol: ['b'], + flags: ['r', 'k'] + } + ); + let pawnLines = { + w: "pppppppp", + b: "pppppppp" + }; + for (const c of ['w', 'b']) { + const army = "army" + (c == 'w' ? "1" : "2"); + if (this.options[army] != 'F') { + for (let obj of [s, pawnLines]) { + obj[c] = obj[c].split("") + .map(p => V.PiecesMap[this.options[army]][p]).join(""); + } + } + } + return { + fen: s.b.join("") + "/" + + pawnLines['b'] + "/8/8/8/8/" + pawnLines['w'].toUpperCase() + + "/" + s.w.join("").toUpperCase(), + o: {flags: s.flags} + }; + } + + getPartFen(o) { + return Object.assign( + { "armies": this.options["army1"] + this.options["army2"] }, + super.getPartFen(o) + ); + } + + setOtherVariables(fenParsed) { + super.setOtherVariables(fenParsed); + this.army1 = fenParsed.armies.charAt(0); + this.army2 = fenParsed.armies.charAt(1); + } + + isKing(x, y, p) { + if (!p) + p = this.getPiece(x, y); + return (super.isKing(x, y, p) || ['a', 'e', 'm'].includes(p)); + } + + // Helper to describe pieces movements + static get steps() { + return { + // Dabbabah + 'd': [ + [-2, 0], + [0, -2], + [2, 0], + [0, 2] + ], + // Alfil + 'a': [ + [2, 2], + [2, -2], + [-2, 2], + [-2, -2] + ], + // Ferz + 'f': [ + [1, 1], + [1, -1], + [-1, 1], + [-1, -1] + ], + // Wazir + 'w': [ + [-1, 0], + [0, -1], + [1, 0], + [0, 1] + ], + // Threeleaper + '$3': [ + [-3, 0], + [0, -3], + [3, 0], + [0, 3] + ], + // Narrow knight + '$n': [ + [-2, -1], + [-2, 1], + [2, -1], + [2, 1] + ] + }; + } + + pieces(color, x, y) { + const res = super.pieces(color, x, y); + return Object.assign( + { + 'd': { + "class": "c_rook", + both: [ + {steps: V.steps.b}, + {steps: V.steps.d, range: 1} + ] + }, + 'w': { + "class": "c_knight", + both: [ + {steps: V.steps.a, range: 1}, + {steps: V.steps.r, range: 1} + ] + }, + 'f': { + "class": "c_bishop", + both: [ + {steps: V.steps.d, range: 1}, + {steps: V.steps.a, range: 1}, + {steps: V.steps.b, range: 1} + ] + }, + 'c': { + "class": "c_queen", + both: [ + {steps: V.steps.b}, + {steps: V.steps.n, range: 1} + ] + }, + 'm': { moveas: 'k' }, + 'z': { moveas: 'p' }, + 'g': { + + }, + 'i': { + + }, + 't': { + + }, + 'l': { + + }, + 'e': { moveas: 'k' }, + 'v': { moveas: 'p' }, + 's': { + + }, + 'y': { + + }, + 'h': { + + }, + 'o': { + + }, + 'a': { moveas: 'k' }, + 'u': { moveas: 'p' } + }, + res + ); + + + + + + getPotentialN_rookMoves(sq) { + const c = this.turn; + const rookSteps = [ [0, -1], [0, 1], [c == 'w' ? -1 : 1, 0] ]; + const backward = (c == 'w' ? 1 : -1); + const kingSteps = [ [backward, -1], [backward, 0], [backward, 1] ]; + return ( + this.getSlideNJumpMoves(sq, rookSteps).concat( + this.getSlideNJumpMoves(sq, kingSteps, 1)) + ); + } + + getPotentialN_knightMoves(sq) { + return ( + this.getSlideNJumpMoves(sq, V.steps.$n, 1).concat( + this.getSlideNJumpMoves(sq, V.steps.f, 1)) + ); + } + + getPotentialN_bishopMoves(sq) { + const backward = (this.turn == 'w' ? 1 : -1); + const kingSteps = [ + [0, -1], [0, 1], [backward, -1], [backward, 0], [backward, 1] + ]; + const forward = -backward; + const knightSteps = [ + [2*forward, -1], [2*forward, 1], [forward, -2], [forward, 2] + ]; + return ( + this.getSlideNJumpMoves(sq, knightSteps, 1).concat( + this.getSlideNJumpMoves(sq, kingSteps, 1)) + ); + } + + getPotentialN_queenMoves(sq) { + const backward = (this.turn == 'w' ? 1 : -1); + const forward = -backward; + const kingSteps = [ + [forward, -1], [forward, 1], + [backward, -1], [backward, 0], [backward, 1] + ]; + const knightSteps = [ + [2*forward, -1], [2*forward, 1], [forward, -2], [forward, 2] + ]; + const rookSteps = [ [0, -1], [0, 1], [forward, 0] ]; + return ( + this.getSlideNJumpMoves(sq, rookSteps).concat( + this.getSlideNJumpMoves(sq, kingSteps, 1)).concat( + this.getSlideNJumpMoves(sq, knightSteps, 1)) + ); + } + + getPotentialR_rookMoves(sq) { + return this.getSlideNJumpMoves(sq, V.steps.r, 4); + } + + getPotentialR_knightMoves(sq) { + return ( + this.getSlideNJumpMoves(sq, V.steps.d, 1).concat( + this.getSlideNJumpMoves(sq, V.steps.w, 1)) + ); + } + + getPotentialR_bishopMoves(sq) { + return ( + this.getSlideNJumpMoves(sq, V.steps.d, 1).concat( + this.getSlideNJumpMoves(sq, V.steps.f, 1)).concat( + this.getSlideNJumpMoves(sq, V.steps.$3, 1)) + ); + } + + getPotentialR_queenMoves(sq) { + return ( + this.getSlideNJumpMoves(sq, V.steps.r).concat( + this.getSlideNJumpMoves(sq, V.steps.n, 1)) + ); + } + + case V.PAWN: { + // Can promote in anything from the two current armies + let promotions = []; + for (let army of ["army1", "army2"]) { + if (army == "army2" && this.army2 == this.army1) break; + switch (this[army]) { + case 'C': { + Array.prototype.push.apply(promotions, + [V.C_ROOK, V.C_KNIGHT, V.C_BISHOP, V.C_QUEEN]); + break; + } + case 'N': { + Array.prototype.push.apply(promotions, + [V.N_ROOK, V.N_KNIGHT, V.N_BISHOP, V.N_QUEEN]); + break; + } + case 'R': { + Array.prototype.push.apply(promotions, + [V.R_ROOK, V.R_KNIGHT, V.R_BISHOP, V.R_QUEEN]); + break; + } + case 'F': { + Array.prototype.push.apply(promotions, + [V.ROOK, V.KNIGHT, V.BISHOP, V.QUEEN]); + break; + } + } + } + return super.getPotentialPawnMoves(sq, promotions); + } + default: return super.getPotentialMovesFrom(sq); + } + + getCastleMoves([x, y]) { + const color = this.getColor(x, y); + let finalSquares = [ [2, 3], [V.size.y - 2, V.size.y - 3] ]; + if ( + (color == 'w' && this.army1 == 'C') || + (color == 'b' && this.army2 == 'C') + ) { + // Colorbound castle long in an unusual way: + finalSquares[0] = [1, 2]; + } + return super.getCastleMoves([x, y], finalSquares); + } + +}; -- 2.44.0