X-Git-Url: https://git.auder.net/?a=blobdiff_plain;f=client%2Fsrc%2Fvariants%2FFullcavalry.js;h=07951f6baea06c5ebd9d748d8bed4355d75cb6dc;hb=4313762da3237b04f204e121a20cab3ba7bb5dd2;hp=c25f3400afce4e0c1c1ed8d3cd1f132339f64bb0;hpb=0fb43db7c2858201e8410670b90f95ad8b138964;p=vchess.git diff --git a/client/src/variants/Fullcavalry.js b/client/src/variants/Fullcavalry.js index c25f3400..07951f6b 100644 --- a/client/src/variants/Fullcavalry.js +++ b/client/src/variants/Fullcavalry.js @@ -76,9 +76,11 @@ export class FullcavalryRules extends ChessRules { } getPPpath(m, orientation) { + // If castle, show choices on m.appear[1]: + const index = (m.appear.length == 2 ? 1 : 0); return ( this.getPpath( - m.appear[0].c + m.appear[0].p, + m.appear[index].c + m.appear[index].p, null, null, orientation @@ -86,55 +88,30 @@ export class FullcavalryRules extends ChessRules { ); } - static GenRandInitFen(randomness) { - if (randomness == 0) + static GenRandInitFen(options) { + if (options.randomness == 0) // Deterministic: - return "efbqkbnm/pppppppp/8/8/8/8/PPPPPPPP/EDBQKBNM w 0 ahah -"; + return "enbqkbnm/pppppppp/8/8/8/8/PPPPPPPP/ENBQKBNM w 0 ahah -"; - const baseFen = ChessRules.GenRandInitFen(randomness); - // Replace black rooks by lancers oriented south, - // and white rooks by lancers oriented north: - return baseFen.replace(/r/g, 'g').replace(/R/g, 'C'); - } - - // Because of the lancers, getPiece() could be wrong: - // use board[x][y][1] instead (always valid). - // TODO: base implementation now uses this too (no?) - getBasicMove([sx, sy], [ex, ey], tr) { - const initColor = this.getColor(sx, sy); - const initPiece = this.board[sx][sy].charAt(1); - let mv = new Move({ - appear: [ - new PiPo({ - x: ex, - y: ey, - c: tr ? tr.c : initColor, - p: tr ? tr.p : initPiece - }) - ], - vanish: [ - new PiPo({ - x: sx, - y: sy, - c: initColor, - p: initPiece - }) - ] - }); - - // The opponent piece disappears if we take it - if (this.board[ex][ey] != V.EMPTY) { - mv.vanish.push( - new PiPo({ - x: ex, - y: ey, - c: this.getColor(ex, ey), - p: this.board[ex][ey].charAt(1) - }) - ); - } - - return mv; + const baseFen = ChessRules.GenRandInitFen(options); + // Replace rooks by lancers with expected orientation: + const firstBlackRook = baseFen.indexOf('r'), + lastBlackRook = baseFen.lastIndexOf('r'), + firstWhiteRook = baseFen.indexOf('R'), + lastWhiteRook = baseFen.lastIndexOf('R'); + return ( + baseFen.substring(0, firstBlackRook) + + (firstBlackRook <= 3 ? 'e' : 'm') + + baseFen.substring(firstBlackRook + 1, lastBlackRook) + + (lastBlackRook >= 5 ? 'm' : 'e') + + // Subtract 35 = total number of characters before last FEN row: + // 8x3 (full rows) + 4 (empty rows) + 7 (separators) + baseFen.substring(lastBlackRook + 1, firstWhiteRook) + + (firstWhiteRook - 35 <= 3 ? 'E' : 'M') + + baseFen.substring(firstWhiteRook + 1, lastWhiteRook) + + (lastWhiteRook - 35 >= 5 ? 'M' : 'E') + + baseFen.substring(lastWhiteRook + 1) + ); } getPotentialMovesFrom([x, y]) { @@ -143,6 +120,22 @@ export class FullcavalryRules extends ChessRules { return super.getPotentialMovesFrom([x, y]); } + getPotentialPawnMoves([x, y]) { + const color = this.getColor(x, y); + let shiftX = (color == "w" ? -1 : 1); + const lastRank = (color == "w" ? 0 : 7); + let finalPieces = [V.PAWN]; + if (x + shiftX == lastRank) { + // Only allow direction facing inside board: + const allowedLancerDirs = + lastRank == 0 + ? ['e', 'f', 'g', 'h', 'm'] + : ['c', 'd', 'e', 'm', 'o']; + finalPieces = allowedLancerDirs.concat([V.KNIGHT, V.BISHOP, V.QUEEN]); + } + return super.getPotentialPawnMoves([x, y], finalPieces); + } + // Obtain all lancer moves in "step" direction getPotentialLancerMoves_aux([x, y], step, tr) { let moves = []; @@ -184,6 +177,100 @@ export class FullcavalryRules extends ChessRules { return moves; } + getCastleMoves([x, y]) { + const c = this.getColor(x, y); + + // Castling ? + const oppCol = V.GetOppCol(c); + let moves = []; + let i = 0; + // King, then lancer: + const finalSquares = [ [2, 3], [V.size.y - 2, V.size.y - 3] ]; + castlingCheck: for ( + let castleSide = 0; + castleSide < 2; + castleSide++ //large, then small + ) { + if (this.castleFlags[c][castleSide] >= V.size.y) continue; + // If this code is reached, lancer and king are on initial position + + const lancerPos = this.castleFlags[c][castleSide]; + const castlingPiece = this.board[x][lancerPos].charAt(1); + + // Nothing on the path of the king ? (and no checks) + const finDist = finalSquares[castleSide][0] - y; + let step = finDist / Math.max(1, Math.abs(finDist)); + i = y; + do { + if ( + (this.isAttacked([x, i], oppCol)) || + ( + this.board[x][i] != V.EMPTY && + // NOTE: next check is enough, because of chessboard constraints + (this.getColor(x, i) != c || ![y, lancerPos].includes(i)) + ) + ) { + continue castlingCheck; + } + i += step; + } while (i != finalSquares[castleSide][0]); + + // Nothing on final squares, except maybe king and castling lancer? + for (i = 0; i < 2; i++) { + if ( + finalSquares[castleSide][i] != lancerPos && + this.board[x][finalSquares[castleSide][i]] != V.EMPTY && + ( + finalSquares[castleSide][i] != y || + this.getColor(x, finalSquares[castleSide][i]) != c + ) + ) { + continue castlingCheck; + } + } + + // If this code is reached, castle is valid + let allowedLancerDirs = [castlingPiece]; + if (finalSquares[castleSide][1] != lancerPos) { + // It moved: allow reorientation + allowedLancerDirs = + x == 0 + ? ['e', 'f', 'g', 'h', 'm'] + : ['c', 'd', 'e', 'm', 'o']; + } + allowedLancerDirs.forEach(dir => { + moves.push( + new Move({ + appear: [ + new PiPo({ + x: x, + y: finalSquares[castleSide][0], + p: V.KING, + c: c + }), + new PiPo({ + x: x, + y: finalSquares[castleSide][1], + p: dir, + c: c + }) + ], + vanish: [ + new PiPo({ x: x, y: y, p: V.KING, c: c }), + new PiPo({ x: x, y: lancerPos, p: castlingPiece, c: c }) + ], + end: + Math.abs(y - lancerPos) <= 2 + ? { x: x, y: lancerPos } + : { x: x, y: y + 2 * (castleSide == 0 ? -1 : 1) } + }) + ); + }); + } + + return moves; + } + isAttacked(sq, color) { return ( super.isAttacked(sq, color) || @@ -205,12 +292,8 @@ export class FullcavalryRules extends ChessRules { this.getColor(coord.x, coord.y) == color ) ) { - if ( - this.getPiece(coord.x, coord.y) == V.LANCER && - !this.isImmobilized([coord.x, coord.y]) - ) { + if (this.getPiece(coord.x, coord.y) == V.LANCER) lancerPos.push({x: coord.x, y: coord.y}); - } coord.x += step[0]; coord.y += step[1]; } @@ -245,15 +328,22 @@ export class FullcavalryRules extends ChessRules { filterValid(moves) { // At move 1, forbid captures (in case of...): - if (this.movesCount >= 2) return moves; + if (this.movesCount >= 2) return super.filterValid(moves); return moves.filter(m => m.vanish.length == 1); } + static get SEARCH_DEPTH() { + return 2; + } + getNotation(move) { let notation = super.getNotation(move); if (Object.keys(V.LANCER_DIRNAMES).includes(move.vanish[0].p)) // Lancer: add direction info notation += "=" + V.LANCER_DIRNAMES[move.appear[0].p]; + else if (move.appear.length == 2 && move.vanish[1].p != move.appear[1].p) + // Same after castle: + notation += "+L:" + V.LANCER_DIRNAMES[move.appear[1].p]; else if ( move.vanish[0].p == V.PAWN && Object.keys(V.LANCER_DIRNAMES).includes(move.appear[0].p)