X-Git-Url: https://git.auder.net/?a=blobdiff_plain;f=client%2Fsrc%2Fvariants%2FPandemonium.js;h=4894ec1676679070d009feaec63b9415d23153b2;hb=3b98a861b893f0dc8e125c6f4a68faeb075ed56e;hp=f4ae3c44a55ae47d3f4446e74cd0d42f660e8963;hpb=7721a36a50b840b1dfe4cfaf5ed7abcbf525ffd5;p=vchess.git diff --git a/client/src/variants/Pandemonium.js b/client/src/variants/Pandemonium.js index f4ae3c44..4894ec16 100644 --- a/client/src/variants/Pandemonium.js +++ b/client/src/variants/Pandemonium.js @@ -1,17 +1,12 @@ import { ChessRules, Move, PiPo } from "@/base_rules"; import { randInt } from "@/utils/alea"; +import { ArrayFun } from "@/utils/array"; export class PandemoniumRules extends ChessRules { - static get PawnSpecs() { - return Object.assign( - {}, - ChessRules.PawnSpecs, - { - threeSquares: true, - promotions: [V.GILDING] - } - ); + loseOnRepetition() { + // If current side is under check: lost + return this.underCheck(this.turn); } static get GILDING() { @@ -147,23 +142,74 @@ export class PandemoniumRules extends ChessRules { return counts.join(""); } - setFlags(fenflags) { - // white a-castle, h-castle, king pos, then same for black. - this.castleFlags = { w: [-1, -1, -1], b: [-1, -1, -1] }; - for (let i = 0; i < 6; i++) { - this.castleFlags[i < 3 ? "w" : "b"][i % 3] = - V.ColumnToCoord(fenflags.charAt(i)); + static GenRandInitFen(randomness) { + if (randomness == 0) { + return ( + "rnbqkmcbnr/pppppppppp/91/91/91/91/91/91/PPPPPPPPPP/RNBQKMCBNR " + + "w 0 ajaj - 00000000000000" + ); } - } - static GenRandInitFen(randomness) { - // No randomization here for now (but initial setup choice) + let pieces = { w: new Array(10), b: new Array(10) }; + let flags = ""; + for (let c of ["w", "b"]) { + if (c == 'b' && randomness == 1) { + pieces['b'] = pieces['w']; + flags += flags; + break; + } + + let positions = ArrayFun.range(10); + + // Get random squares for bishops (different colors) + let randIndex = 2 * randInt(5); + let bishop1Pos = positions[randIndex]; + let randIndex_tmp = 2 * randInt(5) + 1; + let bishop2Pos = positions[randIndex_tmp]; + positions.splice(Math.max(randIndex, randIndex_tmp), 1); + positions.splice(Math.min(randIndex, randIndex_tmp), 1); + + randIndex = randInt(8); + let knight1Pos = positions[randIndex]; + positions.splice(randIndex, 1); + randIndex = randInt(7); + let knight2Pos = positions[randIndex]; + positions.splice(randIndex, 1); + + randIndex = randInt(6); + let queenPos = positions[randIndex]; + positions.splice(randIndex, 1); + + // Random squares for cardinal + marshal + randIndex = randInt(5); + let cardinalPos = positions[randIndex]; + positions.splice(randIndex, 1); + randIndex = randInt(4); + let marshalPos = positions[randIndex]; + positions.splice(randIndex, 1); + + let rook1Pos = positions[0]; + let kingPos = positions[1]; + let rook2Pos = positions[2]; + + pieces[c][rook1Pos] = "r"; + pieces[c][knight1Pos] = "n"; + pieces[c][bishop1Pos] = "b"; + pieces[c][queenPos] = "q"; + pieces[c][kingPos] = "k"; + pieces[c][marshalPos] = "m"; + pieces[c][cardinalPos] = "c"; + pieces[c][bishop2Pos] = "b"; + pieces[c][knight2Pos] = "n"; + pieces[c][rook2Pos] = "r"; + flags += V.CoordToColumn(rook1Pos) + V.CoordToColumn(rook2Pos); + } return ( - "rnbqkmcbnr/pppppppppp/91/91/91/91/91/91/PPPPPPPPPP/RNBQKMCBNR " + - "w 0 ajeaje - 00000000000000" + pieces["b"].join("") + + "/pppppppppp/91/91/91/91/91/91/PPPPPPPPPP/" + + pieces["w"].join("").toUpperCase() + + " w 0 " + flags + " - 00000000000000" ); - // TODO later: randomization too --> 2 bishops, not next to each other. - // then knights next to bishops. Then other pieces (...). } getEnpassantFen() { @@ -223,6 +269,7 @@ export class PandemoniumRules extends ChessRules { getReserveMoves([x, y]) { const color = this.turn; + const oppCol = V.GetOppCol(color); const p = V.RESERVE_PIECES[y]; if (this.reserve[color][p] == 0) return []; const bounds = (p == V.PAWN ? [1, V.size.x - 1] : [0, V.size.x]); @@ -285,54 +332,53 @@ export class PandemoniumRules extends ChessRules { ]; } const firstRank = (this.movesCount == 0 ? 9 : 0); - // TODO: initDestFile currently hardcoded for deterministic setup - const initDestFile = new Map([[1, 2], [8, 7]]); - // Only option is knight --> bishop swap: - if ( - x == firstRank && - !!initDestFile.get(y) && - this.getPiece(x, y) == V.KNIGHT - ) { - const destFile = initDestFile.get(y); - return [ - new Move({ - appear: [ - new PiPo({ - x: x, - y: destFile, - c: c, - p: V.KNIGHT - }), - new PiPo({ - x: x, - y: y, - c: c, - p: V.BISHOP - }) - ], - vanish: [ - new PiPo({ - x: x, - y: y, - c: c, - p: V.KNIGHT - }), - new PiPo({ - x: x, - y: destFile, - c: c, - p: V.BISHOP - }) - ], - start: { x: x, y: y }, - end: { x: x, y: destFile } - }) - ]; + if (x != firstRank || this.getPiece(x, y) != V.KNIGHT) return []; + // Swap with who? search for matching bishop: + let knights = [], + bishops = []; + for (let i = 0; i < 10; i++) { + const elt = this.board[x][i][1]; + if (elt == 'n') knights.push(i); + else if (elt == 'b') bishops.push(i); } - return []; + const destFile = (knights[0] == y ? bishops[0] : bishops[1]); + return [ + new Move({ + appear: [ + new PiPo({ + x: x, + y: destFile, + c: c, + p: V.KNIGHT + }), + new PiPo({ + x: x, + y: y, + c: c, + p: V.BISHOP + }) + ], + vanish: [ + new PiPo({ + x: x, + y: y, + c: c, + p: V.KNIGHT + }), + new PiPo({ + x: x, + y: destFile, + c: c, + p: V.BISHOP + }) + ], + start: { x: x, y: y }, + end: { x: x, y: destFile } + }) + ]; } // Normal move (after initial setup) - if (x >= V.size.x) return this.getReserveMoves(x, y); + if (x >= V.size.x) return this.getReserveMoves([x, y]); const p = this.getPiece(x, y); const sq = [x, y]; let moves = []; @@ -360,10 +406,10 @@ export class PandemoniumRules extends ChessRules { // Maybe apply promotions: if (Object.keys(V.PromoteMap).includes(p)) { const promoted = V.PromoteMap[p]; - const lastRank = (c == 'w' ? 0 : 9); + const lastRanks = (c == 'w' ? [0, 1] : [9, 8]); let promotions = []; moves.forEach(m => { - if (m.start.x == lastRank || m.end.x == lastRank) { + if (lastRanks.includes(m.start.x) || lastRanks.includes(m.end.x)) { let pMove = JSON.parse(JSON.stringify(m)); pMove.appear[0].p = promoted; promotions.push(pMove); @@ -374,19 +420,34 @@ export class PandemoniumRules extends ChessRules { return moves; } + addPawnMoves([x1, y1], [x2, y2], moves) { + const color = this.turn; + const lastRanks = (color == "w" ? [0, 1] : [9, 8]); + if (!lastRanks.includes(x2)) { + moves.push(this.getBasicMove([x1, y1], [x2, y2])); + return; + } + let finalPieces = [V.GILDING]; + if (x2 == lastRanks[1]) finalPieces.push(V.PAWN); + for (let piece of finalPieces) { + const tr = (piece != V.PAWN ? { c: color, p: piece } : null); + moves.push(this.getBasicMove([x1, y1], [x2, y2], tr)); + } + } + getPotentialPawnMoves([x, y]) { const color = this.turn; - const shiftX = V.PawnSpecs.directions[color]; + const shiftX = (color == 'w' ? -1 : 1); let moves = []; if (this.board[x + shiftX][y] == V.EMPTY) { this.addPawnMoves([x, y], [x + shiftX, y], moves); - if ((color == 'w' && x >= V.size.x - 3) || (color == 'b' && x <= 3)) { + if ((color == 'w' && x >= V.size.x - 3) || (color == 'b' && x <= 2)) { if (this.board[x + 2 * shiftX][y] == V.EMPTY) { moves.push(this.getBasicMove([x, y], [x + 2 * shiftX, y])); if ( ( - (color == 'w' && x >= V.size.x - 2) || - (color == 'b' && x <= 2) + (color == 'w' && x == V.size.x - 2) || + (color == 'b' && x == 1) ) && this.board[x + 3 * shiftX][y] == V.EMPTY @@ -477,25 +538,14 @@ export class PandemoniumRules extends ChessRules { if ( this.castleFlags[c][0] < V.size.y || this.castleFlags[c][1] < V.size.y - ) { - moves = moves.concat(this.getCastleMoves(sq)); - } - return moves; - } - - getCastleMoves([x, y]) { - const c = this.getColor(x, y); - if ( - ((c == 'w' && x == 9) || (c == 'b' && x == 0)) && - y == this.castleFlags[c][2] ) { const finalSquares = [ [1, 2], [7, 6] ]; - return super.getCastleMoves([x, y], finalSquares, false, [V.ROOK]); + moves = moves.concat(super.getCastleMoves(sq, finalSquares)); } - return []; + return moves; } isAttacked(sq, color) { @@ -541,23 +591,23 @@ export class PandemoniumRules extends ChessRules { const steps = V.steps[V.KNIGHT].concat(V.steps[V.ROOK]).concat(V.steps[V.BISHOP]); return ( - super.isAttackedBySlideNJump(sq, color, steps, V.SCEPTER, "oneStep") + super.isAttackedBySlideNJump(sq, color, V.SCEPTER, steps, "oneStep") ); } isAttackedByHorse(sq, color) { return ( - super.isAttackedBySlideNJump(sq, color, V.steps[V.BISHOP], V.HORSE) || + super.isAttackedBySlideNJump(sq, color, V.HORSE, V.steps[V.BISHOP]) || super.isAttackedBySlideNJump( - sq, color, V.steps[V.ROOK], V.HORSE, "oneStep") + sq, color, V.HORSE, V.steps[V.ROOK], "oneStep") ); } isAttackedByDragon(sq, color) { return ( - super.isAttackedBySlideNJump(sq, color, V.steps[V.ROOK], V.DRAGON) || + super.isAttackedBySlideNJump(sq, color, V.DRAGON, V.steps[V.ROOK]) || super.isAttackedBySlideNJump( - sq, color, V.steps[V.BISHOP], V.DRAGON, "oneStep") + sq, color, V.DRAGON, V.steps[V.BISHOP], "oneStep") ); } @@ -623,7 +673,8 @@ export class PandemoniumRules extends ChessRules { s: 'n', h: 'b', w: 'c', - a: 'm' + a: 'm', + g: 'p' }; } @@ -647,14 +698,6 @@ export class PandemoniumRules extends ChessRules { this.postPlay(move); } - updateCastleFlags(move, piece) { - if (move.appear.length == 2) { - // Castling (only move which disable flags) - this.castleFlags[move.appear[0].c][0] = 10; - this.castleFlags[move.appear[0].c][1] = 10; - } - } - postPlay(move) { if (move.vanish.length == 0 && move.appear.length == 0) return; super.postPlay(move); @@ -689,40 +732,12 @@ export class PandemoniumRules extends ChessRules { this.reserve[color][V.MayDecode(move.vanish[1].p)]--; } - getCurrentScore() { - const c = this.turn, - oppCol = V.GetOppCol(this.turn); - let facingKings = false; - if ( - this.kingPos[c][0] == this.kingPos[oppCol][0] || - this.kingPos[c][1] == this.kingPos[oppCol][1] - ) { - facingKings = true; - let step = [ - this.kingPos[oppCol][0] - this.kingPos[c][0], - this.kingPos[oppCol][1] - this.kingPos[c][1] - ]; - if (step[0] != 0) step[0] /= Math.abs(step[0]); - else step[1] /= Math.abs(step[1]); - let [x, y] = - [ this.kingPos[c][0] + step[0], this.kingPos[c][1] + step[1] ]; - while (x != this.kingPos[oppCol][0] || y != this.kingPos[oppCol][1]) { - if (this.board[x][y] != V.EMPTY) { - facingKings = false; - break; - } - x += step[0]; - y += step[1]; - } - } - if (facingKings) return (c == "w" ? "1-0" : "0-1"); - if (!this.atLeastOneMove()) return (c == "w" ? "0-1" : "1-0"); - return "*"; - } - static get VALUES() { return Object.assign( + {}, + ChessRules.VALUES, { + n: 2.5, //knight is weaker g: 9, s: 5, h: 6, @@ -731,8 +746,7 @@ export class PandemoniumRules extends ChessRules { w: 9, m: 8, a: 9 - }, - ChessRules.VALUES + } ); }