-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";
(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
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);
let moves = [];
for (let i=0; i<this.size.x; i++) {
for (let j=0; j<this.size.y; j++) {
- if (this.canDrop([c, p], [i, j])) {
+ if (this.onBoard(i, j) && this.canDrop([c, p], [i, j])) {
let mv = new Move({
start: {x: c, y: p},
end: {x: i, y: j},
--- /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
+
+preamble = """<?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="crimson" stroke="darkslategray"/>'
+white = '<circle cx="115" cy="115" r="100" fill="gold" stroke="darkslategray"/>'
+
+digits = [
+ # 1 (unused here)
+ '<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"'
+]
+
+final = "</svg>"
+
+for color in ["white", "black"]:
+ for number in range(5):
+ filename = color + "_stack" + (str(number + 1) if number >= 1 else "") + ".svg"
+ f = open(filename, "w")
+ f.write(preamble)
+ 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="black"/>')
+ f.write("\n")
+ f.write(final)
+ f.close()
--- /dev/null
+import ChessRules from "/base_rules.js";
+import {Random} from "/utils/alea.js";
+import PiPo from "/utils/PiPo.js";
+import Move from "/utils/Move.js";
+
+export default class AvalamRules extends ChessRules {
+
+ static get Options() {
+ return {
+ select: [{
+ label: "Randomness",
+ variable: "randomness",
+ defaut: 1,
+ options: [
+ {label: "Deterministic", value: 0},
+ {label: "Random", value: 1},
+ ]
+ }],
+ input: [
+ {
+ label: "Free placement",
+ variable: "freefill",
+ type: "checkbox",
+ defaut: false
+ }
+ ]
+ };
+ }
+
+ get hasFlags() {
+ return false;
+ }
+ get hasEnpassant() {
+ return false;
+ }
+
+ pieces(color, x, y) {
+ const steps = [
+ [1, 0], [0, 1], [-1, 0], [0, -1],
+ [1, 1], [1, -1], [-1, 1], [-1, -1]
+ ];
+ return {
+ 'b': {
+ "class": "stack",
+ moves: [{steps: steps, range: 1}]
+ },
+ 'c': {
+ "class": "stack2",
+ moveas: 'b'
+ },
+ 'd': {
+ "class": "stack3",
+ moveas: 'b'
+ },
+ 'e': {
+ "class": "stack4",
+ moveas: 'b'
+ },
+ 'f': {
+ "class": "stack5",
+ moveas: 'b'
+ }
+ };
+ }
+
+ genRandInitBaseFen() {
+ let fen = "";
+ if (this.freefill)
+ fen = "9/".repeat(8) + "9 w 0";
+ else if (this.options["randomness"] == 0) {
+ fen = "2Bb5/1BbBb4/1bBbBbB2/1BbBbBbBb/BbBb1bBbB/" +
+ "bBbBbBbB1/2BbBbBb1/4bBbB1/5bB2 w 0";
+ }
+ else {
+ const pieces = ('B'.repeat(24) + 'b'.repeat(24)).split("");
+ const a = Random.shuffle(pieces, 48).join("");
+ fen = (
+ "2" + a.substr(0, 2) + "5/1" + a.substr(2, 4) +
+ "4/1" + a.substr(6, 6) + "2/1" + a.substr(12, 8) +
+ "/" + a.substr(20, 4) + "1" + a.substr(24, 4) +
+ "/" + a.substr(28, 8) + "1/2" + a.substr(36, 6) +
+ "1/4" + a.substr(42, 4) + "1/5" + a.substr(46, 2) +
+ "2 w 0"
+ );
+ }
+ return { fen: fen, o: {} };
+ }
+
+ getSquareColorClass(x, y) {
+ return "board-sq";
+ }
+
+ get size() {
+ return {x: 9, y: 9};
+ }
+
+ onBoard(x, y) {
+ if (!super.onBoard(x, y))
+ return false;
+ switch (x) {
+ case 0:
+ return [2, 3].includes(y);
+ case 1:
+ return [1, 2, 3, 4].includes(y);
+ case 2:
+ return [1, 2, 3, 4, 5, 6].includes(y);
+ case 3:
+ return y >= 1;
+ case 4:
+ return y != 4;
+ case 5:
+ return y <= 7;
+ case 6:
+ return [2, 3, 4, 5, 6, 7].includes(y);
+ case 7:
+ return [4, 5, 6, 7].includes(y);
+ case 8:
+ return [5, 6].includes(y);
+ }
+ return false; //never reached
+ }
+
+ canIplay() {
+ return this.playerColor == this.turn;
+ }
+
+ doClick(coords) {
+ if (!this.freefill || this.board[coords.x][coords.y] != "")
+ return null;
+ return new Move({
+ start: {x: coords.x, y: coords.y},
+ vanish: [],
+ appear: [new PiPo({x: coords.x, y: coords.y, c: this.turn, p: 'b'})]
+ });
+ }
+
+ getBasicMove([x1, y1], [x2, y2]) {
+ const cp1 = this.board[x1][y1],
+ cp2 = this.board[x2][y2];
+ const newPiece =
+ String.fromCharCode(cp1.charCodeAt(1) + cp2.charCodeAt(1) - 97);
+ return (
+ new Move({
+ vanish: [
+ new PiPo({ x: x1, y: y1, c: cp1.charAt(0), p: cp1.charAt(1) }),
+ new PiPo({ x: x2, y: y2, c: cp2.charAt(0), p: cp2.charAt(1) })
+ ],
+ appear: [
+ new PiPo({ x: x2, y: y2, c: cp1.charAt(0), p: newPiece })
+ ]
+ })
+ );
+ }
+
+ getPotentialMovesFrom([x, y]) {
+ const height = this.board[x][y].charCodeAt(1) - 97;
+ if (height == 5)
+ return [];
+ let moves = [];
+ for (let s of this.pieces()['b'].moves[0].steps) {
+ const [i, j] = [x + s[0], y + s[1]];
+ if (
+ this.onBoard(i, j) &&
+ this.board[i][j] != "" &&
+ (height + this.board[i][j].charCodeAt(1) - 97 <= 5)
+ ) {
+ moves.push(this.getBasicMove([x, y], [i, j]));
+ }
+ }
+ return moves;
+ }
+
+ filterValid(moves) {
+ return moves;
+ }
+
+ getCurrentScore() {
+ let towersCount = {w: 0, b: 0};
+ for (let i = 0; i < this.size.x; i++) {
+ for (let j = 0; j < this.size.y; j++) {
+ if (this.board[i][j] != "") {
+ if (this.getPotentialMovesFrom([i, j]).length > 0)
+ return '*';
+ towersCount[ this.board[i][j][0] ]++;
+ }
+ }
+ }
+ if (towersCount['w'] > towersCount['b'])
+ return "1-0";
+ if (towersCount['b'] > towersCount['w'])
+ return "0-1";
+ return "1/2";
+ }
+
+};