X-Git-Url: https://git.auder.net/?a=blobdiff_plain;ds=inline;f=base_rules.js;h=b315fd59a94ae77d3e2aa4a366e58245ae6a3805;hb=f3824309fa7dffd121ebb859088362997cabe9c3;hp=0b7d6ed8a397851df0fb3b34007942ff8666e716;hpb=126ffc709b84d4919dc2c1726577e59211198a1b;p=xogo.git diff --git a/base_rules.js b/base_rules.js index 0b7d6ed..b315fd5 100644 --- a/base_rules.js +++ b/base_rules.js @@ -1,5 +1,5 @@ -import { Random } from "/utils/alea.js"; -import { ArrayFun } from "/utils/array.js"; +import {Random} from "/utils/alea.js"; +import {ArrayFun} from "/utils/array.js"; import PiPo from "/utils/PiPo.js"; import Move from "/utils/Move.js"; @@ -208,7 +208,7 @@ export default class ChessRules { baseFen.o = Object.assign({init: true}, baseFen.o); const parts = this.getPartFen(baseFen.o); return ( - baseFen.fen + + baseFen.fen + " w 0" + (Object.keys(parts).length > 0 ? (" " + JSON.stringify(parts)) : "") ); } @@ -218,7 +218,7 @@ export default class ChessRules { let fen, flags = "0707"; if (!this.options.randomness) // Deterministic: - fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w 0"; + fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR"; else { // Randomize @@ -271,8 +271,7 @@ export default class ChessRules { fen = ( pieces["b"].join("") + "/pppppppp/8/8/8/8/PPPPPPPP/" + - pieces["w"].join("").toUpperCase() + - " w 0" + pieces["w"].join("").toUpperCase() ); } return { fen: fen, o: {flags: flags} }; @@ -477,17 +476,15 @@ export default class ChessRules { } // ordering as in pieces() p,r,n,b,q,k - initReserves(reserveStr) { + initReserves(reserveStr, pieceArray) { + if (!pieceArray) + pieceArray = ['p', 'r', 'n', 'b', 'q', 'k']; const counts = reserveStr.split("").map(c => parseInt(c, 36)); - this.reserve = { w: {}, b: {} }; - const pieceName = ['p', 'r', 'n', 'b', 'q', 'k']; - const L = pieceName.length; - for (let i of ArrayFun.range(2 * L)) { - if (i < L) - this.reserve['w'][pieceName[i]] = counts[i]; - else - this.reserve['b'][pieceName[i-L]] = counts[i]; - } + const L = pieceArray.length; + this.reserve = { + w: ArrayFun.toObject(pieceArray, counts.slice(0, L)), + b: ArrayFun.toObject(pieceArray, counts.slice(L, 2 * L)) + }; } initIspawn(ispawnStr) { @@ -528,20 +525,16 @@ export default class ChessRules { (oldV,newV) => oldV + (this.reserve[c][newV] > 0 ? 1 : 0), 0); } - static AddClass_es(piece, class_es) { + static AddClass_es(elt, class_es) { if (!Array.isArray(class_es)) class_es = [class_es]; - class_es.forEach(cl => { - piece.classList.add(cl); - }); + class_es.forEach(cl => elt.classList.add(cl)); } - static RemoveClass_es(piece, class_es) { + static RemoveClass_es(elt, class_es) { if (!Array.isArray(class_es)) class_es = [class_es]; - class_es.forEach(cl => { - piece.classList.remove(cl); - }); + class_es.forEach(cl => elt.classList.remove(cl)); } // Generally light square bottom-right @@ -629,6 +622,8 @@ export default class ChessRules { class="chessboard_SVG">`; for (let i=0; i < this.size.x; i++) { for (let j=0; j < this.size.y; j++) { + if (!this.onBoard(i, j)) + continue; const ii = (flipped ? this.size.x - 1 - i : i); const jj = (flipped ? this.size.y - 1 - j : j); let classes = this.getSquareColorClass(ii, jj); @@ -784,8 +779,8 @@ export default class ChessRules { piece = "k"; //capturing cannibal king: back to king form const oldCount = this.reserve[color][piece]; this.reserve[color][piece] = count; - // Redrawing is much easier if count==0 - if ([oldCount, count].includes(0)) + // Redrawing is much easier if count==0 (or undefined) + if ([oldCount, count].some(item => !item)) this.re_drawReserve([color]); else { const numId = this.getReserveNumId(color, piece); @@ -1018,11 +1013,10 @@ export default class ChessRules { // TODO: onpointerdown/move/up ? See reveal.js /controllers/touch.js } + // NOTE: not called if isDiagram, or genFenOnly removeListeners() { let container = document.getElementById(this.containerId); this.windowResizeObs.unobserve(container); - if (this.isDiagram) - return; //no listeners in this case if ('onmousedown' in window) { this.mouseListeners.forEach(ml => { document.removeEventListener(ml.type, ml.listener); @@ -1247,13 +1241,13 @@ export default class ChessRules { }, 'r': { "class": "rook", - moves: [ + both: [ {steps: [[0, 1], [0, -1], [1, 0], [-1, 0]]} ] }, 'n': { "class": "knight", - moves: [ + both: [ { steps: [ [1, 2], [1, -2], [-1, 2], [-1, -2], @@ -1265,13 +1259,13 @@ export default class ChessRules { }, 'b': { "class": "bishop", - moves: [ + both: [ {steps: [[1, 1], [1, -1], [-1, 1], [-1, -1]]} ] }, 'q': { "class": "queen", - moves: [ + both: [ { steps: [ [0, 1], [0, -1], [1, 0], [-1, 0], @@ -1282,7 +1276,7 @@ export default class ChessRules { }, 'k': { "class": "king", - moves: [ + both: [ { steps: [ [0, 1], [0, -1], [1, 0], [-1, 0], @@ -1346,7 +1340,20 @@ export default class ChessRules { } getStepSpec(color, x, y, piece) { - return this.pieces(color, x, y)[piece || this.getPieceType(x, y)]; + let pieceType = piece; + let allSpecs = this.pieces(color, x, y); + if (!piece) + pieceType = this.getPieceType(x, y); + else if (allSpecs[piece].moveas) + pieceType = allSpecs[piece].moveas; + let res = allSpecs[pieceType]; + if (!res["both"]) + res.both = []; + if (!res["moves"]) + res.moves = []; + if (!res["attack"]) + res.attack = []; + return res; } // Can thing on square1 capture thing on square2? @@ -1380,7 +1387,7 @@ export default class ChessRules { const oppCol = C.GetOppCol(color); const piece = this.getPieceType(x, y); const stepSpec = this.getStepSpec(color, x, y, piece); - const attacks = stepSpec.attack || stepSpec.moves; + const attacks = stepSpec.both.concat(stepSpec.attack); for (let a of attacks) { outerLoop: for (let step of a.steps) { let [i, j] = [x + step[0], y + step[1]]; @@ -1494,7 +1501,7 @@ export default class ChessRules { let moves = []; for (let i=0; i { + const exploreSteps = (stepArray, mode) => { for (let s of stepArray) { outerLoop: for (let step of s.steps) { if (o.segments) { @@ -1798,9 +1805,9 @@ export default class ChessRules { !o.captureTarget || (o.captureTarget[0] == i && o.captureTarget[1] == j) ) { - if (o.one && !o.attackOnly) + if (o.one && mode != "attack") return true; - if (!o.attackOnly) + if (mode != "attack") addSquare(!o.captureTarget ? [i, j] : [x, y]); if (o.captureTarget) return res[0]; @@ -1823,9 +1830,9 @@ export default class ChessRules { if (!explored[i + "." + j]) { explored[i + "." + j] = true; if (allowed([x, y], [i, j])) { - if (o.one && !o.moveOnly) + if (o.one && mode != "moves") return true; - if (!o.moveOnly) + if (mode != "moves") addSquare(!o.captureTarget ? [i, j] : [x, y]); if ( o.captureTarget && @@ -1840,17 +1847,15 @@ export default class ChessRules { return undefined; //default, but let's explicit it }; if (o.captureTarget) - return exploreSteps(o.captureSteps) + return exploreSteps(o.captureSteps, "attack"); else { const stepSpec = o.stepSpec || this.getStepSpec(this.getColor(x, y), x, y); let outOne = false; - if (!o.attackOnly || !stepSpec.attack) - outOne = exploreSteps(stepSpec.moves); - if (!outOne && !o.moveOnly && !!stepSpec.attack) { - o.attackOnly = true; //ok because o is always a temporary object - outOne = exploreSteps(stepSpec.attack); - } + if (!o.attackOnly) + outOne = exploreSteps(stepSpec.both.concat(stepSpec.moves), "moves"); + if (!outOne && !o.moveOnly) + outOne = exploreSteps(stepSpec.both.concat(stepSpec.attack), "attack"); return (o.one ? outOne : res); } } @@ -1873,7 +1878,7 @@ export default class ChessRules { if (this.canStepOver(x, y, apparentPiece)) continue; const stepSpec = this.getStepSpec(colIJ, i, j); - const attacks = stepSpec.attack || stepSpec.moves; + const attacks = stepSpec.attack.concat(stepSpec.both); for (let a of attacks) { for (let s of a.steps) { // Quick check: if step isn't compatible, don't even try @@ -2075,7 +2080,7 @@ export default class ChessRules { // will be executed in filterValid() later. ( i != finalSquares[castleSide][0] && - this.underCheck([x, i], oppCol) + this.underCheck([[x, i]], oppCol) ) || ( @@ -2182,8 +2187,6 @@ export default class ChessRules { underCheck(square_s, oppCol) { if (this.options["taking"] || this.options["dark"]) return false; - if (!Array.isArray(square_s[0])) - square_s = [square_s]; return square_s.some(sq => this.underAttack(sq, oppCol)); } @@ -2345,14 +2348,13 @@ export default class ChessRules { } postPlay(move) { - const color = this.turn; if (this.options["dark"]) this.updateEnlightened(); if (this.options["teleport"]) { if ( this.subTurnTeleport == 1 && move.vanish.length > move.appear.length && - move.vanish[1].c == color + move.vanish[1].c == this.turn ) { const v = move.vanish[move.vanish.length - 1]; this.captured = {x: v.x, y: v.y, c: v.c, p: v.p}; @@ -2362,8 +2364,12 @@ export default class ChessRules { this.subTurnTeleport = 1; this.captured = null; } + this.tryChangeTurn(move); + } + + tryChangeTurn(move) { if (this.isLastMove(move)) { - this.turn = C.GetOppCol(color); + this.turn = C.GetOppCol(this.turn); this.movesCount++; this.subTurn = 1; } @@ -2422,7 +2428,11 @@ export default class ChessRules { } // What is the score ? (Interesting if game is over) - getCurrentScore(move) { + getCurrentScore(move_s) { + const move = move_s[move_s.length - 1]; + // Shortcut in case the score was computed before: + if (move.result) + return move.result; const color = this.turn; const oppCol = C.GetOppCol(color); const kingPos = { @@ -2477,32 +2487,37 @@ export default class ChessRules { buildMoveStack(move, r) { this.moveStack.push(move); this.computeNextMove(move); - this.play(move); - const newTurn = this.turn; - if (this.moveStack.length == 1 && !this.hideMoves) - this.playVisual(move, r); - if (move.next) { - this.gameState = { - fen: this.getFen(), - board: JSON.parse(JSON.stringify(this.board)) //easier - }; - this.buildMoveStack(move.next, r); - } - else { - if (this.moveStack.length == 1) { - // Usual case (one normal move) - this.afterPlay(this.moveStack, newTurn, {send: true, res: true}); - this.moveStack = [] + const then = () => { + const newTurn = this.turn; + if (this.moveStack.length == 1 && !this.hideMoves) + this.playVisual(move, r); + if (move.next) { + this.gameState = { + fen: this.getFen(), + board: JSON.parse(JSON.stringify(this.board)) //easier + }; + this.buildMoveStack(move.next, r); } else { - this.afterPlay(this.moveStack, newTurn, {send: true, res: false}); - this.re_initFromFen(this.gameState.fen, this.gameState.board); - this.playReceivedMove(this.moveStack.slice(1), () => { - this.afterPlay(this.moveStack, newTurn, {send: false, res: true}); - this.moveStack = [] - }); + if (this.moveStack.length == 1) { + // Usual case (one normal move) + this.afterPlay(this.moveStack, newTurn, {send: true, res: true}); + this.moveStack = []; + } + else { + this.afterPlay(this.moveStack, newTurn, {send: true, res: false}); + this.re_initFromFen(this.gameState.fen, this.gameState.board); + this.playReceivedMove(this.moveStack.slice(1), () => { + this.afterPlay(this.moveStack, newTurn, {send: false, res: true}); + this.moveStack = []; + }); + } } - } + }; + // If hiding moves, then they are revealed in play() with callback + this.play(move, this.hideMoves ? then : null); + if (!this.hideMoves) + then(); } // Implemented in variants using (automatic) moveStack @@ -2633,8 +2648,9 @@ export default class ChessRules { launchAnimation(moves, container, callback) { if (this.hideMoves) { - moves.forEach(m => this.play(m)); - callback(); + for (let i=0; i {}); return; } const r = container.querySelector(".chessboard").getBoundingClientRect();