X-Git-Url: https://git.auder.net/?a=blobdiff_plain;f=variants%2FBaroque%2Fclass.js;h=84331a2a29a344cccd2c303385494124437b8dfd;hb=65203419968be4b63acf55172fe4b28658b96f38;hp=62904e8ec986362563cf5090f7605fd60781d526;hpb=0e466aac11288f35b34d744b2652c7b4e9df2e24;p=xogo.git diff --git a/variants/Baroque/class.js b/variants/Baroque/class.js index 62904e8..84331a2 100644 --- a/variants/Baroque/class.js +++ b/variants/Baroque/class.js @@ -1,10 +1,8 @@ -import ChessRules from "/base_rules.js"; -import GiveawayRules from "/variants/Giveaway/class.js"; +import AbstractSpecialCaptureRules from "/variants/_SpecialCaptures/class.js"; +import {FenUtil} from "/utils/setupPieces.js"; import {Random} from "/utils/alea.js"; -import PiPo from "/utils/PiPo.js"; -import Move from "/utils/Move.js"; -export default class BaroqueRules extends ChessRules { +export default class BaroqueRules extends AbstractSpecialCaptureRules { static get Options() { return { @@ -33,53 +31,41 @@ export default class BaroqueRules extends ChessRules { get hasFlags() { return false; } - get hasEnpassant() { - return false; - } genRandInitBaseFen() { - if (this.options["randomness"] == 0) - return "rnbkqbnm/pppppppp/8/8/8/8/PPPPPPPP/MNBQKBNR"; - const options = Object.assign({mode: "suicide"}, this.options); - const gr = new GiveawayRules({options: options, genFenOnly: true}); - let res = gr.genRandInitBaseFen(); - let immPos = {}; - for (let c of ['w', 'b']) { - const rookChar = (c == 'w' ? 'R' : 'r'); - switch (Random.randInt(2)) { - case 0: - immPos[c] = res.fen.indexOf(rookChar); - break; - case 1: - immPos[c] = res.fen.lastIndexOf(rookChar); - break; + const s = FenUtil.setupPieces( + ['r', 'n', 'b', 'q', 'k', 'b', 'n', 'i'], + { + randomness: this.options["randomness"], + diffCol: ['b'] } + ); + if (this.options["randomness"] <= 1) { + // Fix immobilizers/rooks pattern + const toExchange1 = s.w.indexOf('r'), + toExchange2 = s.w.indexOf('i'); + s.w[toExchange1] = 'i'; + s.w[toExchange2] = 'r'; } - res.fen = res.fen.substring(0, immPos['b']) + 'i' + - res.fen.substring(immPos['b'] + 1, immPos['w']) + 'I' + - res.fen.substring(immPos['w'] + 1); - return res; + return { + fen: s.b.join("") + "/pppppppp/8/8/8/8/PPPPPPPP/" + + s.w.join("").toUpperCase(), + o: {} + }; } - // Although other pieces keep their names here for coding simplicity, - // keep in mind that: - // - a "rook" is a coordinator, capturing by coordinating with the king - // - a "knight" is a long-leaper, capturing as in draughts - // - a "bishop" is a chameleon, capturing as its prey - // - a "queen" is a withdrawer, capturing by moving away from pieces - pieces() { return Object.assign({}, super.pieces(), { 'p': { - "class": "pawn", + "class": "pawn", //pincer moves: [ {steps: [[0, 1], [0, -1], [1, 0], [-1, 0]]} ] }, 'r': { - "class": "rook", + "class": "rook", //coordinator moves: [ { steps: [ @@ -90,20 +76,20 @@ export default class BaroqueRules extends ChessRules { ] }, 'n': { - "class": "knight", + "class": "knight", //long-leaper moveas: 'r' }, 'b': { - "class": "bishop", + "class": "bishop", //chameleon moveas: 'r' }, 'q': { - "class": "queen", + "class": "queen", //withdrawer moveas: 'r' }, 'i': { "class": "immobilizer", - moveas: 'q' + moveas: 'r' } } ); @@ -113,8 +99,8 @@ export default class BaroqueRules extends ChessRules { isImmobilized([x, y]) { const piece = this.getPiece(x, y); const color = this.getColor(x, y); - const oppCol = C.GetOppCol(color); - const adjacentSteps = this.pieces()['k'].moves[0].steps; + const oppCol = C.GetOppTurn(color); + const adjacentSteps = this.pieces()['k'].both[0].steps; for (let step of adjacentSteps) { const [i, j] = [x + step[0], this.getY(y + step[1])]; if ( @@ -162,241 +148,23 @@ export default class BaroqueRules extends ChessRules { return []; switch (moves[0].vanish[0].p) { case 'p': - this.addPawnCaptures(moves); + this.addPincerCaptures(moves); break; case 'r': - this.addRookCaptures(moves); + this.addCoordinatorCaptures(moves); break; case 'n': const [x, y] = [moves[0].start.x, moves[0].start.y]; - moves = moves.concat(this.getKnightCaptures([x, y])); + moves = moves.concat(this.getLeaperCaptures([x, y])); break; case 'b': - moves = this.getBishopCaptures(moves); + moves = this.getChameleonCaptures(moves, "pull"); break; case 'q': - this.addPawnCaptures(moves); + this.addPushmePullyouCaptures(moves, false, "pull"); break; } return moves; } - // Modify capturing moves among listed pawn moves - addPawnCaptures(moves, byChameleon) { - const steps = this.pieces()['p'].moves[0].steps; - const color = this.turn; - const oppCol = C.GetOppCol(color); - moves.forEach(m => { - if (byChameleon && m.start.x != m.end.x && m.start.y != m.end.y) - // Chameleon not moving as pawn - return; - // Try capturing in every direction - for (let step of steps) { - const sq2 = [m.end.x + 2 * step[0], this.getY(m.end.y + 2 * step[1])]; - if ( - this.onBoard(sq2[0], sq2[1]) && - this.board[sq2[0]][sq2[1]] != "" && - this.getColor(sq2[0], sq2[1]) == color - ) { - // Potential capture - const sq1 = [m.end.x + step[0], this.getY(m.end.y + step[1])]; - if ( - this.board[sq1[0]][sq1[1]] != "" && - this.getColor(sq1[0], sq1[1]) == oppCol - ) { - const piece1 = this.getPiece(sq1[0], sq1[1]); - if (!byChameleon || piece1 == 'p') { - m.vanish.push( - new PiPo({ - x: sq1[0], - y: sq1[1], - c: oppCol, - p: piece1 - }) - ); - } - } - } - } - }); - } - - addRookCaptures(moves, byChameleon) { - const color = this.turn; - const oppCol = V.GetOppCol(color); - const kp = this.searchKingPos(color)[0]; - moves.forEach(m => { - // Check piece-king rectangle (if any) corners for enemy pieces - if (m.end.x == kp[0] || m.end.y == kp[1]) - return; //"flat rectangle" - const corner1 = [m.end.x, kp[1]]; - const corner2 = [kp[0], m.end.y]; - for (let [i, j] of [corner1, corner2]) { - if (this.board[i][j] != "" && this.getColor(i, j) == oppCol) { - const piece = this.getPiece(i, j); - if (!byChameleon || piece == 'r') { - m.vanish.push( - new PiPo({ - x: i, - y: j, - p: piece, - c: oppCol - }) - ); - } - } - } - }); - } - - getKnightCaptures(startSquare, byChameleon) { - // Look in every direction for captures - const steps = this.pieces()['r'].moves[0].steps; - const color = this.turn; - const oppCol = C.GetOppCol(color); - let moves = []; - const [x, y] = [startSquare[0], startSquare[1]]; - const piece = this.getPiece(x, y); //might be a chameleon! - outerLoop: for (let step of steps) { - let [i, j] = [x + step[0], this.getY(y + step[1])]; - while (this.onBoard(i, j) && this.board[i][j] == "") - [i, j] = [i + step[0], this.getY(j + step[1])]; - if ( - !this.onBoard(i, j) || - this.getColor(i, j) == color || - (byChameleon && this.getPiece(i, j) != 'n') - ) { - continue; - } - // last(thing), cur(thing) : stop if "cur" is our color, - // or beyond board limits, or if "last" isn't empty and cur neither. - // Otherwise, if cur is empty then add move until cur square; - // if cur is occupied then stop if !!byChameleon and the square not - // occupied by a leaper. - let last = [i, j]; - let cur = [i + step[0], this.getY(j + step[1])]; - let vanished = [new PiPo({x: x, y: y, c: color, p: piece})]; - while (this.onBoard(cur[0], cur[1])) { - if (this.board[last[0]][last[1]] != "") { - const oppPiece = this.getPiece(last[0], last[1]); - if (!!byChameleon && oppPiece != 'n') - continue outerLoop; - // Something to eat: - vanished.push( - new PiPo({x: last[0], y: last[1], c: oppCol, p: oppPiece}) - ); - } - if (this.board[cur[0]][cur[1]] != "") { - if ( - this.getColor(cur[0], cur[1]) == color || - this.board[last[0]][last[1]] != "" - ) { - //TODO: redundant test - continue outerLoop; - } - } - else { - moves.push( - new Move({ - appear: [new PiPo({x: cur[0], y: cur[1], c: color, p: piece})], - vanish: JSON.parse(JSON.stringify(vanished)), //TODO: required? - start: {x: x, y: y}, - end: {x: cur[0], y: cur[1]} - }) - ); - } - last = [last[0] + step[0], this.getY(last[1] + step[1])]; - cur = [cur[0] + step[0], this.getY(cur[1] + step[1])]; - } - } - return moves; - } - - // Chameleon - getBishopCaptures(moves) { - const [x, y] = [moves[0].start.x, moves[0].start.y]; - moves = moves.concat(this.getKnightCaptures([x, y], "asChameleon")); - // No "king capture" because king cannot remain under check - this.addPawnCaptures(moves, "asChameleon"); - this.addRookCaptures(moves, "asChameleon"); - this.addQueenCaptures(moves, "asChameleon"); - // Post-processing: merge similar moves, concatenating vanish arrays - let mergedMoves = {}; - moves.forEach(m => { - const key = m.end.x + this.size.x * m.end.y; - if (!mergedMoves[key]) - mergedMoves[key] = m; - else { - for (let i = 1; i < m.vanish.length; i++) - mergedMoves[key].vanish.push(m.vanish[i]); - } - }); - return Object.values(mergedMoves); - } - - addQueenCaptures(moves, byChameleon) { - if (moves.length == 0) return; - const [x, y] = [moves[0].start.x, moves[0].start.y]; - const adjacentSteps = this.pieces()['r'].moves[0].steps; - let capturingDirections = []; - const color = this.turn; - const oppCol = C.GetOppCol(color); - adjacentSteps.forEach(step => { - const [i, j] = [x + step[0], this.getY(y + step[1])]; - if ( - this.onBoard(i, j) && - this.board[i][j] != "" && - this.getColor(i, j) == oppCol && - (!byChameleon || this.getPiece(i, j) == 'q') - ) { - capturingDirections.push(step); - } - }); - moves.forEach(m => { - const step = [ - m.end.x != x ? (m.end.x - x) / Math.abs(m.end.x - x) : 0, - m.end.y != y ? (m.end.y - y) / Math.abs(m.end.y - y) : 0 - ]; - // NOTE: includes() and even _.isEqual() functions fail... - // TODO: this test should be done only once per direction - if ( - capturingDirections.some(dir => { - return dir[0] == -step[0] && dir[1] == -step[1]; - }) - ) { - const [i, j] = [x - step[0], this.getY(y - step[1])]; - m.vanish.push( - new PiPo({ - x: i, - y: j, - p: this.getPiece(i, j), - c: oppCol - }) - ); - } - }); - } - - underAttack([x, y], oppCol) { - // Generate all potential opponent moves, check if king captured. - // TODO: do it more efficiently. - const color = this.getColor(x, y); - for (let i = 0; i < this.size.x; i++) { - for (let j = 0; j < this.size.y; j++) { - if ( - this.board[i][j] != "" && this.getColor(i, j) == oppCol && - this.getPotentialMovesFrom([i, j]).some(m => { - return ( - m.vanish.length >= 2 && - [1, m.vanish.length - 1].some(k => m.vanish[k].p == 'k') - ); - }) - ) { - return true; - } - } - } - return false; - } - };