X-Git-Url: https://git.auder.net/?a=blobdiff_plain;f=base_rules.js;h=0b7d6ed8a397851df0fb3b34007942ff8666e716;hb=126ffc709b84d4919dc2c1726577e59211198a1b;hp=b98c7248d29a2bec84794f6cfd412e236cb30b92;hpb=f3e90e30b6e7ff416afe288bc9dd865e5daf9860;p=xogo.git diff --git a/base_rules.js b/base_rules.js index b98c724..0b7d6ed 100644 --- a/base_rules.js +++ b/base_rules.js @@ -116,6 +116,11 @@ export default class ChessRules { return false; } + // Some variants reveal moves only after both players played + get hideMoves() { + return false; + } + // Some variants use click infos: doClick(coords) { if (typeof coords.x != "number") @@ -197,8 +202,19 @@ export default class ChessRules { return (f.charCodeAt(0) <= 90 ? "w" + f.toLowerCase() : "b" + f); } - // Setup the initial random-or-not (asymmetric-or-not) position genRandInitFen(seed) { + Random.setSeed(seed); //may be unused + let baseFen = this.genRandInitBaseFen(); + baseFen.o = Object.assign({init: true}, baseFen.o); + const parts = this.getPartFen(baseFen.o); + return ( + baseFen.fen + + (Object.keys(parts).length > 0 ? (" " + JSON.stringify(parts)) : "") + ); + } + + // Setup the initial random-or-not (asymmetric-or-not) position + genRandInitBaseFen() { let fen, flags = "0707"; if (!this.options.randomness) // Deterministic: @@ -206,7 +222,6 @@ export default class ChessRules { else { // Randomize - Random.setSeed(seed); let pieces = {w: new Array(8), b: new Array(8)}; flags = ""; // Shuffle pieces on first (and last rank if randomness == 2) @@ -216,9 +231,7 @@ export default class ChessRules { flags += flags; break; } - let positions = ArrayFun.range(8); - // Get random squares for bishops let randIndex = 2 * Random.randInt(4); const bishop1Pos = positions[randIndex]; @@ -228,7 +241,6 @@ export default class ChessRules { // Remove chosen squares positions.splice(Math.max(randIndex, randIndex_tmp), 1); positions.splice(Math.min(randIndex, randIndex_tmp), 1); - // Get random squares for knights randIndex = Random.randInt(6); const knight1Pos = positions[randIndex]; @@ -236,18 +248,15 @@ export default class ChessRules { randIndex = Random.randInt(5); const knight2Pos = positions[randIndex]; positions.splice(randIndex, 1); - // Get random square for queen randIndex = Random.randInt(4); const queenPos = positions[randIndex]; positions.splice(randIndex, 1); - // Rooks and king positions are now fixed, // because of the ordering rook-king-rook const rook1Pos = positions[0]; const kingPos = positions[1]; const rook2Pos = positions[2]; - // Finally put the shuffled pieces in the board array pieces[c][rook1Pos] = "r"; pieces[c][knight1Pos] = "n"; @@ -266,19 +275,7 @@ export default class ChessRules { " w 0" ); } - // Add turn + flags + enpassant (+ reserve) - let parts = []; - if (this.hasFlags) - parts.push(`"flags":"${flags}"`); - if (this.hasEnpassant) - parts.push('"enpassant":"-"'); - if (this.hasReserveFen) - parts.push('"reserve":"000000000000"'); - if (this.options["crazyhouse"]) - parts.push('"ispawn":"-"'); - if (parts.length >= 1) - fen += " {" + parts.join(",") + "}"; - return fen; + return { fen: fen, o: {flags: flags} }; } // "Parse" FEN: just return untransformed string data @@ -296,23 +293,28 @@ export default class ChessRules { // Return current fen (game state) getFen() { - let fen = ( - this.getPosition() + " " + - this.getTurnFen() + " " + - this.movesCount + const parts = this.getPartFen({}); + return ( + this.getBaseFen() + + (Object.keys(parts).length > 0 ? (" " + JSON.stringify(parts)) : "") ); - let parts = []; + } + + getBaseFen() { + return this.getPosition() + " " + this.turn + " " + this.movesCount; + } + + getPartFen(o) { + let parts = {}; if (this.hasFlags) - parts.push(`"flags":"${this.getFlagsFen()}"`); + parts["flags"] = o.init ? o.flags : this.getFlagsFen(); if (this.hasEnpassant) - parts.push(`"enpassant":"${this.getEnpassantFen()}"`); + parts["enpassant"] = o.init ? "-" : this.getEnpassantFen(); if (this.hasReserveFen) - parts.push(`"reserve":"${this.getReserveFen()}"`); + parts["reserve"] = this.getReserveFen(o); if (this.options["crazyhouse"]) - parts.push(`"ispawn":"${this.getIspawnFen()}"`); - if (parts.length >= 1) - fen += " {" + parts.join(",") + "}"; - return fen; + parts["ispawn"] = this.getIspawnFen(o); + return parts; } static FenEmptySquares(count) { @@ -353,10 +355,6 @@ export default class ChessRules { return position; } - getTurnFen() { - return this.turn; - } - // Flags part of the FEN string getFlagsFen() { return ["w", "b"].map(c => { @@ -367,17 +365,22 @@ export default class ChessRules { // Enpassant part of the FEN string getEnpassantFen() { if (!this.epSquare) - return "-"; //no en-passant + return "-"; return C.CoordsToSquare(this.epSquare); } - getReserveFen() { + getReserveFen(o) { + if (o.init) + return "000000000000"; return ( ["w","b"].map(c => Object.values(this.reserve[c]).join("")).join("") ); } - getIspawnFen() { + getIspawnFen(o) { + if (o.init) + // NOTE: cannot merge because this.ispawn doesn't exist yet + return "-"; const squares = Object.keys(this.ispawn); if (squares.length == 0) return "-"; @@ -405,18 +408,18 @@ export default class ChessRules { if (o.genFenOnly) // This object will be used only for initial FEN generation return; + + // Some variables this.playerColor = o.color; this.afterPlay = o.afterPlay; //trigger some actions after playing a move + this.containerId = o.element; + this.isDiagram = o.diagram; + this.marks = o.marks; - // Fen string fully describes the game state + // Initializations if (!o.fen) o.fen = this.genRandInitFen(o.seed); this.re_initFromFen(o.fen); - - // Graphical (can use variables defined above) - this.containerId = o.element; - this.isDiagram = o.diagram; - this.marks = o.marks; this.graphicalInit(); } @@ -1076,6 +1079,21 @@ export default class ChessRules { } } + displayMessage(elt, msg, classe_s, timeout) { + if (elt) + // Fixed element, e.g. for Dice Chess + elt.innerHTML = msg; + else { + // Temporary div (Chakart, Apocalypse...) + let divMsg = document.createElement("div"); + C.AddClass_es(divMsg, classe_s); + divMsg.innerHTML = msg; + let container = document.getElementById(this.containerId); + container.appendChild(divMsg); + setTimeout(() => container.removeChild(divMsg), timeout); + } + } + //////////////// // DARK METHODS @@ -1529,18 +1547,18 @@ export default class ChessRules { moves = this.capturePostProcess(moves, oppCol); if (this.options["atomic"]) - this.atomicPostProcess(moves, color, oppCol); + moves = this.atomicPostProcess(moves, color, oppCol); if ( moves.length > 0 && this.getPieceType(moves[0].start.x, moves[0].start.y) == "p" ) { - this.pawnPostProcess(moves, color, oppCol); + moves = this.pawnPostProcess(moves, color, oppCol); } if (this.options["cannibal"] && this.options["rifle"]) // In this case a rifle-capture from last rank may promote a pawn - this.riflePromotePostProcess(moves, color); + moves = this.riflePromotePostProcess(moves, color); return moves; } @@ -1612,6 +1630,7 @@ export default class ChessRules { m.next = mNext; } }); + return moves; } pawnPostProcess(moves, color, oppCol) { @@ -1631,7 +1650,7 @@ export default class ChessRules { m.appear.shift(); return; } - let finalPieces = ["p"]; + let finalPieces; if ( this.options["cannibal"] && this.board[x2][y2] != "" && @@ -1645,16 +1664,13 @@ export default class ChessRules { if (initPiece == "!") //cannibal king-pawn m.appear[0].p = C.CannibalKingCode[finalPieces[0]]; for (let i=1; i targetObj.increment()); } } + targetObj.target += + this.tryAnimateCastle(move, () => targetObj.increment()); targetObj.target += this.customAnimate(move, segments, () => targetObj.increment()); if (targetObj.target == 0) callback(); } + tryAnimateCastle(move, cb) { + if ( + this.hasCastle && + move.vanish.length == 2 && + move.appear.length == 2 && + this.isKing(0, 0, move.vanish[0].p) && + this.isKing(0, 0, move.appear[0].p) + ) { + const start = {x: move.vanish[1].x, y: move.vanish[1].y}, + end = {x: move.appear[1].x, y: move.appear[1].y}; + const segments = [ [[start.x, start.y], [end.x, end.y]] ]; + this.animateMoving(start, end, null, segments, cb); + return 1; + } + return 0; + } + // Potential other animations (e.g. for Suction variant) customAnimate(move, segments, cb) { return 0; //nb of targets } - playReceivedMove(moves, callback) { - const launchAnimation = () => { - const r = container.querySelector(".chessboard").getBoundingClientRect(); - const animateRec = i => { - this.animate(moves[i], () => { - this.play(moves[i]); - this.playVisual(moves[i], r); - if (i < moves.length - 1) - setTimeout(() => animateRec(i+1), 300); - else - callback(); - }); - }; - animateRec(0); + launchAnimation(moves, container, callback) { + if (this.hideMoves) { + moves.forEach(m => this.play(m)); + callback(); + return; + } + const r = container.querySelector(".chessboard").getBoundingClientRect(); + const animateRec = i => { + this.animate(moves[i], () => { + this.play(moves[i]); + this.playVisual(moves[i], r); + if (i < moves.length - 1) + setTimeout(() => animateRec(i+1), 300); + else + callback(); + }); }; + animateRec(0); + } + + playReceivedMove(moves, callback) { // Delay if user wasn't focused: const checkDisplayThenAnimate = (delay) => { if (container.style.display == "none") { alert("New move! Let's go back to game..."); document.getElementById("gameInfos").style.display = "none"; container.style.display = "block"; - setTimeout(launchAnimation, 700); + setTimeout( + () => this.launchAnimation(moves, container, callback), + 700 + ); + } + else { + setTimeout( + () => this.launchAnimation(moves, container, callback), + delay || 0 + ); } - else - setTimeout(launchAnimation, delay || 0); }; let container = document.getElementById(this.containerId); if (document.hidden) {