- // Set flags and enpassant:
- if (this.hasFlags)
- this.setFlags(fenParsed.flags);
- if (this.hasEnpassant)
- this.epSquare = this.getEpSquare(fenParsed.enpassant);
- if (this.hasReserve && !this.isDiagram)
- this.initReserves(fenParsed.reserve);
- if (this.options["crazyhouse"])
- this.initIspawn(fenParsed.ispawn);
- if (this.options["teleport"]) {
- this.subTurnTeleport = 1;
- this.captured = null;
- }
- if (this.options["dark"]) {
- // Setup enlightened: squares reachable by player side
- this.enlightened = ArrayFun.init(this.size.x, this.size.y, false);
- this.updateEnlightened();
- }
- this.subTurn = 1; //may be unused
- if (!this.moveStack) //avoid resetting (unwanted)
- this.moveStack = [];
- }
-
- // ordering as in pieces() p,r,n,b,q,k
- static get ReserveArray() {
- return ['p', 'r', 'n', 'b', 'q', 'k'];
- }
-
- initReserves(reserveStr) {
- const counts = reserveStr.split("").map(c => parseInt(c, 36));
- const L = V.ReserveArray.length;
- this.reserve = {
- w: ArrayFun.toObject(V.ReserveArray, counts.slice(0, L)),
- b: ArrayFun.toObject(V.ReserveArray, counts.slice(L, 2 * L))
- };
- }
-
- initIspawn(ispawnStr) {
- if (ispawnStr != "-")
- this.ispawn = ArrayFun.toObject(ispawnStr.split(","), true);
- else
- this.ispawn = {};
- }
-
- ////////////////
- // VISUAL UTILS
-
- getPieceWidth(rwidth) {
- return (rwidth / Math.max(this.size.x, this.size.y));
- }
-
- getReserveSquareSize(rwidth, nbR) {
- const sqSize = this.getPieceWidth(rwidth);
- return Math.min(sqSize, rwidth / nbR);
- }
-
- getReserveNumId(color, piece) {
- return `${this.containerId}|rnum-${color}${piece}`;
- }
-
- getNbReservePieces(color) {
- return (
- Object.values(this.reserve[color]).reduce(
- (oldV,newV) => oldV + (newV > 0 ? 1 : 0), 0)
- );
- }
-
- getRankInReserve(c, p) {
- const pieces = Object.keys(this.pieces(c, c, p));
- const lastIndex = pieces.findIndex(pp => pp == p)
- let toTest = pieces.slice(0, lastIndex);
- return toTest.reduce(
- (oldV,newV) => oldV + (this.reserve[c][newV] > 0 ? 1 : 0), 0);
- }
-
- static AddClass_es(elt, class_es) {
- if (!Array.isArray(class_es))
- class_es = [class_es];
- class_es.forEach(cl => elt.classList.add(cl));
- }
-
- static RemoveClass_es(elt, class_es) {
- if (!Array.isArray(class_es))
- class_es = [class_es];
- class_es.forEach(cl => elt.classList.remove(cl));
- }
-
- // Generally light square bottom-right
- getSquareColorClass(x, y) {
- return ((x+y) % 2 == 0 ? "light-square": "dark-square");
- }
-
- getMaxDistance(r) {
- // Works for all rectangular boards:
- return Math.sqrt(r.width ** 2 + r.height ** 2);
- }
-
- getDomPiece(x, y) {
- return (typeof x == "string" ? this.r_pieces : this.g_pieces)[x][y];
- }
-
- //////////////////
- // VISUAL METHODS
-
- graphicalInit() {
- const g_init = () => {
- this.re_drawBoardElements();
- if (!this.isDiagram && !this.mouseListeners && !this.touchListeners)
- this.initMouseEvents();
- };
- let container = document.getElementById(this.containerId);
- this.windowResizeObs = new ResizeObserver(g_init);
- this.windowResizeObs.observe(container);
- }
-
- re_drawBoardElements() {
- const board = this.getSvgChessboard();
- const container = document.getElementById(this.containerId);
- const rc = container.getBoundingClientRect();
- let chessboard = container.querySelector(".chessboard");
- chessboard.innerHTML = "";
- chessboard.insertAdjacentHTML('beforeend', board);
- // Compare window ratio width / height to aspectRatio:
- const windowRatio = rc.width / rc.height;
- let cbWidth, cbHeight;
- const vRatio = this.size.ratio || 1;
- if (windowRatio <= vRatio) {
- // Limiting dimension is width:
- cbWidth = Math.min(rc.width, 767);
- cbHeight = cbWidth / vRatio;
- }
- else {
- // Limiting dimension is height:
- cbHeight = Math.min(rc.height, 767);
- cbWidth = cbHeight * vRatio;
- }
- if (this.hasReserve && !this.isDiagram) {
- const sqSize = cbWidth / this.size.y;
- // NOTE: allocate space for reserves (up/down) even if they are empty
- // Cannot use getReserveSquareSize() here, but sqSize is an upper bound.
- if ((rc.height - cbHeight) / 2 < sqSize + 5) {
- cbHeight = rc.height - 2 * (sqSize + 5);
- cbWidth = cbHeight * vRatio;
- }
- }
- chessboard.style.width = cbWidth + "px";
- chessboard.style.height = cbHeight + "px";
- // Center chessboard:
- const spaceLeft = (rc.width - cbWidth) / 2,
- spaceTop = (rc.height - cbHeight) / 2;
- chessboard.style.left = spaceLeft + "px";
- chessboard.style.top = spaceTop + "px";
- // Give sizes instead of recomputing them,
- // because chessboard might not be drawn yet.
- this.setupVisualPieces({
- width: cbWidth,
- height: cbHeight,
- x: spaceLeft,
- y: spaceTop
- });
- }
-
- // Get SVG board (background, no pieces)
- getSvgChessboard() {
- let board = `
- <svg
- viewBox="0 0 ${10*this.size.y} ${10*this.size.x}"
- class="chessboard_SVG">`;
- board += this.getBaseSvgChessboard();
- board += "</svg>";
- return board;
- }
-
- getBaseSvgChessboard() {
- let board = "";
- const flipped = this.flippedBoard;
- 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);
- if (this.enlightened && !this.enlightened[ii][jj])
- classes += " in-shadow";
- // NOTE: x / y reversed because coordinates system is reversed.
- board += `
- <rect
- class="${classes}"
- id="${this.coordsToId({x: ii, y: jj})}"
- width="10"
- height="10"
- x="${10*j}"
- y="${10*i}"
- />`;
- }
- }
- return board;
- }
-
- setupVisualPieces(r) {
- let chessboard =
- document.getElementById(this.containerId).querySelector(".chessboard");
- if (!r)
- r = chessboard.getBoundingClientRect();
- const pieceWidth = this.getPieceWidth(r.width);
- const addPiece = (i, j, arrName, classes) => {
- this[arrName][i][j] = document.createElement("piece");
- C.AddClass_es(this[arrName][i][j], classes);
- this[arrName][i][j].style.width = pieceWidth + "px";
- this[arrName][i][j].style.height = pieceWidth + "px";
- let [ip, jp] = this.getPixelPosition(i, j, r);
- // Translate coordinates to use chessboard as reference:
- this[arrName][i][j].style.transform =
- `translate(${ip - r.x}px,${jp - r.y}px)`;
- chessboard.appendChild(this[arrName][i][j]);
- };
- const conditionalReset = (arrName) => {
- if (this[arrName]) {
- // Refreshing: delete old pieces first. This isn't necessary,
- // but simpler (this method isn't called many times)
- for (let i=0; i<this.size.x; i++) {
- for (let j=0; j<this.size.y; j++) {
- if (this[arrName][i][j]) {
- this[arrName][i][j].remove();
- this[arrName][i][j] = null;
- }
- }
- }
- }
- else
- this[arrName] = ArrayFun.init(this.size.x, this.size.y, null);
- if (arrName == "d_pieces")
- this.marks.forEach((m) => {
- const mCoords = this.coordsFromUsual(m);
- addPiece(mCoords.x, mCoords.y, arrName, "mark");
- });
- };
- if (this.marks)
- conditionalReset("d_pieces");
- conditionalReset("g_pieces");
- for (let i=0; i < this.size.x; i++) {
- for (let j=0; j < this.size.y; j++) {
- if (this.board[i][j] != "") {
- const color = this.getColor(i, j);
- const piece = this.getPiece(i, j);
- addPiece(i, j, "g_pieces", this.pieces(color, i, j)[piece]["class"]);
- this.g_pieces[i][j].classList.add(V.GetColorClass(color));
- if (this.enlightened && !this.enlightened[i][j])
- this.g_pieces[i][j].classList.add("hidden");
- }
- if (this.marks && this.d_pieces[i][j]) {
- let classes = ["mark"];
- if (this.board[i][j] != "")
- classes.push("transparent");
- addPiece(i, j, "d_pieces", classes);
- }
- }
- }
- if (this.hasReserve && !this.isDiagram)
- this.re_drawReserve(['w', 'b'], r);
- }
-
- // NOTE: assume this.reserve != null
- re_drawReserve(colors, r) {
- if (this.r_pieces) {
- // Remove (old) reserve pieces
- for (let c of colors) {
- Object.keys(this.r_pieces[c]).forEach(p => {
- this.r_pieces[c][p].remove();
- delete this.r_pieces[c][p];
- const numId = this.getReserveNumId(c, p);
- document.getElementById(numId).remove();
- });
- }
- }
- else
- this.r_pieces = { w: {}, b: {} };
- let container = document.getElementById(this.containerId);
- if (!r)
- r = container.querySelector(".chessboard").getBoundingClientRect();
- for (let c of colors) {
- let reservesDiv = document.getElementById("reserves_" + c);
- if (reservesDiv)
- reservesDiv.remove();
- if (!this.reserve[c])
- continue;
- const nbR = this.getNbReservePieces(c);
- if (nbR == 0)
- continue;
- const sqResSize = this.getReserveSquareSize(r.width, nbR);
- let ridx = 0;
- const vShift = (c == this.playerColor ? r.height + 5 : -sqResSize - 5);
- const [i0, j0] = [r.x, r.y + vShift];
- let rcontainer = document.createElement("div");
- rcontainer.id = "reserves_" + c;
- rcontainer.classList.add("reserves");
- rcontainer.style.left = i0 + "px";
- rcontainer.style.top = j0 + "px";
- // NOTE: +1 fix display bug on Firefox at least
- rcontainer.style.width = (nbR * sqResSize + 1) + "px";
- rcontainer.style.height = sqResSize + "px";
- container.appendChild(rcontainer);
- for (let p of Object.keys(this.reserve[c])) {
- if (this.reserve[c][p] == 0)
- continue;
- let r_cell = document.createElement("div");
- r_cell.id = this.coordsToId({x: c, y: p});
- r_cell.classList.add("reserve-cell");
- r_cell.style.width = sqResSize + "px";
- r_cell.style.height = sqResSize + "px";
- rcontainer.appendChild(r_cell);
- let piece = document.createElement("piece");
- C.AddClass_es(piece, this.pieces(c, c, p)[p]["class"]);
- piece.classList.add(V.GetColorClass(c));
- piece.style.width = "100%";
- piece.style.height = "100%";
- this.r_pieces[c][p] = piece;
- r_cell.appendChild(piece);
- let number = document.createElement("div");
- number.textContent = this.reserve[c][p];
- number.classList.add("reserve-num");
- number.id = this.getReserveNumId(c, p);
- const fontSize = "1.3em";
- number.style.fontSize = fontSize;
- number.style.fontSize = fontSize;
- r_cell.appendChild(number);
- ridx++;
- }
- }
- }
-
- updateReserve(color, piece, count) {
- if (this.options["cannibal"] && C.CannibalKings[piece])
- 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 (or undefined)
- if ([oldCount, count].some(item => !item))
- this.re_drawReserve([color]);
- else {
- const numId = this.getReserveNumId(color, piece);
- document.getElementById(numId).textContent = count;
- }
- }
-
- // Resize board: no need to destroy/recreate pieces
- rescale(mode) {
- const container = document.getElementById(this.containerId);
- let chessboard = container.querySelector(".chessboard");
- const rc = container.getBoundingClientRect(),
- r = chessboard.getBoundingClientRect();
- const multFact = (mode == "up" ? 1.05 : 0.95);
- let [newWidth, newHeight] = [multFact * r.width, multFact * r.height];
- // Stay in window:
- const vRatio = this.size.ratio || 1;
- if (newWidth > rc.width) {
- newWidth = rc.width;
- newHeight = newWidth / vRatio;
- }
- if (newHeight > rc.height) {
- newHeight = rc.height;
- newWidth = newHeight * vRatio;
- }
- chessboard.style.width = newWidth + "px";
- chessboard.style.height = newHeight + "px";
- const newX = (rc.width - newWidth) / 2;
- chessboard.style.left = newX + "px";
- const newY = (rc.height - newHeight) / 2;
- chessboard.style.top = newY + "px";
- const newR = {x: newX, y: newY, width: newWidth, height: newHeight};
- const pieceWidth = this.getPieceWidth(newWidth);
- // NOTE: next "if" for variants which use squares filling
- // instead of "physical", moving pieces
- if (this.g_pieces) {
- for (let i=0; i < this.size.x; i++) {
- for (let j=0; j < this.size.y; j++) {
- if (this.g_pieces[i][j]) {
- // NOTE: could also use CSS transform "scale"
- this.g_pieces[i][j].style.width = pieceWidth + "px";
- this.g_pieces[i][j].style.height = pieceWidth + "px";
- const [ip, jp] = this.getPixelPosition(i, j, newR);
- // Translate coordinates to use chessboard as reference:
- this.g_pieces[i][j].style.transform =
- `translate(${ip - newX}px,${jp - newY}px)`;
- }
- }
- }
- }
- if (this.hasReserve)
- this.rescaleReserve(newR);
- }
-
- rescaleReserve(r) {
- for (let c of ['w','b']) {
- if (!this.reserve[c])
- continue;
- const nbR = this.getNbReservePieces(c);
- if (nbR == 0)
- continue;
- // Resize container first
- const sqResSize = this.getReserveSquareSize(r.width, nbR);
- const vShift = (c == this.playerColor ? r.height + 5 : -sqResSize - 5);
- const [i0, j0] = [r.x, r.y + vShift];
- let rcontainer = document.getElementById("reserves_" + c);
- rcontainer.style.left = i0 + "px";
- rcontainer.style.top = j0 + "px";
- rcontainer.style.width = (nbR * sqResSize + 1) + "px";
- rcontainer.style.height = sqResSize + "px";
- // And then reserve cells:
- const rpieceWidth = this.getReserveSquareSize(r.width, nbR);
- Object.keys(this.reserve[c]).forEach(p => {
- if (this.reserve[c][p] == 0)
- return;
- let r_cell = document.getElementById(this.coordsToId({x: c, y: p}));
- r_cell.style.width = sqResSize + "px";
- r_cell.style.height = sqResSize + "px";
- });
- }
- }
-
- // Return the absolute pixel coordinates given current position.
- // Our coordinate system differs from CSS one (x <--> y).
- // We return here the CSS coordinates (more useful).
- getPixelPosition(i, j, r) {
- if (i < 0 || j < 0)
- return [0, 0]; //piece vanishes
- let x, y;
- if (typeof i == "string") {
- // Reserves: need to know the rank of piece
- const nbR = this.getNbReservePieces(i);
- const rsqSize = this.getReserveSquareSize(r.width, nbR);
- x = this.getRankInReserve(i, j) * rsqSize;
- y = (this.playerColor == i ? y = r.height + 5 : - 5 - rsqSize);
- }
- else {
- const sqSize = r.width / Math.max(this.size.x, this.size.y);
- const flipped = this.flippedBoard;
- x = (flipped ? this.size.y - 1 - j : j) * sqSize +
- Math.abs(this.size.x - this.size.y) * sqSize / 2;
- y = (flipped ? this.size.x - 1 - i : i) * sqSize;
- }
- return [r.x + x, r.y + y];
- }
-
- initMouseEvents() {
- let container = document.getElementById(this.containerId);
- let chessboard = container.querySelector(".chessboard");
-
- const getOffset = e => {
- if (e.clientX)
- // Mouse
- return {x: e.clientX, y: e.clientY};
- let touchLocation = null;
- if (e.targetTouches && e.targetTouches.length >= 1)
- // Touch screen, dragstart
- touchLocation = e.targetTouches[0];
- else if (e.changedTouches && e.changedTouches.length >= 1)
- // Touch screen, dragend
- touchLocation = e.changedTouches[0];
- if (touchLocation)
- return {x: touchLocation.clientX, y: touchLocation.clientY};
- return {x: 0, y: 0}; //shouldn't reach here =)
- }
-
- const centerOnCursor = (piece, e) => {
- const centerShift = this.getPieceWidth(r.width) / 2;
- const offset = getOffset(e);
- piece.style.left = (offset.x - centerShift) + "px";
- piece.style.top = (offset.y - centerShift) + "px";
- }
-
- let start = null,
- r = null,
- startPiece, curPiece = null,
- pieceWidth;
- const mousedown = (e) => {
- // Disable zoom on smartphones:
- if (e.touches && e.touches.length > 1)
- e.preventDefault();
- r = chessboard.getBoundingClientRect();
- pieceWidth = this.getPieceWidth(r.width);
- const cd = this.idToCoords(e.target.id);
- if (cd) {
- const move = this.doClick(cd);
- if (move)
- this.buildMoveStack(move, r);
- else if (!this.clickOnly) {
- const [x, y] = Object.values(cd);
- if (typeof x != "number")
- startPiece = this.r_pieces[x][y];
- else
- startPiece = this.g_pieces[x][y];
- if (startPiece && this.canIplay(x, y)) {
- e.preventDefault();
- start = cd;
- curPiece = startPiece.cloneNode();
- curPiece.style.transform = "none";
- curPiece.style.zIndex = 5;
- curPiece.style.width = pieceWidth + "px";
- curPiece.style.height = pieceWidth + "px";
- centerOnCursor(curPiece, e);
- container.appendChild(curPiece);
- startPiece.style.opacity = "0.4";
- chessboard.style.cursor = "none";
- }
- }
- }
- };
-
- const mousemove = (e) => {
- if (start) {
- e.preventDefault();
- centerOnCursor(curPiece, e);
- }
- else if (e.changedTouches && e.changedTouches.length >= 1)
- // Attempt to prevent horizontal swipe...
- e.preventDefault();
- };
-
- const mouseup = (e) => {
- if (!start)
- return;
- const [x, y] = [start.x, start.y];
- start = null;
- e.preventDefault();
- chessboard.style.cursor = "pointer";
- startPiece.style.opacity = "1";
- const offset = getOffset(e);
- const landingElt = document.elementFromPoint(offset.x, offset.y);
- const cd =
- (landingElt ? this.idToCoords(landingElt.id) : undefined);
- if (cd) {
- // NOTE: clearly suboptimal, but much easier, and not a big deal.
- const potentialMoves = this.getPotentialMovesFrom([x, y])
- .filter(m => m.end.x == cd.x && m.end.y == cd.y);
- const moves = this.filterValid(potentialMoves);
- if (moves.length >= 2)
- this.showChoices(moves, r);
- else if (moves.length == 1)
- this.buildMoveStack(moves[0], r);
- }
- curPiece.remove();
- };
-
- const resize = (e) => this.rescale(e.deltaY < 0 ? "up" : "down");
-
- if ('onmousedown' in window) {
- this.mouseListeners = [
- {type: "mousedown", listener: mousedown},
- {type: "mousemove", listener: mousemove},
- {type: "mouseup", listener: mouseup},
- {type: "wheel", listener: resize}
- ];
- this.mouseListeners.forEach(ml => {
- document.addEventListener(ml.type, ml.listener);
- });
- }
- if ('ontouchstart' in window) {
- this.touchListeners = [
- {type: "touchstart", listener: mousedown},
- {type: "touchmove", listener: mousemove},
- {type: "touchend", listener: mouseup}
- ];
- this.touchListeners.forEach(tl => {
- // https://stackoverflow.com/a/42509310/12660887
- document.addEventListener(tl.type, tl.listener, {passive: false});
- });
- }
- // TODO: onpointerdown/move/up ? See reveal.js /controllers/touch.js
- }
-
- // NOTE: not called if isDiagram
- removeListeners() {
- let container = document.getElementById(this.containerId);
- this.windowResizeObs.unobserve(container);
- if ('onmousedown' in window) {
- this.mouseListeners.forEach(ml => {
- document.removeEventListener(ml.type, ml.listener);
- });
- }
- if ('ontouchstart' in window) {
- this.touchListeners.forEach(tl => {
- // https://stackoverflow.com/a/42509310/12660887
- document.removeEventListener(tl.type, tl.listener);
- });
- }
- }
-
- showChoices(moves, r) {
- let container = document.getElementById(this.containerId);
- let chessboard = container.querySelector(".chessboard");
- let choices = document.createElement("div");
- choices.id = "choices";
- if (!r)
- r = chessboard.getBoundingClientRect();
- choices.style.width = r.width + "px";
- choices.style.height = r.height + "px";
- choices.style.left = r.x + "px";
- choices.style.top = r.y + "px";
- chessboard.style.opacity = "0.5";
- container.appendChild(choices);
- const squareWidth = r.width / this.size.y;
- const firstUpLeft = (r.width - (moves.length * squareWidth)) / 2;
- const firstUpTop = (r.height - squareWidth) / 2;
- const color = moves[0].appear[0].c;
- const callback = (m) => {
- chessboard.style.opacity = "1";
- container.removeChild(choices);
- this.buildMoveStack(m, r);
- }
- for (let i=0; i < moves.length; i++) {
- let choice = document.createElement("div");
- choice.classList.add("choice");
- choice.style.width = squareWidth + "px";
- choice.style.height = squareWidth + "px";
- choice.style.left = (firstUpLeft + i * squareWidth) + "px";
- choice.style.top = firstUpTop + "px";
- choice.style.backgroundColor = "lightyellow";
- choice.onclick = () => callback(moves[i]);
- const piece = document.createElement("piece");
- const cdisp = moves[i].choice || moves[i].appear[0].p;
- C.AddClass_es(piece,
- this.pieces(color, moves[i].end.x, moves[i].end.y)[cdisp]["class"]);
- piece.classList.add(V.GetColorClass(color));
- piece.style.width = "100%";
- piece.style.height = "100%";
- choice.appendChild(piece);
- choices.appendChild(choice);
- }
- }
-
- 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
-
- updateEnlightened() {
- this.oldEnlightened = this.enlightened;
- this.enlightened = ArrayFun.init(this.size.x, this.size.y, false);
- // Add pieces positions + all squares reachable by moves (includes Zen):
- for (let x=0; x<this.size.x; x++) {
- for (let y=0; y<this.size.y; y++) {
- if (this.board[x][y] != "" && this.getColor(x, y) == this.playerColor)
- {
- this.enlightened[x][y] = true;
- this.getPotentialMovesFrom([x, y]).forEach(m => {
- this.enlightened[m.end.x][m.end.y] = true;
- });
- }
- }
- }
- if (this.epSquare)
- this.enlightEnpassant();
- }
-
- // Include square of the en-passant capturing square:
- enlightEnpassant() {
- // NOTE: shortcut, pawn has only one attack type, doesn't depend on square
- // TODO: (0, 0) is wrong, would need to place an attacker here...
- const steps = this.pieces(this.playerColor, 0, 0)["p"].attack[0].steps;
- for (let step of steps) {
- const x = this.epSquare.x - step[0], //NOTE: epSquare.x not on edge
- y = this.getY(this.epSquare.y - step[1]);
- if (
- this.onBoard(x, y) &&
- this.getColor(x, y) == this.playerColor &&
- this.getPieceType(x, y) == "p"
- ) {
- this.enlightened[x][this.epSquare.y] = true;
- break;
- }
- }
- }
-
- // Apply diff this.enlightened --> oldEnlightened on board
- graphUpdateEnlightened() {
- let chessboard =
- document.getElementById(this.containerId).querySelector(".chessboard");
- const r = chessboard.getBoundingClientRect();
- const pieceWidth = this.getPieceWidth(r.width);
- for (let x=0; x<this.size.x; x++) {
- for (let y=0; y<this.size.y; y++) {
- if (!this.enlightened[x][y] && this.oldEnlightened[x][y]) {
- let elt = document.getElementById(this.coordsToId({x: x, y: y}));
- elt.classList.add("in-shadow");
- if (this.g_pieces[x][y])
- this.g_pieces[x][y].classList.add("hidden");
- }
- else if (this.enlightened[x][y] && !this.oldEnlightened[x][y]) {
- let elt = document.getElementById(this.coordsToId({x: x, y: y}));
- elt.classList.remove("in-shadow");
- if (this.g_pieces[x][y])
- this.g_pieces[x][y].classList.remove("hidden");
- }
- }
- }
- }
-
- //////////////
- // BASIC UTILS
-
- get size() {
- return {
- x: 8,
- y: 8,
- ratio: 1 //for rectangular board = y / x (optional, 1 = default)
- };
- }
-
- // Color of thing on square (i,j). '' if square is empty
- getColor(i, j) {
- if (typeof i == "string")
- return i; //reserves : 'wb'
- return this.board[i][j].charAt(0);
- }
-
- static GetColorClass(c) {
- if (c == 'w')
- return "white";
- if (c == 'b')
- return "black";
- return "other-color"; //unidentified color
- }
-
- // Piece on i,j. '' if square is empty
- getPiece(i, j) {
- if (typeof j == "string")
- return j; //reserves : 'bq'
- return this.board[i][j].charAt(1);
- }
-
- // Piece type on square (i,j)
- getPieceType(x, y, p) {
- if (!p)
- p = this.getPiece(x, y);
- return this.pieces(this.getColor(x, y), x, y)[p].moveas || p;
- }
-
- isKing(x, y, p) {
- if (!p)
- p = this.getPiece(x, y);
- if (!this.options["cannibal"])
- return p == 'k';
- return !!C.CannibalKings[p];
- }
-
- static GetOppTurn(color) {
- return (color == 'w' ? 'b' : 'w');
- }
-
- // Get opponent color(s): may differ from turn (e.g. Checkered)
- getOppCols(color) {
- return [ (color == "w" ? "b" : "w") ];
- }
-
- // Is (x,y) on the chessboard?
- onBoard(x, y) {
- return (x >= 0 && x < this.size.x &&
- y >= 0 && y < this.size.y);
- }
-
- // Am I allowed to move thing at square x,y ?
- canIplay(x, y) {
- return (this.playerColor == this.turn && this.getColor(x, y) == this.turn);
- }
-
- ////////////////////////
- // PIECES SPECIFICATIONS
-
- getPawnShift(color) {
- return (color == "w" ? -1 : 1);
- }
- isPawnInitRank(x, color) {
- return (color == 'w' && x >= 6) || (color == 'b' && x <= 1);