X-Git-Url: https://git.auder.net/?a=blobdiff_plain;f=client%2Fsrc%2Fvariants%2FSchess.js;h=5f5857197751990053899f7c95effbad801f1a76;hb=4313762da3237b04f204e121a20cab3ba7bb5dd2;hp=ebc2c7c26f2d289053d6404bab805ebf23c42e33;hpb=40ac07d9dfc8a58911550aa9c87a0f0736723f1f;p=vchess.git diff --git a/client/src/variants/Schess.js b/client/src/variants/Schess.js index ebc2c7c2..5f585719 100644 --- a/client/src/variants/Schess.js +++ b/client/src/variants/Schess.js @@ -1,6 +1,7 @@ import { ChessRules, PiPo } from "@/base_rules"; export class SchessRules extends ChessRules { + static get PawnSpecs() { return Object.assign( {}, @@ -20,19 +21,19 @@ export class SchessRules extends ChessRules { return 'e'; } + static get NOTHING() { + return 'o'; + } + static get PIECES() { return ChessRules.PIECES.concat([V.HAWK, V.ELEPHANT]); } getPpath(b) { - if ([V.HAWK, V.ELEPHANT].includes(b[1])) return "Schess/" + b; + if ([V.HAWK, V.ELEPHANT, V.NOTHING].includes(b[1])) return "Schess/" + b; return b; } - // TODO: maybe changes could be done to this method to show "empty" - // instead of a piece to not use a pocket piece... -// getPPpath(b) { } - static IsGoodFen(fen) { if (!ChessRules.IsGoodFen(fen)) return false; const fenParsed = V.ParseFen(fen); @@ -50,7 +51,7 @@ export class SchessRules extends ChessRules { setFlags(fenflags) { super.setFlags(fenflags); //castleFlags this.pieceFlags = { - w: [...Array(8)], //pawns can move 2 squares? + w: [...Array(8)], //pieces can generate Hawk or Elephant? b: [...Array(8)] }; const flags = fenflags.substr(4); //skip first 4 letters, for castle @@ -77,9 +78,9 @@ export class SchessRules extends ChessRules { ); } - static GenRandInitFen(randomness) { + static GenRandInitFen(options) { return ( - ChessRules.GenRandInitFen(randomness).slice(0, -2) + + ChessRules.GenRandInitFen(options).slice(0, -2) + // Add pieceFlags + pocket "1111111111111111 - 1111" ); @@ -119,12 +120,12 @@ export class SchessRules extends ChessRules { const fenParsed = V.ParseFen(fen); this.pocket = { "w": { - h: parseInt(fenParsed.pocket[0]), - e: parseInt(fenParsed.pocket[1]) + h: parseInt(fenParsed.pocket[0], 10), + e: parseInt(fenParsed.pocket[1], 10) }, "b": { - h: parseInt(fenParsed.pocket[2]), - e: parseInt(fenParsed.pocket[3]) + h: parseInt(fenParsed.pocket[2], 10), + e: parseInt(fenParsed.pocket[3], 10) } }; } @@ -141,12 +142,22 @@ export class SchessRules extends ChessRules { default: moves = super.getPotentialMovesFrom([x, y]); } + // For moves presentation when choices: + const unshiftNothing = (m) => { + const a = m.appear[0]; + m.appear.unshift(new PiPo({ + p: V.NOTHING, + c: 'o', + x: a.x, + y: a.y + })); + }; // Post-processing: add choices for hawk and elephant, // except for moves letting the king under check. const color = this.turn; if (Object.values(this.pocket[color]).some(v => v > 0)) { const firstRank = (color == "w" ? 7 : 0); - let pocketMoves = []; + let validMoves = []; moves.forEach(m => { let inCheckAfter = false; this.play(m); @@ -155,16 +166,19 @@ export class SchessRules extends ChessRules { if (!inCheckAfter) { for (let pp of ['h', 'e']) { if (this.pocket[color][pp] > 0) { + let shift = (m.appear[0].p == V.NOTHING ? 1 : 0); if ( m.start.x == firstRank && this.pieceFlags[color][m.start.y] && ( - m.appear.length == 1 || + m.appear.length == shift+1 || // Special castle case: is initial king square free? - ![m.appear[0].y, m.appear[1].y].includes(m.vanish[0].y) + ![m.appear[shift].y, m.appear[shift+1].y] + .includes(m.vanish[0].y) ) ) { let pMove = JSON.parse(JSON.stringify(m)); + if (shift == 1) pMove.appear.shift(); // NOTE: unshift instead of push, for choices presentation pMove.appear.unshift(new PiPo({ p: pp, @@ -172,41 +186,48 @@ export class SchessRules extends ChessRules { x: x, y: y })); - pocketMoves.push(pMove); + validMoves.push(pMove); + if (shift == 0) unshiftNothing(m); } + shift = (m.appear[0].p == V.NOTHING ? 1 : 0); if ( - m.appear.length == 2 && - ![m.appear[0].y, m.appear[1].y].includes(m.vanish[1].y) + m.appear.length >= 2 + shift && + m.vanish.length == 2 && + ![m.appear[shift].y, m.appear[shift+1].y] + .includes(m.vanish[1].y) ) { // Special castle case: rook flag was necessarily on let pMove = JSON.parse(JSON.stringify(m)); + if (shift == 1) pMove.appear.shift(); pMove.appear.unshift(new PiPo({ p: pp, c: color, x: m.vanish[1].x, y: m.vanish[1].y })); - pocketMoves.push(pMove); + validMoves.push(pMove); + if (shift == 0) unshiftNothing(m); } } } + // Unshift, to show the empty square on the left: + validMoves.unshift(m); } }); - // NOTE: the order matter, for presentation on screen - moves = moves.concat(pocketMoves); + moves = validMoves; } return moves; } getPotentialHawkMoves(sq) { return this.getSlideNJumpMoves(sq, V.steps[V.BISHOP]).concat( - this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], "oneStep") + this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], 1) ); } getPotentialElephantMoves(sq) { return this.getSlideNJumpMoves(sq, V.steps[V.ROOK]).concat( - this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], "oneStep") + this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], 1) ); } @@ -221,29 +242,24 @@ export class SchessRules extends ChessRules { isAttackedByHawk(sq, color) { return ( this.isAttackedBySlideNJump(sq, color, V.HAWK, V.steps[V.BISHOP]) || - this.isAttackedBySlideNJump( - sq, - color, - V.HAWK, - V.steps[V.KNIGHT], - "oneStep" - ) + this.isAttackedBySlideNJump(sq, color, V.HAWK, V.steps[V.KNIGHT], 1) ); } isAttackedByElephant(sq, color) { return ( this.isAttackedBySlideNJump(sq, color, V.ELEPHANT, V.steps[V.ROOK]) || - this.isAttackedBySlideNJump( - sq, - color, - V.ELEPHANT, - V.steps[V.KNIGHT], - "oneStep" - ) + this.isAttackedBySlideNJump(sq, color, V.ELEPHANT, V.steps[V.KNIGHT], 1) ); } + filterValid(moves) { + if (Object.values(this.pocket[this.turn]).some(v => v > 0)) + // Undercheck tests done in getPotentialMovesFrom() + return moves; + return super.filterValid(moves); + } + prePlay(move) { super.prePlay(move); if (move.appear.length >= 2) { @@ -256,9 +272,18 @@ export class SchessRules extends ChessRules { } postPlay(move) { - super.postPlay(move); const color = move.vanish[0].c; - const oppCol = V.GetOppCol(color); + const piece = move.vanish[0].p; + // Update king position + flags + if (piece == V.KING) { + const shift = + ([V.HAWK, V.ELEPHANT, V.NOTHING].includes(move.appear[0].p) ? 1 : 0); + this.kingPos[color][0] = move.appear[shift].x; + this.kingPos[color][1] = move.appear[shift].y; + } + this.updateCastleFlags(move, piece); + + const oppCol = this.turn; const firstRank = (color == 'w' ? 7 : 0); const oppFirstRank = 7 - firstRank; // Does this move turn off a piece init square flag? @@ -266,7 +291,7 @@ export class SchessRules extends ChessRules { if (this.pieceFlags[color][move.start.y]) this.pieceFlags[color][move.start.y] = false; // Special castle case: - if (move.appear.length >= 2) { + if (move.appear.length >= 2 && move.vanish.length == 2) { const L = move.appear.length; if (move.appear[L-1].p == V.ROOK) this.pieceFlags[color][move.vanish[1].y] = false; @@ -293,22 +318,34 @@ export class SchessRules extends ChessRules { static get VALUES() { return Object.assign( - {}, - ChessRules.VALUES, - { 'h': 5, 'e': 7 } + { + 'h': 5, + 'e': 7 + }, + ChessRules.VALUES ); } getNotation(move) { - if ( - move.appear.length >= 2 && - [V.HAWK, V.ELEPHANT].includes(move.appear[0].p) - ) { - const suffix = "/" + move.appear[0].p.toUpperCase(); - let cmove = JSON.parse(JSON.stringify(move)); - cmove.appear.shift(); - return super.getNotation(cmove) + suffix; + if (move.appear.length >= 2) { + const pPieceAppear = [V.HAWK, V.ELEPHANT].includes(move.appear[0].p); + const nothingAppear = (move.appear[0].p == V.NOTHING); + if (pPieceAppear || nothingAppear) { + let suffix = ""; + if (pPieceAppear) { + suffix = "/" + move.appear[0].p.toUpperCase(); + if (move.appear.length == 3) { + // Castling; indicate square + suffix += + V.CoordsToSquare({ x: move.appear[0].x, y: move.appear[0].y }); + } + } + let cmove = JSON.parse(JSON.stringify(move)); + cmove.appear.shift(); + return super.getNotation(cmove) + suffix; + } } return super.getNotation(move); } + };