X-Git-Url: https://git.auder.net/?a=blobdiff_plain;f=client%2Fsrc%2Fvariants%2FEightpieces.js;h=dc7580b32a63e806eb2eb6a6737e5ec7c9ab0bd9;hb=abbda16dbd485dfc43ee502bbef67045b1aecc59;hp=583b1c5ac5a14e609324a274136da6d39cea31ec;hpb=7f1df0d95d2190fd69ef7c58f5a795aef3f92869;p=vchess.git diff --git a/client/src/variants/Eightpieces.js b/client/src/variants/Eightpieces.js index 583b1c5a..dc7580b3 100644 --- a/client/src/variants/Eightpieces.js +++ b/client/src/variants/Eightpieces.js @@ -1,8 +1,8 @@ -import { ArrayFun } from "@/utils/array"; -import { randInt } from "@/utils/alea"; +import { randInt, sample } from "@/utils/alea"; import { ChessRules, PiPo, Move } from "@/base_rules"; export class EightpiecesRules extends ChessRules { + static get JAILER() { return "j"; } @@ -167,81 +167,54 @@ export class EightpiecesRules extends ChessRules { } } - static GenRandInitFen(randomness) { - if (randomness == 0) - // Deterministic: + static GenRandInitFen(options) { + if (options.randomness == 0) return "jfsqkbnr/pppppppp/8/8/8/8/PPPPPPPP/JDSQKBNR w 0 ahah - -"; - let pieces = { w: new Array(8), b: new Array(8) }; - let flags = ""; - // Shuffle pieces on first (and last rank if randomness == 2) - for (let c of ["w", "b"]) { - if (c == 'b' && randomness == 1) { - const lancerIdx = pieces['w'].findIndex(p => { - return Object.keys(V.LANCER_DIRS).includes(p); - }); - pieces['b'] = - pieces['w'].slice(0, lancerIdx) - .concat(['g']) - .concat(pieces['w'].slice(lancerIdx + 1)); - flags += flags; - break; - } + const baseFen = ChessRules.GenRandInitFen(options); + const fenParts = baseFen.split(' '); + const posParts = fenParts[0].split('/'); - let positions = ArrayFun.range(8); - - // Get random squares for bishop and sentry - let randIndex = 2 * randInt(4); - let bishopPos = positions[randIndex]; - // The sentry must be on a square of different color - let randIndex_tmp = 2 * randInt(4) + 1; - let sentryPos = positions[randIndex_tmp]; - if (c == 'b') { - // Check if white sentry is on the same color as ours. - // If yes: swap bishop and sentry positions. - // NOTE: test % 2 == 1 because there are 7 slashes. - if ((pieces['w'].indexOf('s') - sentryPos) % 2 == 1) - [bishopPos, sentryPos] = [sentryPos, bishopPos]; + // Replace one bishop by sentry, so that sentries on different colors + // Also replace one random rook by jailer, + // and one random knight by lancer (facing north/south) + let pieceLine = { b: posParts[0], w: posParts[7].toLowerCase() }; + let posBlack = { r: -1, n: -1, b: -1 }; + const mapP = { r: 'j', n: 'l', b: 's' }; + ['w', 'b'].forEach(c => { + ['r', 'n', 'b'].forEach(p => { + let pl = pieceLine[c]; + let pos = -1; + if (options.randomness == 2 || c == 'b') + pos = (randInt(2) == 0 ? pl.indexOf(p) : pl.lastIndexOf(p)); + else pos = posBlack[p]; + pieceLine[c] = + pieceLine[c].substr(0, pos) + mapP[p] + pieceLine[c].substr(pos+1); + if (options.randomness == 1 && c == 'b') posBlack[p] = pos; + }); + }); + // Rename 'l' into 'g' (black) or 'c' (white) + pieceLine['w'] = pieceLine['w'].replace('l', 'c'); + pieceLine['b'] = pieceLine['b'].replace('l', 'g'); + if (options.randomness == 2) { + const ws = pieceLine['w'].indexOf('s'); + const bs = pieceLine['b'].indexOf('s'); + if (ws % 2 != bs % 2) { + // Fix sentry: should be on different colors. + // => move sentry on other bishop for random color + const c = sample(['w', 'b'], 1); + pieceLine[c] = pieceLine[c] + .replace('b', 't'); //tmp + .replace('s', 'b'); + .replace('t', 's'); } - positions.splice(Math.max(randIndex, randIndex_tmp), 1); - positions.splice(Math.min(randIndex, randIndex_tmp), 1); - - // Get random squares for knight and lancer - randIndex = randInt(6); - const knightPos = positions[randIndex]; - positions.splice(randIndex, 1); - randIndex = randInt(5); - const lancerPos = positions[randIndex]; - positions.splice(randIndex, 1); - - // Get random square for queen - randIndex = randInt(4); - const queenPos = positions[randIndex]; - positions.splice(randIndex, 1); - - // Rook, jailer and king positions are now almost fixed, - // only the ordering rook->jailer or jailer->rook must be decided. - let rookPos = positions[0]; - let jailerPos = positions[2]; - const kingPos = positions[1]; - flags += V.CoordToColumn(rookPos) + V.CoordToColumn(jailerPos); - if (Math.random() < 0.5) [rookPos, jailerPos] = [jailerPos, rookPos]; - - pieces[c][rookPos] = "r"; - pieces[c][knightPos] = "n"; - pieces[c][bishopPos] = "b"; - pieces[c][queenPos] = "q"; - pieces[c][kingPos] = "k"; - pieces[c][sentryPos] = "s"; - // Lancer faces north for white, and south for black: - pieces[c][lancerPos] = c == 'w' ? 'c' : 'g'; - pieces[c][jailerPos] = "j"; } + return ( - pieces["b"].join("") + - "/pppppppp/8/8/8/8/PPPPPPPP/" + - pieces["w"].join("").toUpperCase() + - " w 0 " + flags + " - -" + pieceLine['b'] + "/" + + posParts.slice(1, 7).join('/') + "/" + + pieceLine['w'].toUpperCase() + " " + + fenParts.slice(1, 5).join(' ') + " -" ); } @@ -269,45 +242,6 @@ export class EightpiecesRules extends ChessRules { return null; } - // Because of the lancers, getPiece() could be wrong: - // use board[x][y][1] instead (always valid). - 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; - } - canIplay(side, [x, y]) { return ( (this.subTurn == 1 && this.turn == side && this.getColor(x, y) == side) @@ -383,7 +317,8 @@ export class EightpiecesRules extends ChessRules { } return true; }); - } else if (this.subTurn == 2) { + } + else if (this.subTurn == 2) { // Put back the sentinel on board: const color = this.turn; moves.forEach(m => { @@ -732,10 +667,7 @@ export class EightpiecesRules extends ChessRules { getPotentialKingMoves(sq) { const moves = this.getSlideNJumpMoves( - sq, - V.steps[V.ROOK].concat(V.steps[V.BISHOP]), - "oneStep" - ); + sq, V.steps[V.ROOK].concat(V.steps[V.BISHOP]), 1); return ( this.subTurn == 1 ? moves.concat(this.getCastleMoves(sq)) @@ -885,8 +817,8 @@ export class EightpiecesRules extends ChessRules { const oppCol = V.GetOppCol(color); const sliderAttack = (allowedSteps, lancer) => { const deltaX = x2 - x1, - absDeltaX = Math.abs(deltaX); - const deltaY = y2 - y1, + deltaY = y2 - y1; + const absDeltaX = Math.abs(deltaX), absDeltaY = Math.abs(deltaY); const step = [ deltaX / absDeltaX || 0, deltaY / absDeltaY || 0 ]; if ( @@ -898,12 +830,18 @@ export class EightpiecesRules extends ChessRules { } let sq = [ x1 + step[0], y1 + step[1] ]; while (sq[0] != x2 || sq[1] != y2) { - if ( - // NOTE: no need to check OnBoard in this special case - (!lancer && this.board[sq[0]][sq[1]] != V.EMPTY) || - (!!lancer && this.getColor(sq[0], sq[1]) == oppCol) - ) { - return false; + // NOTE: no need to check OnBoard in this special case + if (this.board[sq[0]][sq[1]] != V.EMPTY) { + const p = this.getPiece(sq[0], sq[1]); + const pc = this.getColor(sq[0], sq[1]); + if ( + // Enemy sentry on the way will be gone: + (p != V.SENTRY || pc != oppCol) && + // Lancer temporarily "changed color": + (!lancer || pc == color) + ) { + return false; + } } sq[0] += step[0]; sq[1] += step[1]; @@ -1194,4 +1132,5 @@ export class EightpiecesRules extends ChessRules { } return notation; } + };