# xogo.casa
-Simplified version of old vchess.club, to focus on the essential : the game.
+Simplified version of old vchess.club, to focus on the essential.
## Requirements (dev)
-PHP + Python + Node.js + npm.
+PHP + Node.js + npm.
+
```npm i -g nodemon```
## Usage
-Initialisation (done once): retrieve 'binaries'
-(files binary or not which never change).
+Initialisation (done only once):
```./initialize.sh```
-Rename and edit the parameters.js.dist file:
+Edit the parameters.js file:
-```cp js/parameters.js.dist js/parameters.js```
+```vim js/parameters.js```
Finally:
-Otage, Emergo, Pacosako : fonction "buildPiece(arg1, arg2)" returns HTML element with 2 SVG or SVG + number
-==> plus simple : deux classes, images superposées (?)
-
https://fr.wikipedia.org/wiki/Unlur
DuckChess + crazyduck --> move it at random ? Capturing ? Hmm.
cp js/parameters.js.dist js/parameters.js
npm i
cd pieces/Avalam && python generateSVG.py && cd ../..
-cd pieces/Emergo && python generateSVG.py && cd ../..
(oldV,newV) => oldV + (this.reserve[c][newV] > 0 ? 1 : 0), 0);
}
+ // Placeholder for variants building SVG pieces "on demand"
+ setPieceBackground(domPiece, piece, color, x, y) {}
+
static AddClass_es(elt, class_es) {
if (!Array.isArray(class_es))
class_es = [class_es];
if (!r)
r = chessboard.getBoundingClientRect();
const pieceWidth = this.getPieceWidth(r.width);
- const addPiece = (i, j, arrName, classes) => {
+ const addPiece = (i, j, arrName, classes, piece, color) => {
this[arrName][i][j] = document.createElement("piece");
C.AddClass_es(this[arrName][i][j], classes);
+ if (!!piece)
+ this.setPieceBackground(this[arrName][i][j], piece, color, i, j);
this[arrName][i][j].style.width = pieceWidth + "px";
this[arrName][i][j].style.height = pieceWidth + "px";
let [ip, jp] = this.getPixelPosition(i, j, r);
}
else
this[arrName] = ArrayFun.init(this.size.x, this.size.y, null);
- if (arrName == "d_pieces")
+ 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");
const color = this.getColor(i, j);
const piece = this.getPiece(i, j);
addPiece(i, j, "g_pieces",
- this.pieceDef(piece, color, i, j)["class"]);
+ this.pieceDef(piece, color, i, j)["class"], piece, color);
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");
rcontainer.appendChild(r_cell);
let piece = document.createElement("piece");
C.AddClass_es(piece, this.pieceDef(p, c, c, p)["class"]);
+ this.setPieceBackground(piece, p, c, c, p);
piece.classList.add(V.GetColorClass(c));
piece.style.width = "100%";
piece.style.height = "100%";
const cdisp = moves[i].choice || moves[i].appear[0].p;
C.AddClass_es(piece,
this.pieceDef(cdisp, color, moves[i].end.x, moves[i].end.y)["class"]);
+ this.setPieceBackground(piece,
+ cdisp, color, moves[i].end.x, moves[i].end.y);
piece.classList.add(V.GetColorClass(color));
piece.style.width = "100%";
piece.style.height = "100%";
this.g_pieces[a.x][a.y] = document.createElement("piece");
C.AddClass_es(this.g_pieces[a.x][a.y],
this.pieceDef(a.p, a.c, a.x, a.y)["class"]);
+ this.setPieceBackground(this.g_pieces[a.x][a.y], a.p, a.c, a.x, a.y);
this.g_pieces[a.x][a.y].classList.add(V.GetColorClass(a.c));
this.g_pieces[a.x][a.y].style.width = pieceWidth + "px";
this.g_pieces[a.x][a.y].style.height = pieceWidth + "px";
this.pieceDef(startCode, apparentColor, start.x, start.y)["class"]);
C.AddClass_es(movingPiece,
this.pieceDef(drag.p, apparentColor, start.x, start.y)["class"]);
+ this.setPieceBackground(movingPiece,
+ drag.p, apparentColor, start.x, start.y);
if (apparentColor != drag.c) {
movingPiece.classList.remove(V.GetColorClass(apparentColor));
movingPiece.classList.add(V.GetColorClass(drag.c));
+++ /dev/null
-#!/usr/bin/env python
-
-# Compose each piece SVG with numbers
-# https://travishorn.com/removing-parts-of-shapes-in-svg-b539a89e5649
-# https://developer.mozilla.org/fr/docs/Web/SVG/Tutoriel/Paths
-
-###############################
-# 1. Simple pieces (mono-color)
-###############################
-
-preamble_simple = """<?xml version="1.0" encoding="UTF-8" ?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
-<svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="230" height="230">"""
-
-black = '<circle cx="115" cy="115" r="100" fill="black"/>'
-white = '<circle cx="115" cy="115" r="100" fill="whitesmoke" stroke="saddlebrown"/>'
-
-digits = [
- # 1 (unused)
- '<path d="M130,85 v60"',
- # 2
- '<path d="M100,85 h30 v30 h-30 v30 h30"',
- # 3
- '<path d="M100,85 h30 v30 h-30 M130,115 v30 h-30"',
- # 4
- '<path d="M100,85 v30 h30 v30 M130,85 v30"',
- # 5
- '<path d="M130,85 h-30 v30 h30 v30 h-30"',
- # 6
- '<path d="M130,85 h-30 v60 h30 v-30 h-30"',
- # 7
- '<path d="M100,85 h30 v60"',
- # 8
- '<path d="M100,85 h30 v60 h-30 z M100,115 h30"',
- # 9
- '<path d="M100,135 h30 v-60 h-30 v30 h30"',
- # 10
- '<path d="M95,85 v60 M105,85 h30 v60 h-30 v-60"',
- # 11
- '<path d="M95,85 v60 M135,85 v60"',
- # 12
- '<path d="M95,85 v60 M105,85 h30 v30 h-30 v30 h30"'
-]
-
-final = "</svg>"
-
-for color in ["white", "black"]:
- chrShift = 0 if color == "white" else 32
- for number in range(12):
- filename = chr(65 + number + chrShift) + "@.svg"
- f = open(filename, "w")
- f.write(preamble_simple)
- f.write("\n")
- f.write(white if color == "white" else black)
- f.write("\n")
- if number >= 1:
- f.write(digits[number] + ' fill="none" stroke-width="5" ' + ('stroke="red"' if color == "white" else 'stroke="orange"') + '/>')
- f.write("\n")
- f.write(final)
- f.close()
-
-################################
-# 1. Composite pieces (bi-color)
-################################
-
-preamble_composite = """<?xml version="1.0" encoding="UTF-8" ?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
-<svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="230" height="230">
-<defs>
- <mask id="stripe">
- <rect x="0" y="0" width="230" height="230" fill="white"/>
- <rect x="0" y="115" width="230" height="115"/>
- </mask>
-</defs>"""
-
-black_top = '<circle cx="115" cy="115" r="100" fill="black" mask="url(#stripe)"/>'
-white_bottom = '<circle cx="115" cy="115" r="100" fill="whitesmoke" stroke="saddlebrown"/>'
-white_top = '<circle cx="115" cy="115" r="100" fill="whitesmoke" stroke="saddlebrown" mask="url(#stripe)"/>'
-black_bottom = '<circle cx="115" cy="115" r="100" fill="black"/>'
-
-digits = {
- "top": [
- # 1 (unused here)
- '<path d="M130,35 v60"',
- # 2
- '<path d="M100,35 h30 v30 h-30 v30 h30"',
- # 3
- '<path d="M100,35 h30 v30 h-30 M130,65 v30 h-30"',
- # 4
- '<path d="M100,35 v30 h30 v30 M130,35 v30"',
- # 5
- '<path d="M130,35 h-30 v30 h30 v30 h-30"',
- # 6
- '<path d="M130,35 h-30 v60 h30 v-30 h-30"',
- # 7
- '<path d="M100,35 h30 v60"',
- # 8
- '<path d="M100,35 h30 v60 h-30 z M100,65 h30"',
- # 9
- '<path d="M100,95 h30 v-60 h-30 v30 h30"',
- # 10
- '<path d="M90,35 v60 M100,35 h30 v60 h-30 v-60"',
- # 11
- '<path d="M90,35 v60 M130,35 v60"',
- # 12
- '<path d="M90,35 v60 M100,35 h30 v30 h-30 v30 h30"'
- ],
- "bottom": [
- # 1 (unused here)
- '<path d="M130,135 v60"',
- # 2
- '<path d="M100,135 h30 v30 h-30 v30 h30"',
- # 3
- '<path d="M100,135 h30 v30 h-30 M130,165 v30 h-30"',
- # 4
- '<path d="M100,135 v30 h30 v30 M130,135 v30"',
- # 5
- '<path d="M130,135 h-30 v30 h30 v30 h-30"',
- # 6
- '<path d="M130,135 h-30 v60 h30 v-30 h-30"',
- # 7
- '<path d="M100,135 h30 v60"',
- # 8
- '<path d="M100,135 h30 v60 h-30 z M100,165 h30"',
- # 9
- '<path d="M100,195 h30 v-60 h-30 v30 h30"',
- # 10
- '<path d="M90,135 v60 M100,135 h30 v60 h-30 v-60"',
- # 11
- '<path d="M90,135 v60 M130,135 v60"',
- # 12
- '<path d="M90,135 v60 M100,135 h30 v30 h-30 v30 h30"'
- ]
-}
-
-final = "</svg>"
-
-for colorTop in ["white", "black"]:
- chrShift = 0 if colorTop == "white" else 32
- for top in range(12):
- for bottom in range(12):
- filename = chr(65 + top + chrShift) + chr(65 + bottom + chrShift) + ".svg"
- f = open(filename, "w")
- f.write(preamble_composite)
- f.write("\n")
- f.write(black_bottom if colorTop == "white" else white_bottom)
- f.write("\n")
- f.write(white_top if colorTop == "white" else black_top)
- f.write("\n")
- if top >= 1:
- f.write(digits["top"][top] + ' fill="none" stroke-width="5" ' + ('stroke="red"' if colorTop == "white" else 'stroke="orange"') + '/>')
- f.write("\n")
- if bottom >= 1:
- f.write(digits["bottom"][bottom] + ' fill="none" stroke-width="5" ' + ('stroke="red"' if colorTop == "black" else 'stroke="orange"') + '/>')
- f.write("\n")
- f.write(final)
- f.close()
return board;
}
- getColor(x, y) {
- const sq = (typeof x == "string" ? x : this.board[x][y]);
- return sq.charCodeAt(0) < 97 ? 'w' : 'b';
- }
-
- pieceDef(piece, color, x, y) {
- const color = this.getColor(piece);
- piece.charAt(0)
- //this.board[x][y]
- // --> TODO
- // Moving always the same, but look differs
- // class: classUp, class: classDOwn + composition
- }
-
- getPiece(x, y) {
- // Both characters required to describe the (aggregated) "piece"
- return this.board[x][y];
+ getSquareColorClass(x, y) {
+ return ((x+y) % 2 == 0 ? "dark-square": "light-square");
}
get size() {
super.setOtherVariables(fenParsed);
// Last capture during a turn (square + direction)
this.lastCapture = null;
+ // Compute pieces drawings when required, and cache it:
+ this.svgEncodedPieces = {};
+ }
+
+ getColor(x, y) {
+ const sq = (typeof x == "string" ? x : this.board[x][y]);
+ return sq.charCodeAt(0) < 97 ? 'w' : 'b';
+ }
+
+ getPiece(x, y) {
+ // Both characters required to describe the (aggregated) "piece"
+ return this.board[x][y];
+ }
+
+ pieceDef(piece, color, x, y) {
+ // Captures handled in getPotentialMoves directly
+ return {
+ moves: [{ steps: [ [-1, -1], [-1, 1], [1, -1], [1, 1] ] }],
+ "class": "emergo-piece",
+ };
+ }
+
+ static GetSvgNumber(n, position) {
+ switch (position) {
+ case "full": {
+ switch (n) {
+ case 1: //unused
+ return '<path d="M130,85 v60"';
+ case 2:
+ return '<path d="M100,85 h30 v30 h-30 v30 h30"';
+ case 3:
+ return '<path d="M100,85 h30 v30 h-30 M130,115 v30 h-30"';
+ case 4:
+ return '<path d="M100,85 v30 h30 v30 M130,85 v30"';
+ case 5:
+ return '<path d="M130,85 h-30 v30 h30 v30 h-30"';
+ case 6:
+ return '<path d="M130,85 h-30 v60 h30 v-30 h-30"';
+ case 7:
+ return '<path d="M100,85 h30 v60"';
+ case 8:
+ return '<path d="M100,85 h30 v60 h-30 z M100,115 h30"';
+ case 9:
+ return '<path d="M100,135 h30 v-60 h-30 v30 h30"';
+ case 10:
+ return '<path d="M95,85 v60 M105,85 h30 v60 h-30 v-60"';
+ case 11:
+ return '<path d="M95,85 v60 M135,85 v60"';
+ case 12:
+ return '<path d="M95,85 v60 M105,85 h30 v30 h-30 v30 h30"';
+ }
+ }
+ case "top": {
+ switch (n) {
+ case 1: //unused here
+ return '<path d="M130,35 v60"';
+ case 2:
+ return '<path d="M100,35 h30 v30 h-30 v30 h30"';
+ case 3:
+ return '<path d="M100,35 h30 v30 h-30 M130,65 v30 h-30"';
+ case 4:
+ return '<path d="M100,35 v30 h30 v30 M130,35 v30"';
+ case 5:
+ return '<path d="M130,35 h-30 v30 h30 v30 h-30"';
+ case 6:
+ return '<path d="M130,35 h-30 v60 h30 v-30 h-30"';
+ case 7:
+ return '<path d="M100,35 h30 v60"';
+ case 8:
+ return '<path d="M100,35 h30 v60 h-30 z M100,65 h30"';
+ case 9:
+ return '<path d="M100,95 h30 v-60 h-30 v30 h30"';
+ case 10:
+ return '<path d="M90,35 v60 M100,35 h30 v60 h-30 v-60"';
+ case 11:
+ return '<path d="M90,35 v60 M130,35 v60"';
+ case 12:
+ return '<path d="M90,35 v60 M100,35 h30 v30 h-30 v30 h30"';
+ }
+ }
+ case "bottom": {
+ switch (n) {
+ case 1: //unused here
+ return '<path d="M130,135 v60"';
+ case 2:
+ return '<path d="M100,135 h30 v30 h-30 v30 h30"';
+ case 3:
+ return '<path d="M100,135 h30 v30 h-30 M130,165 v30 h-30"';
+ case 4:
+ return '<path d="M100,135 v30 h30 v30 M130,135 v30"';
+ case 5:
+ return '<path d="M130,135 h-30 v30 h30 v30 h-30"';
+ case 6:
+ return '<path d="M130,135 h-30 v60 h30 v-30 h-30"';
+ case 7:
+ return '<path d="M100,135 h30 v60"';
+ case 8:
+ return '<path d="M100,135 h30 v60 h-30 z M100,165 h30"';
+ case 9:
+ return '<path d="M100,195 h30 v-60 h-30 v30 h30"';
+ case 10:
+ return '<path d="M90,135 v60 M100,135 h30 v60 h-30 v-60"';
+ case 11:
+ return '<path d="M90,135 v60 M130,135 v60"';
+ case 12:
+ return '<path d="M90,135 v60 M100,135 h30 v30 h-30 v30 h30"';
+ }
+ }
+ return ""; //never reached
+ }
+
+ // Compute piece drawing
+ getSvgEncodedPiece(piece, color) {
+ if (this.svgPieces[piece])
+ return this.svgPieces[piece];
+
+ let rawSvg = `
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 230 230"
+ width="100%" height="100%">`;
+ if (piece.charAt(1) == '@') {
+ const number = ...
+ rawSvg += `
+ <circle cx="115" cy="115" r="100"
+ fill="${color=='w' ? 'whitesmoke' : 'black'}"
+ ${color=='w' ? 'stroke="saddlebrown"' : ''}
+ />`;
+ if (number > 1) {
+ rawSvg += V.GetSvgNumber(number, "full") + `
+ fill="none" stroke-width="5"
+ stroke="${color=='w' ? 'red' : 'orange'}"
+ />`;
+ }
+ }
+ else { //composite
+ const numTop = ...,
+ numBottom = ...;
+ const isTopWhite =
+ rawSvg += `<defs>
+ <mask id="stripe">
+ <rect width="230" height="230" fill="white"/>
+ <rect y="115" width="230" height="115"/>
+ </mask>
+ </defs>
+ <circle cx="115" cy="115" r="100"
+ fill="${color=='b' ? 'whitesmoke' : 'black'}"
+ ${color=='b' ? 'stroke="saddlebrown"' : ''}
+ />
+ <circle cx="115" cy="115" r="100"
+ fill="${color=='w' ? 'whitesmoke' : 'black'}"
+ ${color=='w' ? 'stroke="saddlebrown"' : ''} mask="url(#stripe)"
+ />`;
+ if (numTop > 1) {
+ rawSvg += V.GetSvgNumber(numTop, "top") + `
+ fill="none" stroke-width="5"
+ stroke="${color=='w' ? 'red' : 'orange'}"
+ />`
+ }
+ if (numBottom > 1) {
+ rawSvg += V.GetSvgNumber(numBottom, "bottom") + `
+ fill="none" stroke-width="5"
+ stroke="${color=='b' ? 'red' : 'orange'}"
+ />`;
+ }
+ }
+ rawSvg += "</svg>";
+
+ // On encode le SVG pour qu'il soit lisible dans un "url()" CSS
+ const svgBase64 = btoa(unescape(encodeURIComponent(rawSvg)));
+ this.svgEncodedPieces[piece] = svgBase64;
+ return svgBase64;
+ }
+
+ // Draw piece
+ setPieceBackground(domPiece, piece, color, x, y) {
+ const svgBase64 = this.getSvgEncodedPiece(piece, color);
+ domPiece.style.backgroundImage =
+ `url('data:image/svg+xml;base64,${svgBase64}')`;
}
atLeastOneCaptureFrom([x, y], color, forbiddenStep) {
return mv;
}
- getSquareColorClass(x, y) {
- return ((x+y) % 2 == 0 ? "dark-square": "light-square");
- }
-
-
-
-
getDropMovesFrom([c, p]) {
const color = c;
if (!this.reserve[color] || this.atLeastOneCapture(color))
--- /dev/null
+<p>TODO</p>
-piece.white.stack {
- background-image: url('/pieces/Emergo/white_.svg');
-}
-
-
-
-
-piece.white.stack2 {
- background-image: url('/pieces/Avalam/white_stack2.svg');
-}
-piece.white.stack3 {
- background-image: url('/pieces/Avalam/white_stack3.svg');
-}
-piece.white.stack4 {
- background-image: url('/pieces/Avalam/white_stack4.svg');
-}
-piece.white.stack5 {
- background-image: url('/pieces/Avalam/white_stack5.svg');
-}
-
-piece.black.stack {
- background-image: url('/pieces/Avalam/black_stack.svg');
-}
-piece.black.stack2 {
- background-image: url('/pieces/Avalam/black_stack2.svg');
-}
-piece.black.stack3 {
- background-image: url('/pieces/Avalam/black_stack3.svg');
-}
-piece.black.stack4 {
- background-image: url('/pieces/Avalam/black_stack4.svg');
-}
-piece.black.stack5 {
- background-image: url('/pieces/Avalam/black_stack5.svg');
+.emergo-piece {
+ background-image: var(--piece-img);
+ /*background-size: contain;
+ background-repeat: no-repeat;*/
}