X-Git-Url: https://git.auder.net/?a=blobdiff_plain;f=client%2Fsrc%2Fvariants%2FChakart.js;h=86a867a9ef9ea728e5952cdfbe2bce27afdb8051;hb=ccbb9dfc6459cb3cd80a21abf945693a3fe1b2d5;hp=bfbca52e31f76a16352d13578fa82c65987daec0;hpb=032ecd58543d1182b41da0c45b272e99a3014ad8;p=vchess.git diff --git a/client/src/variants/Chakart.js b/client/src/variants/Chakart.js index bfbca52e..86a867a9 100644 --- a/client/src/variants/Chakart.js +++ b/client/src/variants/Chakart.js @@ -4,6 +4,7 @@ import { ArrayFun } from "@/utils/array"; import { randInt } from "@/utils/alea"; export class ChakartRules extends ChessRules { + static get PawnSpecs() { return SuicideRules.PawnSpecs; } @@ -29,22 +30,6 @@ export class ChakartRules extends ChessRules { return true; } - hoverHighlight(x, y) { - if (this.subTurn == 1) return false; - const L = this.firstMove.length; - const fm = this.firstMove[L-1]; - if (fm.end.effect != 0) return false; - const deltaX = Math.abs(fm.appear[0].x - x); - const deltaY = Math.abs(fm.appear[0].y - y); - return ( - (this.board[x][y] == V.EMPTY || this.getColor(x, y) == 'a') && - ( - (fm.vanish[0].p == V.ROOK && deltaX == 1 && deltaY == 1) || - (fm.vanish[0].p == V.BISHOP && deltaX + deltaY == 1) - ) - ); - } - static get IMMOBILIZE_CODE() { return { 'p': 's', @@ -115,8 +100,12 @@ export class ChakartRules extends ChessRules { getPPpath(m) { if (!!m.promoteInto) return m.promoteInto; + if (m.appear.length == 0 && m.vanish.length == 1) + // King 'remote shell capture', on an adjacent square: + return this.getPpath(m.vanish[0].c + m.vanish[0].p); let piece = m.appear[0].p; if (Object.keys(V.IMMOBILIZE_DECODE).includes(piece)) + // Promotion by capture into immobilized piece: do not reveal! piece = V.IMMOBILIZE_DECODE[piece]; return this.getPpath(m.appear[0].c + piece); } @@ -148,7 +137,7 @@ export class ChakartRules extends ChessRules { if (['K', 'k', 'L', 'l'].includes(row[i])) kings[row[i]]++; if (V.PIECES.includes(row[i].toLowerCase())) sumElts++; else { - const num = parseInt(row[i]); + const num = parseInt(row[i], 10); if (isNaN(num)) return false; sumElts += num; } @@ -210,27 +199,28 @@ export class ChakartRules extends ChessRules { setOtherVariables(fen) { super.setOtherVariables(fen); - const fenParsed = V.ParseFen(fen); // Initialize captured pieces' counts from FEN + const captured = + V.ParseFen(fen).captured.split("").map(x => parseInt(x, 10)); this.captured = { w: { - [V.PAWN]: parseInt(fenParsed.captured[0]), - [V.ROOK]: parseInt(fenParsed.captured[1]), - [V.KNIGHT]: parseInt(fenParsed.captured[2]), - [V.BISHOP]: parseInt(fenParsed.captured[3]), - [V.QUEEN]: parseInt(fenParsed.captured[4]), - [V.KING]: parseInt(fenParsed.captured[5]) + [V.PAWN]: captured[0], + [V.ROOK]: captured[1], + [V.KNIGHT]: captured[2], + [V.BISHOP]: captured[3], + [V.QUEEN]: captured[4], + [V.KING]: captured[5] }, b: { - [V.PAWN]: parseInt(fenParsed.captured[6]), - [V.ROOK]: parseInt(fenParsed.captured[7]), - [V.KNIGHT]: parseInt(fenParsed.captured[8]), - [V.BISHOP]: parseInt(fenParsed.captured[9]), - [V.QUEEN]: parseInt(fenParsed.captured[10]), - [V.KING]: parseInt(fenParsed.captured[11]) + [V.PAWN]: captured[6], + [V.ROOK]: captured[7], + [V.KNIGHT]: captured[8], + [V.BISHOP]: captured[9], + [V.QUEEN]: captured[10], + [V.KING]: captured[11] } }; - this.firstMove = []; + this.effects = []; this.subTurn = 1; } @@ -317,12 +307,10 @@ export class ChakartRules extends ChessRules { } else { // Subturn == 2 - const L = this.firstMove.length; - const fm = this.firstMove[L-1]; - switch (fm.end.effect) { - // case 0: a click is required (banana or bomb) + const L = this.effects.length; + switch (this.effects[L-1]) { case "kingboo": - // Exchange position with any piece, + // Exchange position with any visible piece, // except pawns if arriving on last rank. const lastRank = { 'w': 0, 'b': 7 }; const color = this.turn; @@ -330,12 +318,13 @@ export class ChakartRules extends ChessRules { for (let i=0; i<8; i++) { for (let j=0; j<8; j++) { const colIJ = this.getColor(i, j); + const pieceIJ = this.getPiece(i, j); if ( (i != x || j != y) && this.board[i][j] != V.EMPTY && + pieceIJ != V.INVISIBLE_QUEEN && colIJ != 'a' ) { - const pieceIJ = this.getPiece(i, j); if ( (pieceIJ != V.PAWN || x != lastRank[colIJ]) && (allowLastRank || i != lastRank[color]) @@ -359,71 +348,21 @@ export class ChakartRules extends ChessRules { if (x >= V.size.x) moves = this.getReserveMoves([x, y]); break; case "daisy": - // Play again with the same piece - if (fm.appear[0].x == x && fm.appear[0].y == y) - moves = super.getPotentialMovesFrom([x, y]); + // Play again with any piece + moves = super.getPotentialMovesFrom([x, y]); break; } } return moves; } - // Helper for getBasicMove() + // Helper for getBasicMove(): banana/bomb effect getRandomSquare([x, y], steps) { - const validSteps = steps.filter(s => { - const [i, j] = [x + s[0], y + s[1]]; - return ( - V.OnBoard(i, j) && - (this.board[i][j] == V.EMPTY || this.getColor(i, j) == 'a') - ); - }); - if (validSteps.length == 0) - // Can happen after mushroom jump - return [x, y]; + const validSteps = steps.filter(s => V.OnBoard(x + s[0], y + s[1])); const step = validSteps[randInt(validSteps.length)]; return [x + step[0], y + step[1]]; } - canMove([x, y], piece) { - const color = this.getColor(x, y); - const oppCol = V.GetOppCol(color); - piece = piece || this.getPiece(x, y); - if (piece == V.PAWN) { - const forward = (color == 'w' ? -1 : 1); - return ( - V.OnBoard(x + forward, y) && - ( - this.board[x + forward][y] != oppCol || - ( - V.OnBoard(x + forward, y + 1) && - this.board[x + forward][y + 1] != V.EMPTY && - this.getColor[x + forward, y + 1] == oppCol - ) || - ( - V.OnBoard(x + forward, y - 1) && - this.board[x + forward][y - 1] != V.EMPTY && - this.getColor[x + forward, y - 1] == oppCol - ) - ) - ); - } - // Checking one step is enough: - const steps = - [V.KING, V.QUEEN].includes(piece) - ? V.steps[V.ROOK].concat(V.steps[V.BISHOP]) - : V.steps[piece]; - for (let step of steps) { - const [i, j] = [x + step[0], y + step[1]]; - if ( - V.OnBoard(i, j) && - (this.board[i][j] == V.EMPTY || this.getColor(i, j) != color) - ) { - return true; - } - } - return false; - } - // Apply mushroom, bomb or banana effect (hidden to the player). // Determine egg effect, too, and apply its first part if possible. getBasicMove_aux(psq1, sq2, tr, initMove) { @@ -467,11 +406,11 @@ export class ChakartRules extends ChessRules { // The move starts normally, on board: let move = super.getBasicMove([x1, y1], [x2, y2], tr); if (!!tr) move.promoteInto = tr.c + tr.p; //in case of (chomped...) - const L = this.firstMove.length; + const L = this.effects.length; if ( [V.PAWN, V.KNIGHT].includes(piece1) && !!initMove && - (this.subTurn == 1 || this.firstMove[L-1].end.effect == "daisy") + (this.subTurn == 1 || this.effects[L-1] == "daisy") ) { switch (piece1) { case V.PAWN: { @@ -539,12 +478,13 @@ export class ChakartRules extends ChessRules { const oppLastRank = (color == 'w' ? 7 : 0); for (let i=0; i<8; i++) { for (let j=0; j<8; j++) { + const piece = this.getPiece(i, j); if ( (i != move.vanish[0].x || j != move.vanish[0].y) && this.board[i][j] != V.EMPTY && + piece != V.INVISIBLE_QUEEN && this.getColor(i, j) == color ) { - const piece = this.getPiece(i, j); if (piece != V.KING && (piece != V.PAWN || i != oppLastRank)) pieces.push({ x: i, y: j, p: piece }); } @@ -579,27 +519,10 @@ export class ChakartRules extends ChessRules { // No egg effects at subTurn 2 return; // 1) Determine the effect (some may be impossible) - let effects = ["kingboo", "koopa", "chomp", "bowser"]; + let effects = ["kingboo", "koopa", "chomp", "bowser", "daisy"]; if (Object.values(this.captured[color1]).some(c => c >= 1)) effects.push("toadette"); const lastRank = { 'w': 0, 'b': 7 }; - let canPlayAgain = undefined; - if ( - move.appear[0].p == V.PAWN && - move.appear[0].x == lastRank[color1] - ) { - // Always possible: promote into a queen, rook or king - canPlayAgain = true; - } - else { - move.end.effect = "daisy"; - V.PlayOnBoard(this.board, move); - const square = [move.appear[0].x, move.appear[0].y]; - canPlayAgain = this.canMove(square, piece1); - V.UndoOnBoard(this.board, move); - delete move.end["effect"]; - } - if (canPlayAgain) effects.push("daisy"); if ( this.board.some((b,i) => b.some(cell => { @@ -665,17 +588,22 @@ export class ChakartRules extends ChessRules { ]; if ( V.OnBoard(i, j) && - (this.board[i][j] == V.EMPTY || this.getColor(i, j) == 'a') + ( + this.board[i][j] == V.EMPTY || + this.getPiece(i, j) == V.INVISIBLE_QUEEN || + this.getColor(i, j) == 'a' + ) ) { move.appear[0].x = i; move.appear[0].y = j; if (this.board[i][j] != V.EMPTY) { const object = this.getPiece(i, j); + const color = this.getColor(i, j); move.vanish.push( new PiPo({ x: i, y: j, - c: 'a', + c: color, p: object }) ); @@ -705,11 +633,12 @@ export class ChakartRules extends ChessRules { if ( V.OnBoard(next[0], next[1]) && this.board[next[0]][next[1]] != V.EMPTY && + this.getPiece(next[0], next[1]) != V.INVISIBLE_QUEEN && this.getColor(next[0], next[1]) != 'a' ) { const afterNext = [next[0] + step[0], next[1] + step[1]]; if (V.OnBoard(afterNext[0], afterNext[1])) { - const afterColor = this.getColor(afterNext[0], afterNext[1]) + const afterColor = this.getColor(afterNext[0], afterNext[1]); if ( this.board[afterNext[0]][afterNext[1]] == V.EMPTY || afterColor != color1 @@ -784,13 +713,15 @@ export class ChakartRules extends ChessRules { const [i, j] = [finalSquare[0] + s[0], finalSquare[1] + s[1]]; return ( V.OnBoard(i, j) && + // NOTE: do not place a bomb or banana on the invisible queen! (this.board[i][j] == V.EMPTY || this.getColor(i, j) == 'a') ); }); if (validSteps.length >= 1) { + const randIdx = randInt(validSteps.length); const [x, y] = [ - finalSquare[0] + validSteps[0][0], - finalSquare[1] + validSteps[0][1] + finalSquare[0] + validSteps[randIdx][0], + finalSquare[1] + validSteps[randIdx][1] ]; move.appear.push( new PiPo({ @@ -890,14 +821,16 @@ export class ChakartRules extends ChessRules { let moves = []; if ( this.board[x + shiftX][y] == V.EMPTY || - this.getColor(x + shiftX, y) == 'a' + this.getColor(x + shiftX, y) == 'a' || + this.getPiece(x + shiftX, y) == V.INVISIBLE_QUEEN ) { this.addPawnMoves([x, y], [x + shiftX, y], moves); if ( [firstRank, firstRank + shiftX].includes(x) && ( this.board[x + 2 * shiftX][y] == V.EMPTY || - this.getColor(x + 2 * shiftX, y) == 'a' + this.getColor(x + 2 * shiftX, y) == 'a' || + this.getPiece(x + 2 * shiftX, y) == V.INVISIBLE_QUEEN ) ) { moves.push(this.getBasicMove({ x: x, y: y }, [x + 2 * shiftX, y])); @@ -908,6 +841,8 @@ export class ChakartRules extends ChessRules { y + shiftY >= 0 && y + shiftY < sizeY && this.board[x + shiftX][y + shiftY] != V.EMPTY && + // Pawns cannot capture invisible queen this way! + this.getPiece(x + shiftX, y + shiftY) != V.INVISIBLE_QUEEN && ['a', oppCol].includes(this.getColor(x + shiftX, y + shiftY)) ) { this.addPawnMoves([x, y], [x + shiftX, y + shiftY], moves); @@ -944,48 +879,37 @@ export class ChakartRules extends ChessRules { // If flag allows it, add 'remote shell captures' if (this.powerFlags[this.turn][V.KING]) { V.steps[V.ROOK].concat(V.steps[V.BISHOP]).forEach(step => { - const [nextX, nextY] = [x + step[0], y + step[1]]; - if ( - V.OnBoard(nextX, nextY) && + let [i, j] = [x + step[0], y + step[1]]; + while ( + V.OnBoard(i, j) && ( - this.board[nextX][nextY] == V.EMPTY || + this.board[i][j] == V.EMPTY || + this.getPiece(i, j) == V.INVISIBLE_QUEEN || ( - this.getColor(nextX, nextY) == 'a' && - [V.EGG, V.MUSHROOM].includes(this.getPiece(nextX, nextY)) + this.getColor(i, j) == 'a' && + [V.EGG, V.MUSHROOM].includes(this.getPiece(i, j)) ) ) ) { - let [i, j] = [x + 2 * step[0], y + 2 * step[1]]; - while ( - V.OnBoard(i, j) && - ( - this.board[i][j] == V.EMPTY || - ( - this.getColor(i, j) == 'a' && - [V.EGG, V.MUSHROOM].includes(this.getPiece(i, j)) - ) - ) - ) { - i += step[0]; - j += step[1]; - } - if (V.OnBoard(i, j)) { - const colIJ = this.getColor(i, j); - if (colIJ != color) { - // May just destroy a bomb or banana: - moves.push( - new Move({ - start: { x: x, y: y}, - end: { x: i, y: j }, - appear: [], - vanish: [ - new PiPo({ - x: i, y: j, c: colIJ, p: this.getPiece(i, j) - }) - ] - }) - ); - } + i += step[0]; + j += step[1]; + } + if (V.OnBoard(i, j)) { + const colIJ = this.getColor(i, j); + if (colIJ != color) { + // May just destroy a bomb or banana: + moves.push( + new Move({ + start: { x: x, y: y}, + end: { x: i, y: j }, + appear: [], + vanish: [ + new PiPo({ + x: i, y: j, c: colIJ, p: this.getPiece(i, j) + }) + ] + }) + ); } } }); @@ -1023,66 +947,42 @@ export class ChakartRules extends ChessRules { getAllPotentialMoves() { if (this.subTurn == 1) return super.getAllPotentialMoves(); let moves = []; - const L = this.firstMove.length; - const fm = this.firstMove[L-1]; - switch (fm.end.effect) { - case 0: - moves.push({ - start: { x: -1, y: -1 }, - end: { x: -1, y: -1 }, - appear: [], - vanish: [] - }); - for ( - let step of - (fm.vanish[0].p == V.ROOK ? V.steps[V.BISHOP] : V.steps[V.ROOK]) - ) { - const [i, j] = [fm.appear[0].x + step[0], fm.appear[0].y + step[1]]; - if ( - V.OnBoard(i, j) && - (this.board[i][j] == V.EMPTY || this.getColor(i, j) == 'a') - ) { - let m = new Move({ - start: { x: -1, y: -1 }, - end: { x: i, y: j }, - appear: [ - new PiPo({ - x: i, - y: j, - c: 'a', - p: (fm.vanish[0].p == V.ROOK ? V.BANANA : V.BOMB) - }) - ], - vanish: [] - }); - if (this.board[i][j] != V.EMPTY) { - m.vanish.push( - new PiPo({ x: i, y: j, c: 'a', p: this.getPiece(i, j) })); - } - moves.push(m); - } - } - break; + const color = this.turn; + const L = this.effects.length; + switch (this.effects[L-1]) { case "kingboo": { - const [x, y] = [fm.appear[0].x, fm.appear[0].y]; + let allPieces = []; for (let i=0; i<8; i++) { for (let j=0; j<8; j++) { const colIJ = this.getColor(i, j); + const pieceIJ = this.getPiece(i, j); if ( - i != x && - j != y && + i != x && j != y && this.board[i][j] != V.EMPTY && - colIJ != 'a' + colIJ != 'a' && + pieceIJ != V.INVISIBLE_QUEEN ) { - const movedUnit = new PiPo({ - x: x, - y: y, - c: colIJ, - p: this.getPiece(i, j) + allPieces.push({ x: i, y: j, c: colIJ, p: pieceIJ }); + } + } + } + for (let x=0; x<8; x++) { + for (let y=0; y<8; y++) { + if (this.getColor(i, j) == color) { + // Add exchange with something + allPieces.forEach(pp => { + if (pp.x != i || pp.y != j) { + const movedUnit = new PiPo({ + x: x, + y: y, + c: pp.c, + p: pp.p + }); + let mMove = this.getBasicMove({ x: x, y: y }, [pp.x, pp.y]); + mMove.appear.push(movedUnit); + moves.push(mMove); + } }); - let mMove = this.getBasicMove({ x: x, y: y }, [i, j]); - mMove.appear.push(movedUnit); - moves.push(mMove); } } } @@ -1095,68 +995,12 @@ export class ChakartRules extends ChessRules { break; } case "daisy": - moves = super.getPotentialMovesFrom([fm.appear[0].x, fm.appear[0].y]); + moves = super.getAllPotentialMoves(); break; } return moves; } - doClick(square) { - const L = this.firstMove.length; - const fm = (L > 0 ? this.firstMove[L-1] : null); - if ( - isNaN(square[0]) || - this.subTurn == 1 || - !([0, "daisy"].includes(fm.end.effect)) - ) { - return null; - } - const [x, y] = [square[0], square[1]]; - const deltaX = Math.abs(fm.appear[0].x - x); - const deltaY = Math.abs(fm.appear[0].y - y); - if ( - fm.end.effect == 0 && - (this.board[x][y] == V.EMPTY || this.getColor(x, y) == 'a') && - ( - (fm.vanish[0].p == V.ROOK && deltaX == 1 && deltaY == 1) || - (fm.vanish[0].p == V.BISHOP && deltaX + deltaY == 1) - ) - ) { - let m = new Move({ - start: { x: -1, y: -1 }, - end: { x: x, y: y }, - appear: [ - new PiPo({ - x: x, - y: y, - c: 'a', - p: (fm.vanish[0].p == V.ROOK ? V.BANANA : V.BOMB) - }) - ], - vanish: [] - }); - if (this.board[x][y] != V.EMPTY) { - m.vanish.push( - new PiPo({ x: x, y: y, c: 'a', p: this.getPiece(x, y) })); - } - return m; - } - else if ( - fm.end.effect == "daisy" && - deltaX == 0 && deltaY == 0 && - !this.canMove([x, y]) - ) { - // No possible move: return empty move - return { - start: { x: -1, y: -1 }, - end: { x: -1, y: -1 }, - appear: [], - vanish: [] - }; - } - return null; - } - play(move) { // if (!this.states) this.states = []; // const stateFen = this.getFen(); @@ -1165,8 +1009,8 @@ export class ChakartRules extends ChessRules { move.flags = JSON.stringify(this.aggregateFlags()); V.PlayOnBoard(this.board, move); move.turn = [this.turn, this.subTurn]; - if ([0, "kingboo", "toadette", "daisy"].includes(move.end.effect)) { - this.firstMove.push(move); + if (["kingboo", "toadette", "daisy"].includes(move.end.effect)) { + this.effects.push(move.end.effect); this.subTurn = 2; } else { @@ -1181,7 +1025,11 @@ export class ChakartRules extends ChessRules { if (move.end.effect == "toadette") this.reserve = this.captured; else this.reserve = undefined; const color = move.turn[0]; - if (move.vanish.length == 2 && move.vanish[1].c != 'a') { + if ( + move.vanish.length == 2 && + move.vanish[1].c != 'a' && + move.appear.length == 1 //avoid king Boo! + ) { // Capture: update this.captured let capturedPiece = move.vanish[1].p; if (capturedPiece == V.INVISIBLE_QUEEN) capturedPiece = V.QUEEN; @@ -1245,8 +1093,8 @@ export class ChakartRules extends ChessRules { undo(move) { this.disaggregateFlags(JSON.parse(move.flags)); V.UndoOnBoard(this.board, move); - if ([0, "kingboo", "toadette", "daisy"].includes(move.end.effect)) - this.firstMove.pop(); + if (["kingboo", "toadette", "daisy"].includes(move.end.effect)) + this.effects.pop(); else this.movesCount--; this.turn = move.turn[0]; this.subTurn = move.turn[1]; @@ -1308,9 +1156,9 @@ export class ChakartRules extends ChessRules { return "*"; } - static GenRandInitFen(randomness) { + static GenRandInitFen(options) { return ( - SuicideRules.GenRandInitFen(randomness).slice(0, -1) + + SuicideRules.GenRandInitFen(options).slice(0, -1) + // Add Peach + Mario flags + capture counts "1111 000000000000" ); @@ -1422,13 +1270,13 @@ export class ChakartRules extends ChessRules { move.vanish.every(v => v.c != 'a') ) { // King Boo exchange - return move.vanish[1].p.toUpperCase() + finalSquare; + return V.CoordsToSquare(move.start) + finalSquare; } const piece = move.vanish[0].p; let notation = undefined; if (piece == V.PAWN) { // Pawn move - if (move.vanish.length >= 2) { + if (this.board[move.end.x][move.end.y] != V.EMPTY) { // Capture const startColumn = V.CoordToColumn(move.start.y); notation = startColumn + "x" + finalSquare; @@ -1441,7 +1289,7 @@ export class ChakartRules extends ChessRules { else { notation = piece.toUpperCase() + - (move.vanish.length >= 2 ? "x" : "") + + (this.board[move.end.x][move.end.y] != V.EMPTY ? "x" : "") + finalSquare; } if (!!move.end.effect) { @@ -1469,4 +1317,5 @@ export class ChakartRules extends ChessRules { } return notation; } + };