X-Git-Url: https://git.auder.net/?a=blobdiff_plain;f=variants%2FBaroque%2Fclass.js;h=edf1dd56401ee04253f57aa5c73b9efe9a9967b1;hb=a89fb4e9c92632a2e8295048a86d7a0ae0a7ec46;hp=98ef1c78f7f4b190313fa2095d559af6413e54dc;hpb=9a036f5fbfe3cc1df18b47e43d5db293de013e47;p=xogo.git diff --git a/variants/Baroque/class.js b/variants/Baroque/class.js index 98ef1c7..edf1dd5 100644 --- a/variants/Baroque/class.js +++ b/variants/Baroque/class.js @@ -1,10 +1,11 @@ import ChessRules from "/base_rules.js"; import GiveawayRules from "/variants/Giveaway/class.js"; +import AbstractSpecialCaptureRules from "/variants/_SpecialCaptures.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,9 +34,6 @@ export default class BaroqueRules extends ChessRules { get hasFlags() { return false; } - get hasEnpassant() { - return false; - } genRandInitBaseFen() { if (this.options["randomness"] == 0) @@ -61,25 +59,18 @@ export default class BaroqueRules extends ChessRules { return res; } - // 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 +81,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' } } ); @@ -162,236 +153,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.addQueenCaptures(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[step[0] + "." + step[1]] = true; - } - }); - 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 - ]; - if (capturingDirections[step[0] + "." + 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; - } - };