let options;
function prepareOptions() {
options = {};
- let optHtml = V.Options.select.map(select => { return `
+ let optHtml = "";
+ if (V.Options.select) {
+ optHtml += V.Options.select.map(select => { return `
<div class="option-select">
<label for="var_${select.variable}">${select.label}</label>
<div class="select">
<span class="focus"></span>
</div>
</div>`;
- }).join("");
- optHtml += V.Options.check.map(check => {
- return `
+ }).join("");
+ }
+ if (V.Options.check) {
+ optHtml += V.Options.check.map(check => { return `
<div class="option-check">
<label class="checkbox">
<input id="var_${check.variable}"
<span>${check.label}</span>
</label>
</div>`;
- }).join("");
- if (V.Options.styles.length >= 1) {
+ }).join("");
+ }
+ if (V.Options.input) {
+ optHtml += V.Options.input.map(input => { return `
+ <div class="option-input">
+ <label class="input">
+ <input id="var_${input.variable}"
+ type="${input.type}"
+ content="${input.defaut}"/>
+ <span class="spacer"></span>
+ <span>${input.label}</span>
+ </label>
+ </div>`;
+ }).join("");
+ }
+ if (V.Options.styles) {
optHtml += '<div class="words">';
let i = 0;
const stylesLength = V.Options.styles.length;
return fen;
}
+ static FenEmptySquares(count) {
+ // if more than 9 consecutive free spaces, break the integer,
+ // otherwise FEN parsing will fail.
+ if (count <= 9)
+ return count;
+ // Most boards of size < 18:
+ if (count <= 18)
+ return "9" + (count - 9);
+ // Except Gomoku:
+ return "99" + (count - 18);
+ }
+
// Position part of the FEN string
getPosition() {
- const format = (count) => {
- // if more than 9 consecutive free spaces, break the integer,
- // otherwise FEN parsing will fail.
- if (count <= 9)
- return count;
- // Most boards of size < 18:
- if (count <= 18)
- return "9" + (count - 9);
- // Except Gomoku:
- return "99" + (count - 18);
- };
let position = "";
for (let i = 0; i < this.size.y; i++) {
let emptyCount = 0;
else {
if (emptyCount > 0) {
// Add empty squares in-between
- position += format(emptyCount);
+ position += C.FenEmptySquares(emptyCount);
emptyCount = 0;
}
position += this.board2fen(this.board[i][j]);
}
if (emptyCount > 0)
// "Flush remainder"
- position += format(emptyCount);
+ position += C.FenEmptySquares(emptyCount);
if (i < this.size.y - 1)
position += "/"; //separate rows
}
chessboard.style.top = newY + "px";
const newR = {x: newX, y: newY, width: newWidth, height: newHeight};
const pieceWidth = this.getPieceWidth(newWidth);
- 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)`;
+ // 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)`;
+ }
}
}
}
height: 100%;
}
+/* Default squares colors (can be overriden or unused) */
.dark-square {
fill: #b58863;
}
.light-square {
fill: #f0d9b5;
}
+
.in-shadow {
filter: brightness(50%);
}
+// https://www.boardspace.net/hex/english/Rules%20-%20HexWiki.htm
+export default class HexRules extends ChessRules {
+
+ static get Options() {
+ return {
+ input: [
+ {
+ label: "Board size",
+ type: "number",
+ defaut: 11,
+ variable: "bsize"
+ }
+ ],
+ check: [
+ {
+ label: "Swap",
+ defaut: true,
+ variable: "swap"
+ }
+ ]
+ };
+ }
+
+ get hasReserve() {
+ return false;
+ }
+
+ get noAnimate() {
+ return true;
+ }
+
+ doClick(coords) {
+ if (
+ this.board[coords.x][coords.y] != "" &&
+ (!this.swap || this.movesCount >= 2)
+ ) {
+ return null;
+ }
+ let res = new Move({
+ start: {x: coords.x, y: coords.y},
+ appear: [
+ new PiPo({
+ x: coords.x,
+ y: coords.y,
+ c: this.turn,
+ p: 'p'
+ })
+ ],
+ vanish: []
+ });
+ if (this.board[coords.x][coords.y] != "") {
+ res.vanish.push(
+ new PiPo({
+ x: coords.x,
+ y: coords.y,
+ c: C.GetOppCol(this.turn),
+ p: 'p'
+ })
+ );
+ }
+ return res;
+ }
+
+ genRandInitFen() {
+ // NOTE: size.x == size.y (square boards)
+ const emptyCount = C.FenEmptySquares(this.size.x.repeat);
+ return (emptyCount + "/").repeat(this.size.x).slice(0, -1);
+ }
+
+ getPieceWidth(rwidth) {
+ return (rwidth / this.size.y); //TODO
+ }
+
+ // TODO
getSvgChessboard() {
- const flipped = (this.playerColor == 'b');
let board = `
<svg
width="2771.2px" height="1700px"
for (let j=0; j < this.size.y; j++) {
let classes = this.getSquareColorClass(i, j);
board += `<rect
- class="${classes}"
+ class="neutral-square"
id="${this.coordsToId([i, j])}"
width="10"
height="10"
return board;
}
-// neutral-light neutral-dark --> specify per variant in CSS file
- getSquareColorClass(i, j) {
- return ((i+j) % 2 == 0 ? "light-square": "dark-square");
+ setupPieces() {
+ // TODO: just scan board and get IDs, and addClass "bg-white" or "bg-black"
+ }
+
+ // TODO (NOTE: no flip here, always same view)
+ getPixelPosition(i, j, r) {
+ if (i < 0 || j < 0)
+ return [0, 0]; //piece vanishes
+ let x, y;
+ const sqSize = r.width / this.size.y;
+ const flipped = (this.playerColor == 'b');
+ const x = (flipped ? this.size.y - 1 - j : j) * sqSize,
+ y = (flipped ? this.size.x - 1 - i : i) * sqSize;
+ return [r.x + x, r.y + y];
+ }
+
+ initMouseEvents() {
+ const mousedown = (e) => {
+ if (e.touches && e.touches.length > 1)
+ e.preventDefault();
+ const cd = this.idToCoords(e.target.id);
+ if (cd) {
+ const move = this.doClick(cd);
+ if (move)
+ this.playPlusVisual(move);
+ }
+ };
+
+ if ('onmousedown' in window)
+ document.addEventListener("mousedown", mousedown);
+ if ('ontouchstart' in window)
+ document.addEventListener("touchstart", mousedown, {passive: false});
+ }
+
+ get size() {
+ return {
+ x: this.bsize,
+ y: this.bsize,
+ ratio: 1.630118
+ };
+ }
+
+ pieces() {
+ return {
+ 'p': {
+ "class": "pawn",
+ }
+ };
+ }
+
+ play(move) {
+ super.playOnBoard(move);
+ }
+
+ // TODO:
+ getCurrentScore(move) {
+ const oppCol = C.GetOppCol(this.turn);
+ // Search for connecting path of opp color: TODO
+ // ...
+ if (path found)
+ return (oppCol == "w" ? "1-0" : "0-1");
+ return "*";
+ }
+
+ playVisual(move) {
+ move.vanish.forEach(v => {
+// TODO: just get ID, and remClass "bg-white" or "bg-black" (in CSS: TODO)
+ });
+ move.appear.forEach(a => {
+// TODO: just get ID, and addClass "bg-white" or "bg-black" (in CSS: TODO)
+// this.g_pieces[a.x][a.y] = document.createElement("piece");
+// this.g_pieces[a.x][a.y].classList.add(this.pieces()[a.p]["class"]);
+// this.g_pieces[a.x][a.y].classList.add(a.c == "w" ? "white" : "black");
+// this.g_pieces[a.x][a.y].style.width = pieceWidth + "px";
+// this.g_pieces[a.x][a.y].style.height = pieceWidth + "px";
+ });
}
-// TODO: generalize base_rules.js to not assume size.x == width and size.y == height (not true here).
+};
--- /dev/null
+.neutral-square {
+ fill: #eaeded;
+}