From 90d128509cb2184cfc86bf13f9f6496704be237a Mon Sep 17 00:00:00 2001 From: Benjamin Auder Date: Wed, 27 Dec 2023 12:52:14 +0100 Subject: [PATCH 01/16] Almost finished Cwda --- pieces/Cwda/CREDITS | 1 + pieces/Cwda/c_black_bishop.svg | 153 +++++++++++++++++ pieces/Cwda/c_black_king.svg | 89 ++++++++++ pieces/Cwda/c_black_knight.svg | 248 ++++++++++++++++++++++++++++ pieces/Cwda/c_black_pawn.svg | 61 +++++++ pieces/Cwda/c_black_queen.svg | 198 ++++++++++++++++++++++ pieces/Cwda/c_black_rook.svg | 108 ++++++++++++ pieces/Cwda/c_white_bishop.svg | 153 +++++++++++++++++ pieces/Cwda/c_white_king.svg | 85 ++++++++++ pieces/Cwda/c_white_knight.svg | 265 ++++++++++++++++++++++++++++++ pieces/Cwda/c_white_pawn.svg | 82 +++++++++ pieces/Cwda/c_white_queen.svg | 129 +++++++++++++++ pieces/Cwda/c_white_rook.svg | 106 ++++++++++++ pieces/Cwda/n_black_bishop.svg | 97 +++++++++++ pieces/Cwda/n_black_king.svg | 89 ++++++++++ pieces/Cwda/n_black_knight.svg | 117 +++++++++++++ pieces/Cwda/n_black_pawn.svg | 61 +++++++ pieces/Cwda/n_black_queen.svg | 182 ++++++++++++++++++++ pieces/Cwda/n_black_rook.svg | 98 +++++++++++ pieces/Cwda/n_white_bishop.svg | 81 +++++++++ pieces/Cwda/n_white_king.svg | 85 ++++++++++ pieces/Cwda/n_white_knight.svg | 114 +++++++++++++ pieces/Cwda/n_white_pawn.svg | 82 +++++++++ pieces/Cwda/n_white_queen.svg | 153 +++++++++++++++++ pieces/Cwda/n_white_rook.svg | 97 +++++++++++ pieces/Cwda/r_black_bishop.svg | 86 ++++++++++ pieces/Cwda/r_black_king.svg | 89 ++++++++++ pieces/Cwda/r_black_knight.svg | 136 +++++++++++++++ pieces/Cwda/r_black_pawn.svg | 61 +++++++ pieces/Cwda/r_black_queen.svg | 153 +++++++++++++++++ pieces/Cwda/r_black_rook.svg | 89 ++++++++++ pieces/Cwda/r_white_bishop.svg | 79 +++++++++ pieces/Cwda/r_white_king.svg | 85 ++++++++++ pieces/Cwda/r_white_knight.svg | 109 ++++++++++++ pieces/Cwda/r_white_pawn.svg | 83 ++++++++++ pieces/Cwda/r_white_queen.svg | 148 +++++++++++++++++ pieces/Cwda/r_white_rook.svg | 123 ++++++++++++++ variants.js | 2 +- variants/Cwda/class.js | 237 +++++++++++--------------- variants/Cwda/complete_rules.html | 128 +++++++++++++++ variants/Cwda/rules.html | 12 ++ variants/Cwda/style.css | 112 +++++++++++++ 42 files changed, 4524 insertions(+), 142 deletions(-) create mode 100644 pieces/Cwda/CREDITS create mode 100644 pieces/Cwda/c_black_bishop.svg create mode 100644 pieces/Cwda/c_black_king.svg create mode 100644 pieces/Cwda/c_black_knight.svg create mode 100644 pieces/Cwda/c_black_pawn.svg create mode 100644 pieces/Cwda/c_black_queen.svg create mode 100644 pieces/Cwda/c_black_rook.svg create mode 100644 pieces/Cwda/c_white_bishop.svg create mode 100644 pieces/Cwda/c_white_king.svg create mode 100644 pieces/Cwda/c_white_knight.svg create mode 100644 pieces/Cwda/c_white_pawn.svg create mode 100644 pieces/Cwda/c_white_queen.svg create mode 100644 pieces/Cwda/c_white_rook.svg create mode 100644 pieces/Cwda/n_black_bishop.svg create mode 100644 pieces/Cwda/n_black_king.svg create mode 100644 pieces/Cwda/n_black_knight.svg create mode 100644 pieces/Cwda/n_black_pawn.svg create mode 100644 pieces/Cwda/n_black_queen.svg create mode 100644 pieces/Cwda/n_black_rook.svg create mode 100644 pieces/Cwda/n_white_bishop.svg create mode 100644 pieces/Cwda/n_white_king.svg create mode 100644 pieces/Cwda/n_white_knight.svg create mode 100644 pieces/Cwda/n_white_pawn.svg create mode 100644 pieces/Cwda/n_white_queen.svg create mode 100644 pieces/Cwda/n_white_rook.svg create mode 100644 pieces/Cwda/r_black_bishop.svg create mode 100644 pieces/Cwda/r_black_king.svg create mode 100644 pieces/Cwda/r_black_knight.svg create mode 100644 pieces/Cwda/r_black_pawn.svg create mode 100644 pieces/Cwda/r_black_queen.svg create mode 100644 pieces/Cwda/r_black_rook.svg create mode 100644 pieces/Cwda/r_white_bishop.svg create mode 100644 pieces/Cwda/r_white_king.svg create mode 100644 pieces/Cwda/r_white_knight.svg create mode 100644 pieces/Cwda/r_white_pawn.svg create mode 100644 pieces/Cwda/r_white_queen.svg create mode 100644 pieces/Cwda/r_white_rook.svg create mode 100644 variants/Cwda/complete_rules.html create mode 100644 variants/Cwda/rules.html create mode 100644 variants/Cwda/style.css diff --git a/pieces/Cwda/CREDITS b/pieces/Cwda/CREDITS new file mode 100644 index 0000000..2d04719 --- /dev/null +++ b/pieces/Cwda/CREDITS @@ -0,0 +1 @@ +Pieces designed by "Couch Tomato #2218" on Discord, diff --git a/pieces/Cwda/c_black_bishop.svg b/pieces/Cwda/c_black_bishop.svg new file mode 100644 index 0000000..f9f069b --- /dev/null +++ b/pieces/Cwda/c_black_bishop.svg @@ -0,0 +1,153 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pieces/Cwda/c_black_king.svg b/pieces/Cwda/c_black_king.svg new file mode 100644 index 0000000..953aee8 --- /dev/null +++ b/pieces/Cwda/c_black_king.svg @@ -0,0 +1,89 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/pieces/Cwda/c_black_knight.svg b/pieces/Cwda/c_black_knight.svg new file mode 100644 index 0000000..ed8ead5 --- /dev/null +++ b/pieces/Cwda/c_black_knight.svg @@ -0,0 +1,248 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pieces/Cwda/c_black_pawn.svg b/pieces/Cwda/c_black_pawn.svg new file mode 100644 index 0000000..6b0df69 --- /dev/null +++ b/pieces/Cwda/c_black_pawn.svg @@ -0,0 +1,61 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/pieces/Cwda/c_black_queen.svg b/pieces/Cwda/c_black_queen.svg new file mode 100644 index 0000000..a7e6633 --- /dev/null +++ b/pieces/Cwda/c_black_queen.svg @@ -0,0 +1,198 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pieces/Cwda/c_black_rook.svg b/pieces/Cwda/c_black_rook.svg new file mode 100644 index 0000000..cfb7532 --- /dev/null +++ b/pieces/Cwda/c_black_rook.svg @@ -0,0 +1,108 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/pieces/Cwda/c_white_bishop.svg b/pieces/Cwda/c_white_bishop.svg new file mode 100644 index 0000000..2b93f11 --- /dev/null +++ b/pieces/Cwda/c_white_bishop.svg @@ -0,0 +1,153 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pieces/Cwda/c_white_king.svg b/pieces/Cwda/c_white_king.svg new file mode 100644 index 0000000..a13d1a8 --- /dev/null +++ b/pieces/Cwda/c_white_king.svg @@ -0,0 +1,85 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/pieces/Cwda/c_white_knight.svg b/pieces/Cwda/c_white_knight.svg new file mode 100644 index 0000000..fa874ef --- /dev/null +++ b/pieces/Cwda/c_white_knight.svg @@ -0,0 +1,265 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pieces/Cwda/c_white_pawn.svg b/pieces/Cwda/c_white_pawn.svg new file mode 100644 index 0000000..d6df722 --- /dev/null +++ b/pieces/Cwda/c_white_pawn.svg @@ -0,0 +1,82 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/pieces/Cwda/c_white_queen.svg b/pieces/Cwda/c_white_queen.svg new file mode 100644 index 0000000..cc58283 --- /dev/null +++ b/pieces/Cwda/c_white_queen.svg @@ -0,0 +1,129 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pieces/Cwda/c_white_rook.svg b/pieces/Cwda/c_white_rook.svg new file mode 100644 index 0000000..f51d40d --- /dev/null +++ b/pieces/Cwda/c_white_rook.svg @@ -0,0 +1,106 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/pieces/Cwda/n_black_bishop.svg b/pieces/Cwda/n_black_bishop.svg new file mode 100644 index 0000000..dab8405 --- /dev/null +++ b/pieces/Cwda/n_black_bishop.svg @@ -0,0 +1,97 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/pieces/Cwda/n_black_king.svg b/pieces/Cwda/n_black_king.svg new file mode 100644 index 0000000..10ecec8 --- /dev/null +++ b/pieces/Cwda/n_black_king.svg @@ -0,0 +1,89 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/pieces/Cwda/n_black_knight.svg b/pieces/Cwda/n_black_knight.svg new file mode 100644 index 0000000..f6bd03f --- /dev/null +++ b/pieces/Cwda/n_black_knight.svg @@ -0,0 +1,117 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/pieces/Cwda/n_black_pawn.svg b/pieces/Cwda/n_black_pawn.svg new file mode 100644 index 0000000..73488c5 --- /dev/null +++ b/pieces/Cwda/n_black_pawn.svg @@ -0,0 +1,61 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/pieces/Cwda/n_black_queen.svg b/pieces/Cwda/n_black_queen.svg new file mode 100644 index 0000000..7abeae9 --- /dev/null +++ b/pieces/Cwda/n_black_queen.svg @@ -0,0 +1,182 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pieces/Cwda/n_black_rook.svg b/pieces/Cwda/n_black_rook.svg new file mode 100644 index 0000000..a56cc84 --- /dev/null +++ b/pieces/Cwda/n_black_rook.svg @@ -0,0 +1,98 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/pieces/Cwda/n_white_bishop.svg b/pieces/Cwda/n_white_bishop.svg new file mode 100644 index 0000000..85f032e --- /dev/null +++ b/pieces/Cwda/n_white_bishop.svg @@ -0,0 +1,81 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/pieces/Cwda/n_white_king.svg b/pieces/Cwda/n_white_king.svg new file mode 100644 index 0000000..49c3271 --- /dev/null +++ b/pieces/Cwda/n_white_king.svg @@ -0,0 +1,85 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/pieces/Cwda/n_white_knight.svg b/pieces/Cwda/n_white_knight.svg new file mode 100644 index 0000000..1066139 --- /dev/null +++ b/pieces/Cwda/n_white_knight.svg @@ -0,0 +1,114 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/pieces/Cwda/n_white_pawn.svg b/pieces/Cwda/n_white_pawn.svg new file mode 100644 index 0000000..6bdfc16 --- /dev/null +++ b/pieces/Cwda/n_white_pawn.svg @@ -0,0 +1,82 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/pieces/Cwda/n_white_queen.svg b/pieces/Cwda/n_white_queen.svg new file mode 100644 index 0000000..9357f93 --- /dev/null +++ b/pieces/Cwda/n_white_queen.svg @@ -0,0 +1,153 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pieces/Cwda/n_white_rook.svg b/pieces/Cwda/n_white_rook.svg new file mode 100644 index 0000000..bfaae26 --- /dev/null +++ b/pieces/Cwda/n_white_rook.svg @@ -0,0 +1,97 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/pieces/Cwda/r_black_bishop.svg b/pieces/Cwda/r_black_bishop.svg new file mode 100644 index 0000000..2c8fc2d --- /dev/null +++ b/pieces/Cwda/r_black_bishop.svg @@ -0,0 +1,86 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/pieces/Cwda/r_black_king.svg b/pieces/Cwda/r_black_king.svg new file mode 100644 index 0000000..672f3c2 --- /dev/null +++ b/pieces/Cwda/r_black_king.svg @@ -0,0 +1,89 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/pieces/Cwda/r_black_knight.svg b/pieces/Cwda/r_black_knight.svg new file mode 100644 index 0000000..131b5d0 --- /dev/null +++ b/pieces/Cwda/r_black_knight.svg @@ -0,0 +1,136 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pieces/Cwda/r_black_pawn.svg b/pieces/Cwda/r_black_pawn.svg new file mode 100644 index 0000000..16a15b4 --- /dev/null +++ b/pieces/Cwda/r_black_pawn.svg @@ -0,0 +1,61 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/pieces/Cwda/r_black_queen.svg b/pieces/Cwda/r_black_queen.svg new file mode 100644 index 0000000..78c3f98 --- /dev/null +++ b/pieces/Cwda/r_black_queen.svg @@ -0,0 +1,153 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pieces/Cwda/r_black_rook.svg b/pieces/Cwda/r_black_rook.svg new file mode 100644 index 0000000..0db1444 --- /dev/null +++ b/pieces/Cwda/r_black_rook.svg @@ -0,0 +1,89 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/pieces/Cwda/r_white_bishop.svg b/pieces/Cwda/r_white_bishop.svg new file mode 100644 index 0000000..05cfc70 --- /dev/null +++ b/pieces/Cwda/r_white_bishop.svg @@ -0,0 +1,79 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/pieces/Cwda/r_white_king.svg b/pieces/Cwda/r_white_king.svg new file mode 100644 index 0000000..317f686 --- /dev/null +++ b/pieces/Cwda/r_white_king.svg @@ -0,0 +1,85 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/pieces/Cwda/r_white_knight.svg b/pieces/Cwda/r_white_knight.svg new file mode 100644 index 0000000..52f10e5 --- /dev/null +++ b/pieces/Cwda/r_white_knight.svg @@ -0,0 +1,109 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/pieces/Cwda/r_white_pawn.svg b/pieces/Cwda/r_white_pawn.svg new file mode 100644 index 0000000..43ce32f --- /dev/null +++ b/pieces/Cwda/r_white_pawn.svg @@ -0,0 +1,83 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/pieces/Cwda/r_white_queen.svg b/pieces/Cwda/r_white_queen.svg new file mode 100644 index 0000000..22d6d4f --- /dev/null +++ b/pieces/Cwda/r_white_queen.svg @@ -0,0 +1,148 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pieces/Cwda/r_white_rook.svg b/pieces/Cwda/r_white_rook.svg new file mode 100644 index 0000000..d26e5c7 --- /dev/null +++ b/pieces/Cwda/r_white_rook.svg @@ -0,0 +1,123 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/variants.js b/variants.js index 9ff40a7..524538c 100644 --- a/variants.js +++ b/variants.js @@ -39,7 +39,7 @@ const variants = [ {name: 'Crazyhouse', desc: 'Captures reborn'}, {name: 'Crossing', desc: 'Cross the river'}, {name: 'Cylinder', desc: 'Neverending rows'}, -// {name: 'Cwda', desc: 'New teams', disp: 'Different armies'}, + {name: 'Cwda', desc: 'New teams', disp: 'Different armies'}, {name: 'Dark', desc: 'In the shadow'}, // {name: 'Diamond', desc: 'Rotating board'}, // {name: 'Dice', desc: 'Roll the dice'}, diff --git a/variants/Cwda/class.js b/variants/Cwda/class.js index 393e407..3a47146 100644 --- a/variants/Cwda/class.js +++ b/variants/Cwda/class.js @@ -1,4 +1,5 @@ import ChessRules from "/base_rules.js"; +import {FenUtil} from "/utils/setupPieces.js" export default class CwdaRules extends ChessRules { @@ -76,21 +77,21 @@ export default class CwdaRules extends ChessRules { } ); let pawnLines = { - w: "pppppppp", - b: "pppppppp" + w: Array(8).fill('p'), + b: Array(8).fill('p') }; for (const c of ['w', 'b']) { const army = "army" + (c == 'w' ? "1" : "2"); if (this.options[army] != 'F') { - for (let obj of [s, pawnLines]) { - obj[c] = obj[c].split("") - .map(p => V.PiecesMap[this.options[army]][p]).join(""); - } + for (let obj of [s, pawnLines]) + obj[c] = obj[c].map(p => V.PiecesMap[this.options[army]][p]); } } return { fen: s.b.join("") + "/" + - pawnLines['b'] + "/8/8/8/8/" + pawnLines['w'].toUpperCase() + + pawnLines['b'].join("") + + "/8/8/8/8/" + + pawnLines['w'].join("").toUpperCase() + "/" + s.w.join("").toUpperCase(), o: {flags: s.flags} }; @@ -105,8 +106,8 @@ export default class CwdaRules extends ChessRules { setOtherVariables(fenParsed) { super.setOtherVariables(fenParsed); - this.army1 = fenParsed.armies.charAt(0); - this.army2 = fenParsed.armies.charAt(1); + this.options["army1"] = fenParsed.armies.charAt(0); + this.options["army2"] = fenParsed.armies.charAt(1); } isKing(x, y, p) { @@ -165,12 +166,14 @@ export default class CwdaRules extends ChessRules { pieces(color, x, y) { const res = super.pieces(color, x, y); + const backward = (color == 'w' ? 1 : -1); + const forward = -backward; return Object.assign( { 'd': { "class": "c_rook", both: [ - {steps: V.steps.b}, + {steps: res['b'].both[0].steps}, {steps: V.steps.d, range: 1} ] }, @@ -178,7 +181,7 @@ export default class CwdaRules extends ChessRules { "class": "c_knight", both: [ {steps: V.steps.a, range: 1}, - {steps: V.steps.r, range: 1} + {steps: res['r'].both[0].steps, range: 1} ] }, 'f': { @@ -186,170 +189,122 @@ export default class CwdaRules extends ChessRules { both: [ {steps: V.steps.d, range: 1}, {steps: V.steps.a, range: 1}, - {steps: V.steps.b, range: 1} + {steps: res['b'].both[0].steps, range: 1} ] }, 'c': { "class": "c_queen", both: [ - {steps: V.steps.b}, - {steps: V.steps.n, range: 1} + {steps: res['b'].both[0].steps}, + {steps: res['n'].both[0].steps, range: 1} ] }, - 'm': { moveas: 'k' }, - 'z': { moveas: 'p' }, + 'm': { "class": "c_king", moveas: 'k' }, + 'z': { "class": "c_pawn", moveas: 'p' }, 'g': { - + "class": "n_rook", + both: [ + {steps: [[0, -1], [0, 1], [color == 'w' ? -1 : 1, 0]]}, + {steps: [[backward, -1], [backward, 0], [backward, 1]], range: 1} + ] }, 'i': { - + "class": "n_knight", + both: [ + {steps: V.steps.$n, range: 1}, + {steps: V.steps.f, range: 1} + ] }, 't': { - + "class": "n_bishop", + both: [ + { + steps: [[0, -1], [0, 1], [backward, -1], + [backward, 0], [backward, 1]], + range: 1 + }, + { + steps: [[2*forward, -1], [2*forward, 1], + [forward, -2], [forward, 2]], + range: 1 + } + ] }, 'l': { - + "class": "n_queen", + both: [ + {steps: [[0, -1], [0, 1], [forward, 0]]}, + {steps: [[forward, -1], [forward, 1], + [backward, -1], [backward, 0], [backward, 1]], range: 1}, + {steps: [[2*forward, -1], [2*forward, 1], + [forward, -2], [forward, 2]], range: 1} + ] }, - 'e': { moveas: 'k' }, - 'v': { moveas: 'p' }, + 'e': { "class": "n_king", moveas: 'k' }, + 'v': { "class": "n_pawn", moveas: 'p' }, 's': { - + "class": "r_rook", + both: [{steps: res['r'].both[0].steps, range: 4}] }, 'y': { - + "class": "r_knight", + both: [ + {steps: V.steps.d, range: 1}, + {steps: V.steps.w, range: 1} + ] }, 'h': { - + "class": "r_bishop", + both: [ + {steps: V.steps.d, range: 1}, + {steps: V.steps.f, range: 1}, + {steps: V.steps.$3, range: 1} + ] }, 'o': { - + "class": "r_queen", + both: [ + {steps: res['r'].both[0].steps}, + {steps: res['n'].both[0].steps, range: 1} + ] }, - 'a': { moveas: 'k' }, - 'u': { moveas: 'p' } + 'a': { "class": "r_king", moveas: 'k' }, + 'u': { "class": "r_pawn", moveas: 'p' } }, res ); - - - - - - getPotentialN_rookMoves(sq) { - const c = this.turn; - const rookSteps = [ [0, -1], [0, 1], [c == 'w' ? -1 : 1, 0] ]; - const backward = (c == 'w' ? 1 : -1); - const kingSteps = [ [backward, -1], [backward, 0], [backward, 1] ]; - return ( - this.getSlideNJumpMoves(sq, rookSteps).concat( - this.getSlideNJumpMoves(sq, kingSteps, 1)) - ); - } - - getPotentialN_knightMoves(sq) { - return ( - this.getSlideNJumpMoves(sq, V.steps.$n, 1).concat( - this.getSlideNJumpMoves(sq, V.steps.f, 1)) - ); - } - - getPotentialN_bishopMoves(sq) { - const backward = (this.turn == 'w' ? 1 : -1); - const kingSteps = [ - [0, -1], [0, 1], [backward, -1], [backward, 0], [backward, 1] - ]; - const forward = -backward; - const knightSteps = [ - [2*forward, -1], [2*forward, 1], [forward, -2], [forward, 2] - ]; - return ( - this.getSlideNJumpMoves(sq, knightSteps, 1).concat( - this.getSlideNJumpMoves(sq, kingSteps, 1)) - ); - } - - getPotentialN_queenMoves(sq) { - const backward = (this.turn == 'w' ? 1 : -1); - const forward = -backward; - const kingSteps = [ - [forward, -1], [forward, 1], - [backward, -1], [backward, 0], [backward, 1] - ]; - const knightSteps = [ - [2*forward, -1], [2*forward, 1], [forward, -2], [forward, 2] - ]; - const rookSteps = [ [0, -1], [0, 1], [forward, 0] ]; - return ( - this.getSlideNJumpMoves(sq, rookSteps).concat( - this.getSlideNJumpMoves(sq, kingSteps, 1)).concat( - this.getSlideNJumpMoves(sq, knightSteps, 1)) - ); - } - - getPotentialR_rookMoves(sq) { - return this.getSlideNJumpMoves(sq, V.steps.r, 4); } - getPotentialR_knightMoves(sq) { - return ( - this.getSlideNJumpMoves(sq, V.steps.d, 1).concat( - this.getSlideNJumpMoves(sq, V.steps.w, 1)) - ); - } - - getPotentialR_bishopMoves(sq) { - return ( - this.getSlideNJumpMoves(sq, V.steps.d, 1).concat( - this.getSlideNJumpMoves(sq, V.steps.f, 1)).concat( - this.getSlideNJumpMoves(sq, V.steps.$3, 1)) - ); - } - - getPotentialR_queenMoves(sq) { - return ( - this.getSlideNJumpMoves(sq, V.steps.r).concat( - this.getSlideNJumpMoves(sq, V.steps.n, 1)) - ); - } - - case V.PAWN: { - // Can promote in anything from the two current armies - let promotions = []; - for (let army of ["army1", "army2"]) { - if (army == "army2" && this.army2 == this.army1) break; - switch (this[army]) { - case 'C': { - Array.prototype.push.apply(promotions, - [V.C_ROOK, V.C_KNIGHT, V.C_BISHOP, V.C_QUEEN]); - break; - } - case 'N': { - Array.prototype.push.apply(promotions, - [V.N_ROOK, V.N_KNIGHT, V.N_BISHOP, V.N_QUEEN]); - break; - } - case 'R': { - Array.prototype.push.apply(promotions, - [V.R_ROOK, V.R_KNIGHT, V.R_BISHOP, V.R_QUEEN]); - break; - } - case 'F': { - Array.prototype.push.apply(promotions, - [V.ROOK, V.KNIGHT, V.BISHOP, V.QUEEN]); - break; - } - } - } - return super.getPotentialPawnMoves(sq, promotions); + get pawnPromotions() { + // Can promote in anything from the two current armies + let promotions = []; + for (let army of ["army1", "army2"]) { + if (army == "army2" && this.options["army2"] == this.options["army1"]) + break; + switch (this.options[army]) { + case 'C': + Array.prototype.push.apply(promotions, ['d', 'w', 'f', 'c']); + break; + case 'N': + Array.prototype.push.apply(promotions, ['g', 'i', 't', 'l']); + break; + case 'R': + Array.prototype.push.apply(promotions, ['s', 'y', 'h', 'o']); + break; + case 'F': + Array.prototype.push.apply(promotions, ['r', 'n', 'b', 'q']); + break; } - default: return super.getPotentialMovesFrom(sq); } + return promotions; + } getCastleMoves([x, y]) { const color = this.getColor(x, y); - let finalSquares = [ [2, 3], [V.size.y - 2, V.size.y - 3] ]; + let finalSquares = [ [2, 3], [this.size.y - 2, this.size.y - 3] ]; if ( - (color == 'w' && this.army1 == 'C') || - (color == 'b' && this.army2 == 'C') + (color == 'w' && this.options["army1"] == 'C') || + (color == 'b' && this.options["army2"] == 'C') ) { // Colorbound castle long in an unusual way: finalSquares[0] = [1, 2]; diff --git a/variants/Cwda/complete_rules.html b/variants/Cwda/complete_rules.html new file mode 100644 index 0000000..958c0b6 --- /dev/null +++ b/variants/Cwda/complete_rules.html @@ -0,0 +1,128 @@ + + + Different Armies Rules + + + + + +
+

Different Armies Rules

+ +
+

White and black pieces are replaced by different armies.

+

+ Pawns and kings move as usual, but the other pieces generally do not. + Indeed, before the game start you must select two armies, defining + new movements for "rooks", "knights", "bishops" and "queens". +

+

Pieces movements are described using these simple pieces:

+
    +
  • Dabbabah = jump two squares orthogonally
  • +
  • Alfil = jump two squares diagonally
  • +
  • Wazir = one square orthogonally
  • +
  • Ferz = one square diagonally
  • +
  • Three leaper (L3) = jump three squares orthogonally
  • +
  • Narrow knight = knight without "2+1 lateral moves"
  • +
+

Pawns can be promoted into a piece of any of the two armies playing.

+
+ +

The Colorbound Clobberers

+ +
+ + + +
+
+
+
+
+
+ Moves of the Bede on the left, and of the Waffle on the right. +
+
+ +
+
fen:8/8/8/3F4/8/8/8/8 b7,c6,b5,f5,d3,d7,b3,c4,e4,f3,e6,f7:
+
+ Moves of the Fad. +
+
+ +

+ When castling large, the king and rook arrive respectively on + b1/b8 and c1/c8 so that the rook remains on the same color. +

+ +

The Nutty Knights

+ +
+ + + +
+
fen:8/8/8/8/3G4/8/8/8 d5,d6,d7,d8,c4,b4,a4,e4,f4,g4,h4,c3,d3,e3:
+
fen:8/8/8/8/4i3/8/8/8 d6,d2,f6,f2,d3,d5,f5,f3:
+
+ Moves of the Charging rook on the left, and of the Fibnif on the right. +
+
+ +
+
fen:8/8/8/8/3T4/8/8/8 b5,c6,e6,f5,c4,e4,c3,d3,e3:
+
fen:8/8/8/8/4c3/8/8/8 e5,e6,e7,e8,d4,c4,b4,a4,f4,g4,h4,d6,c5,f6,g5,d5,f5,d3,e3,f3:
+
+ Moves of the Charging knight on the left, and of the Colonel on the right. +
+
+ +

The Remarkable Rookies

+ +
+ + + +
+
fen:8/8/8/3y4/8/8/8/8 d3,b5,d7,f5,c5,d6,e5,d4:
+
fen:8/8/8/4H3/8/8/8/8 c5,e7,g5,e3,b5,e8,h5,e2,d4,d6,f6,f4:
+
+ Moves of the Woody rook on the left, and of the Half-duck on the right. +
+
+ +

Fide army

+ +

The standard chess pieces.

+ +

Source

+ +

Chess with different armies on chessvariants.com.

+ + + + + diff --git a/variants/Cwda/rules.html b/variants/Cwda/rules.html new file mode 100644 index 0000000..cbd2d72 --- /dev/null +++ b/variants/Cwda/rules.html @@ -0,0 +1,12 @@ +

+ Chess with different armies. Default: + + Colorbound Clobberers + . +

+ + + Full rules description. + + +

Ralph Betza (1996).

diff --git a/variants/Cwda/style.css b/variants/Cwda/style.css new file mode 100644 index 0000000..f9f7679 --- /dev/null +++ b/variants/Cwda/style.css @@ -0,0 +1,112 @@ +@import url("/base_pieces.css"); + +piece.white.c_rook { + background-image: url('/pieces/Cwda/c_white_rook.svg'); +} +piece.black.c_rook { + background-image: url('/pieces/Cwda/c_black_rook.svg'); +} +piece.white.c_knight { + background-image: url('/pieces/Cwda/c_white_knight.svg'); +} +piece.black.c_knight { + background-image: url('/pieces/Cwda/c_black_knight.svg'); +} +piece.white.c_bishop { + background-image: url('/pieces/Cwda/c_white_bishop.svg'); +} +piece.black.c_bishop { + background-image: url('/pieces/Cwda/c_black_bishop.svg'); +} +piece.white.c_queen { + background-image: url('/pieces/Cwda/c_white_queen.svg'); +} +piece.black.c_queen { + background-image: url('/pieces/Cwda/c_black_queen.svg'); +} +piece.white.c_king { + background-image: url('/pieces/Cwda/c_white_king.svg'); +} +piece.black.c_king { + background-image: url('/pieces/Cwda/c_black_king.svg'); +} +piece.white.c_pawn { + background-image: url('/pieces/Cwda/c_white_pawn.svg'); +} +piece.black.c_pawn { + background-image: url('/pieces/Cwda/c_black_pawn.svg'); +} + +piece.white.n_rook { + background-image: url('/pieces/Cwda/n_white_rook.svg'); +} +piece.black.n_rook { + background-image: url('/pieces/Cwda/n_black_rook.svg'); +} +piece.white.n_knight { + background-image: url('/pieces/Cwda/n_white_knight.svg'); +} +piece.black.n_knight { + background-image: url('/pieces/Cwda/n_black_knight.svg'); +} +piece.white.n_bishop { + background-image: url('/pieces/Cwda/n_white_bishop.svg'); +} +piece.black.n_bishop { + background-image: url('/pieces/Cwda/n_black_bishop.svg'); +} +piece.white.n_queen { + background-image: url('/pieces/Cwda/n_white_queen.svg'); +} +piece.black.n_queen { + background-image: url('/pieces/Cwda/n_black_queen.svg'); +} +piece.white.n_king { + background-image: url('/pieces/Cwda/n_white_king.svg'); +} +piece.black.n_king { + background-image: url('/pieces/Cwda/n_black_king.svg'); +} +piece.white.n_pawn { + background-image: url('/pieces/Cwda/n_white_pawn.svg'); +} +piece.black.n_pawn { + background-image: url('/pieces/Cwda/n_black_pawn.svg'); +} + +piece.white.r_rook { + background-image: url('/pieces/Cwda/r_white_rook.svg'); +} +piece.black.r_rook { + background-image: url('/pieces/Cwda/r_black_rook.svg'); +} +piece.white.r_knight { + background-image: url('/pieces/Cwda/r_white_knight.svg'); +} +piece.black.r_knight { + background-image: url('/pieces/Cwda/r_black_knight.svg'); +} +piece.white.r_bishop { + background-image: url('/pieces/Cwda/r_white_bishop.svg'); +} +piece.black.r_bishop { + background-image: url('/pieces/Cwda/r_black_bishop.svg'); +} +piece.white.r_queen { + background-image: url('/pieces/Cwda/r_white_queen.svg'); +} +piece.black.r_queen { + background-image: url('/pieces/Cwda/r_black_queen.svg'); +} +piece.white.r_king { + background-image: url('/pieces/Cwda/r_white_king.svg'); +} +piece.black.r_king { + background-image: url('/pieces/Cwda/r_black_king.svg'); +} +piece.white.r_pawn { + background-image: url('/pieces/Cwda/r_white_pawn.svg'); +} +piece.black.r_pawn { + background-image: url('/pieces/Cwda/r_black_pawn.svg'); +} -- 2.44.0 From 2c8375bb77dda7cbeaee983a09e202436be2191c Mon Sep 17 00:00:00 2001 From: Benjamin Auder Date: Thu, 28 Dec 2023 11:46:58 +0100 Subject: [PATCH 02/16] Fix complete rules of Cwda --- base_rules.js | 10 ++++++++-- common.css | 20 ++++++++++++++++++-- utils/drawDiagrams.js | 10 +++++++--- variants/Cwda/class.js | 2 +- variants/Cwda/complete_rules.html | 8 ++++---- 5 files changed, 38 insertions(+), 12 deletions(-) diff --git a/base_rules.js b/base_rules.js index 699b1d8..757707d 100644 --- a/base_rules.js +++ b/base_rules.js @@ -235,7 +235,7 @@ export default class ChessRules { randomness: this.options["randomness"], between: [{p1: 'k', p2: 'r'}], diffCol: ['b'], - flags: ['r', 'k'] + flags: ['r'] } ); return { @@ -642,7 +642,13 @@ export default class ChessRules { else this[arrName] = ArrayFun.init(this.size.x, this.size.y, null); if (arrName == "d_pieces") - this.marks.forEach(([i, j]) => addPiece(i, j, arrName, "mark")); + this.marks.forEach((m) => { + const formattedSquare = + (this.size.x - parseInt(m.substring(1), 10)).toString(36) + + (m.charCodeAt(0) - 97).toString(36); + const mCoords = V.SquareToCoords(formattedSquare); + addPiece(mCoords.x, mCoords.y, arrName, "mark"); + }); }; if (this.marks) conditionalReset("d_pieces"); diff --git a/common.css b/common.css index cdfbc7a..5fee7ef 100644 --- a/common.css +++ b/common.css @@ -180,6 +180,14 @@ main > div { padding: 0 10px; overflow: auto; } +.full-rules figure.show-pieces { + max-width: 90%; + text-align: center; + margin: 0 auto; +} +.full-rules figure.show-pieces > img { + max-width: 100px; +} .full-rules > div { margin-bottom: 20px; } @@ -234,6 +242,16 @@ piece.mark.transparent { .full-rules .right { float: right; } +@media screen and (max-width: 550px) { + .full-rules .left { + float: none; + margin-bottom: 10px; + } + .full-rules .right { + float: none; + margin-top: 10px; + } +} .full-rules figcaption { display: block; text-align: center; @@ -350,8 +368,6 @@ piece.mark.transparent { .chessboard { position: absolute; cursor: pointer; - min-width: 200px; - min-height: 200px; } piece { position: absolute; diff --git a/utils/drawDiagrams.js b/utils/drawDiagrams.js index 9438dd6..3dd01f6 100644 --- a/utils/drawDiagrams.js +++ b/utils/drawDiagrams.js @@ -11,8 +11,12 @@ function fenToDiag(vname) { function getDiagSize(elt) { const baseWidth = Math.min(window.innerWidth, 800); let multFact = 1; - if (elt.classList.contains("left") || elt.classList.contains("right")) - multFact = 0.45; + if (elt.classList.contains("left") || elt.classList.contains("right")) { + if (baseWidth >= 551) + multFact = 0.45; + else + multFact = 0.7; + } else if (baseWidth > 630) multFact = 0.5; else @@ -43,7 +47,7 @@ function re_drawDiagrams() { element: "diag_" + i, fen: diagrams[i].dataset.fen, marks: diagrams[i].dataset.mks - ? JSON.parse('[' + diagrams[i].dataset.mks + ']') + ? diagrams[i].dataset.mks.split(',') : undefined, color: diagrams[i].dataset.col || 'w', options: {}, diff --git a/variants/Cwda/class.js b/variants/Cwda/class.js index 3a47146..db79917 100644 --- a/variants/Cwda/class.js +++ b/variants/Cwda/class.js @@ -73,7 +73,7 @@ export default class CwdaRules extends ChessRules { randomness: this.options["randomness"], between: [{p1: 'k', p2: 'r'}], diffCol: ['b'], - flags: ['r', 'k'] + flags: ['r'] } ); let pawnLines = { diff --git a/variants/Cwda/complete_rules.html b/variants/Cwda/complete_rules.html index 958c0b6..9114c05 100644 --- a/variants/Cwda/complete_rules.html +++ b/variants/Cwda/complete_rules.html @@ -30,7 +30,7 @@

The Colorbound Clobberers

-
+
  • Rook = bishop + dabbabah = "bede" (D),
  • @@ -41,11 +41,11 @@
    + data-fen='8/8/8/3D4/8/8/8/8 w 0 {"armies":"CC","flags":"8888","enpassant":"-"}', + data-mks="a8,b7,c6,e4,f3,g2,h1,c4,b3,a2,e6,f7,g8,f5,d3,b5,d7">
    -- 2.44.0 From a55fde41f82207bf401c54b158dd6d0182799fd3 Mon Sep 17 00:00:00 2001 From: Benjamin Auder Date: Sat, 30 Dec 2023 11:58:13 +0100 Subject: [PATCH 03/16] Fix some complete rules --- .gitignore | 2 + README.md | 1 + common.css | 4 + variants/Alapo/rules.html | 8 +- variants/Alice/rules.html | 8 +- variants/Allmate/rules.html | 8 +- variants/Ambiguous/rules.html | 8 +- variants/Apocalypse/complete_rules.html | 1 - variants/Apocalypse/rules.html | 8 +- variants/Arena/rules.html | 8 +- variants/Atomic/rules.html | 8 +- variants/Avalam/rules.html | 8 +- variants/Avalanche/rules.html | 8 +- variants/Balaklava/rules.html | 8 +- variants/Bario/complete_rules.html | 107 ++++++++++++++++-------- variants/Bario/rules.html | 16 ++-- variants/Baroque/complete_rules.html | 15 ++-- variants/Baroque/rules.html | 8 +- variants/Benedict/rules.html | 8 +- variants/Berolina/rules.html | 6 +- variants/Cannibal/rules.html | 8 +- variants/Chakart/complete_rules.html | 1 - variants/Chakart/rules.html | 8 +- variants/Checkered/complete_rules.html | 19 +++-- variants/Checkered/rules.html | 8 +- variants/Chess960/rules.html | 8 +- variants/Circular/rules.html | 2 +- variants/Clorange/rules.html | 14 ++-- variants/Copycat/rules.html | 6 +- variants/Crazyhouse/rules.html | 8 +- variants/Cwda/complete_rules.html | 72 ++++++++++++---- variants/Cwda/rules.html | 8 +- variants/Dark/rules.html | 8 +- variants/Doublemove/rules.html | 8 +- variants/Giveaway/rules.html | 8 +- variants/Hex/rules.html | 16 ++-- variants/Madrasi/rules.html | 8 +- variants/Progressive/rules.html | 8 +- variants/Recycle/rules.html | 8 +- variants/Refusal/rules.html | 8 +- variants/Rifle/rules.html | 8 +- variants/Suction/rules.html | 8 +- variants/_Antiking/rules.html | 8 +- 43 files changed, 330 insertions(+), 176 deletions(-) diff --git a/.gitignore b/.gitignore index 160c63a..d3206f9 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,7 @@ /node_modules/ /assets/ /assets.zip +/extras/ +/extras.zip /.pid /parameters.js diff --git a/README.md b/README.md index b0517cd..4636ac4 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ PHP + Node.js + npm. ## Usage ```wget https://xogo.live/assets.zip && unzip assets.zip```
    +```wget https://xogo.live/extras.zip && unzip extras.zip```
    Rename parameters.js.dist → parameters.js, and edit file.
    ```npm i``` diff --git a/common.css b/common.css index 5fee7ef..eabf641 100644 --- a/common.css +++ b/common.css @@ -260,6 +260,10 @@ piece.mark.transparent { color: #0D1C46; font-weight: bold; } +.full-rules .img-center { + display: block; + margin: 0 auto; +} /* TODO: use same CSS for rules and full-rules? */ .full-rules p, .full-rules ul, .full-rules ol { margin: 10px 0; diff --git a/variants/Alapo/rules.html b/variants/Alapo/rules.html index 9ec57e0..910613b 100644 --- a/variants/Alapo/rules.html +++ b/variants/Alapo/rules.html @@ -2,8 +2,10 @@

    Goal: bring a piece safely on the last rank.

    - - chessvariants page. - +

    + + chessvariants page. + +

    Johannes Tranelis (1982).

    diff --git a/variants/Alice/rules.html b/variants/Alice/rules.html index 98659ea..215818f 100644 --- a/variants/Alice/rules.html +++ b/variants/Alice/rules.html @@ -1,7 +1,9 @@

    Pieces move to the next board after playing (other side of the mirror).

    - - chessvariants page. - +

    + + chessvariants page. + +

    Vernon R. Parton (1953).

    diff --git a/variants/Allmate/rules.html b/variants/Allmate/rules.html index 4bdc308..4738949 100644 --- a/variants/Allmate/rules.html +++ b/variants/Allmate/rules.html @@ -6,8 +6,10 @@

    Win by mate-capturing the enemy king.

    - - chessvariants page. - +

    + + chessvariants page. + +

    Dr. Chris Taylor (1979).

    diff --git a/variants/Ambiguous/rules.html b/variants/Ambiguous/rules.html index acd3585..137579d 100644 --- a/variants/Ambiguous/rules.html +++ b/variants/Ambiguous/rules.html @@ -8,8 +8,10 @@ your opponent, then to choose one for you - which could be altered.

    - - chessvariants page. - +

    + + chessvariants page. + +

    Fabrice Liardet (2005).

    diff --git a/variants/Apocalypse/complete_rules.html b/variants/Apocalypse/complete_rules.html index ae45dad..9e2d5c0 100644 --- a/variants/Apocalypse/complete_rules.html +++ b/variants/Apocalypse/complete_rules.html @@ -5,7 +5,6 @@ -

    Apocalypse Rules

    diff --git a/variants/Apocalypse/rules.html b/variants/Apocalypse/rules.html index 6674bb2..75f35b2 100644 --- a/variants/Apocalypse/rules.html +++ b/variants/Apocalypse/rules.html @@ -8,8 +8,10 @@

    The goal is to eliminate all enemy pawns.

    - - Full rules description. - +

    + + Full rules description. + +

    C.S. Elliott (1976).

    diff --git a/variants/Arena/rules.html b/variants/Arena/rules.html index 5aa8716..b9098c3 100644 --- a/variants/Arena/rules.html +++ b/variants/Arena/rules.html @@ -14,8 +14,10 @@ A player who lose both king and queen also lose the game.

    - - chessvariants page. - +

    + + chessvariants page. + +

    Jeff Kiska (2000).

    diff --git a/variants/Atomic/rules.html b/variants/Atomic/rules.html index 6067ed5..6675403 100644 --- a/variants/Atomic/rules.html +++ b/variants/Atomic/rules.html @@ -5,6 +5,8 @@

    Win by checkmate or by exploding the enemy king.

    - - lichess page. - +

    + + lichess page. + +

    diff --git a/variants/Avalam/rules.html b/variants/Avalam/rules.html index 83e301e..6883b3b 100644 --- a/variants/Avalam/rules.html +++ b/variants/Avalam/rules.html @@ -9,8 +9,10 @@ largest number of towers of his color (on top) wins.

    - - More informations. - +

    + + More informations. + +

    Philippe Deweys (1995).

    diff --git a/variants/Avalanche/rules.html b/variants/Avalanche/rules.html index b8bb255..9528d3a 100644 --- a/variants/Avalanche/rules.html +++ b/variants/Avalanche/rules.html @@ -6,8 +6,10 @@

    The goal is either to checkmate or to capture the enemy king.

    - - chessvariants page. - +

    + + chessvariants page. + +

    Ralph Betza (1977).

    diff --git a/variants/Balaklava/rules.html b/variants/Balaklava/rules.html index 97c96a6..96ce11b 100644 --- a/variants/Balaklava/rules.html +++ b/variants/Balaklava/rules.html @@ -10,8 +10,10 @@
  • No en passant captures.
- - chessvariants page. - +

+ + chessvariants page. + +

Gianluca Vecchi (1994).

diff --git a/variants/Bario/complete_rules.html b/variants/Bario/complete_rules.html index 93ecc9d..ad700ac 100644 --- a/variants/Bario/complete_rules.html +++ b/variants/Bario/complete_rules.html @@ -1,64 +1,97 @@ -p.boxed - | Your pieces remain in an undefined state until they are moved. + + + + Bario Rules + + + + +
+

Bario Rules

-p - | Bario is a chess variant invented by Panos Louridas in 1998. - a(href="https://www.bario-chess-checkers-chessphotography-spaceart.de/") - | His website - |  contains many examples and explanations. - | See also the discussion - a(href="https://www.chessvariants.com/index/listcomments.php?order=DESC&itemid=Bario") - | on chessvariants.com - | . +

+ Bario is a chess variant invented by Panos Louridas in 1998. + + His website + + contains many examples and explanations. + See also the discussion + + on chessvariants.com + . +

-figure - img.img-center(src="/variants/Bario/chessboard2.jpg" style="width:75%") - figcaption.text-center. - [With author's permission] +
+ +
+ [With author's permission]
Undefined pieces on first ranks. +
+
-p. +

Queens, rooks, bishops and knights begin the game in a reserve below the board, because their location isn't determined yet. At each turn, you can either move something already defined on the board, or -ol - li move a piece from your reserve to any question mark, and then - li move the now defined piece on the board. +

+
    +
  1. move a piece from your reserve to any question mark, and then
  2. +
  3. move the now defined piece on the board.
  4. +
-p An undefined piece gives check if some specialization giving check exists. +

Your pieces remain in an undefined state until they are moved.

-figure.diagram-container - .diagram - | fen:uuuuu1uk/p2p1qp1/1p6/7p/7P/5N2/PP1P1PP1/UUUKU1UU: - figcaption The white king cannot move, a rook might be on c8 or e8 +

An undefined piece gives check if some specialization giving check exists.

-h4 Details, special cases +
+
+
+
The white king cannot move, a rook might be on c8 or e8
+
-p. +

Details, special cases

+ +

At the first move, you must select a square for the king anywhere on the first rank — preferably in a corner. This deviates from the original intention of the author, but this way you will not need to castle later in the game. Click on a square to place the king. +

-p. +

If after your move all your pieces are defined (and weren't before), then all pieces on board revert to undefined state, unless: -ul - li. +

+
    +
  • all your pieces (board + reserve) are now of the same type, in which case none is put back in reserve, or - li. +
  • +
  • all opponent's pieces are of the same type, in which case they also remain defined. +
  • +
-figure.diagram-container - .diagram.diag12 - | fen:uuu1kuuu/2p5/2n5/1p1ppppp/p4PPP/3N3Q/PPPPP1BB/1RRUK3: - .diagram.diag22 - | fen:uuu1kuuu/2p5/2u5/1p1ppppp/p4PPP/3UU2U/PPPPP1UU/1UU1K3: - figcaption. +
+
+
+
+
+
Before and after knight definition on d1 (moving to e3) +
+
-p. +

If one of your undefined pieces is captured, you first have to choose which one was captured from the reserve: place it at the capture location. +

+ + + + + diff --git a/variants/Bario/rules.html b/variants/Bario/rules.html index 733246f..2dbcf24 100644 --- a/variants/Bario/rules.html +++ b/variants/Bario/rules.html @@ -14,12 +14,16 @@ all pieces on board return to undefined state.

- - Author's website. - +

+ + Author's website. + +

- - Full rules description. - +

+ + Full rules description. + +

Panos Louridas (1985).

diff --git a/variants/Baroque/complete_rules.html b/variants/Baroque/complete_rules.html index 1ac46cc..87709ed 100644 --- a/variants/Baroque/complete_rules.html +++ b/variants/Baroque/complete_rules.html @@ -5,7 +5,6 @@ -

Baroque Rules

@@ -108,7 +107,7 @@
+ data-mks='d4,d6,d8,a5'>
All marked squares captures are playable from d2.
@@ -120,8 +119,8 @@

+ data-fen='7k/8/8/3Qr3/8/8/8/K7 w 0' + data-mks="a5,b5,c5">
1.Qa5, 1.Qb5 or 1.Qc5 captures the black rook.
@@ -141,8 +140,8 @@

+ data-fen='7k/8/8/r3pP2/2n5/8/B7/K7 w 0' + data-mks="a5,c4">
1.Bd5 captures the two marked pieces.
@@ -166,8 +165,8 @@

+ data-fen='7k/8/8/p4r/4K3/8/8/8 w 0' + data-mks="e5">
1.Ke5 is impossible
diff --git a/variants/Baroque/rules.html b/variants/Baroque/rules.html index 0e30307..ec5bb30 100644 --- a/variants/Baroque/rules.html +++ b/variants/Baroque/rules.html @@ -6,8 +6,10 @@

The goal is still to checkmate.

- - Full rules description. - +

+ + Full rules description. + +

Robert Abbott (1963).

diff --git a/variants/Benedict/rules.html b/variants/Benedict/rules.html index db103a1..c2798b3 100644 --- a/variants/Benedict/rules.html +++ b/variants/Benedict/rules.html @@ -10,8 +10,10 @@ where only the queen can change the color of enemy pieces.

- - chessvariants page. - +

+ + chessvariants page. + +

William Daniel Troyka (2001).

diff --git a/variants/Berolina/rules.html b/variants/Berolina/rules.html index bfa1cca..1824b27 100644 --- a/variants/Berolina/rules.html +++ b/variants/Berolina/rules.html @@ -1,3 +1,7 @@ -

Pawns movements are reversed: they capture forward, and move diagonally. From the initial rank they can move two squares in diagonal. See also.

+

+ Pawns movements are reversed: they capture forward, and move diagonally. + From the initial rank they can move two squares in diagonal. + See also. +

Edmund Nebermann (1926).

diff --git a/variants/Cannibal/rules.html b/variants/Cannibal/rules.html index 480b5cf..81d9c58 100644 --- a/variants/Cannibal/rules.html +++ b/variants/Cannibal/rules.html @@ -1,5 +1,7 @@

After each capture, the capturer transforms into the captured piece.

- - chessvariants page. - +

+ + chessvariants page. + +

diff --git a/variants/Chakart/complete_rules.html b/variants/Chakart/complete_rules.html index 7bf3080..d1c8fd6 100644 --- a/variants/Chakart/complete_rules.html +++ b/variants/Chakart/complete_rules.html @@ -5,7 +5,6 @@ -

Chakart Rules

diff --git a/variants/Chakart/rules.html b/variants/Chakart/rules.html index d45cb0d..e125478 100644 --- a/variants/Chakart/rules.html +++ b/variants/Chakart/rules.html @@ -10,8 +10,10 @@
  • Eggs hide either a bonus or malus: see full description.
  • - - Full rules description. - +

    + + Full rules description. + +

    Charlotte Blard & Benjamin Auder (2020).

    diff --git a/variants/Checkered/complete_rules.html b/variants/Checkered/complete_rules.html index 5f21663..503e78d 100644 --- a/variants/Checkered/complete_rules.html +++ b/variants/Checkered/complete_rules.html @@ -6,7 +6,6 @@ -

    Checkered Rules

    @@ -15,12 +14,12 @@ The capture of an enemy piece produces a new "checkered" piece belonging to both players.

    -
    - - - - - +
    + + + + +
    Checkered pieces, born after captures.

    Note: the initial French name for this variant is "l'Échiqueté".

    @@ -52,8 +51,10 @@
  • Checkered pieces cannot be captured.
  • -
    -
    fen:2kr4/pp6/2p5/4ss1r/1P2ns1P/2Np4/P1P1P1BP/R2o1RK1:
    +
    +
    +
    Black plays Rxh4=P. (Checkered pawn to) h5 is allowed then, because piece's nature changed. diff --git a/variants/Checkered/rules.html b/variants/Checkered/rules.html index 892f352..a9209dd 100644 --- a/variants/Checkered/rules.html +++ b/variants/Checkered/rules.html @@ -3,8 +3,10 @@ Checkered moves cannot be undone on next turn.

    - - Full rules description. - +

    + + Full rules description. + +

    Patrick Bernier (2012).

    diff --git a/variants/Chess960/rules.html b/variants/Chess960/rules.html index 776fa4a..5192abe 100644 --- a/variants/Chess960/rules.html +++ b/variants/Chess960/rules.html @@ -1,3 +1,5 @@ - - Orthodox chess rules. - +

    + + Orthodox chess rules. + +

    diff --git a/variants/Circular/rules.html b/variants/Circular/rules.html index 6db9dd8..f9067b7 100644 --- a/variants/Circular/rules.html +++ b/variants/Circular/rules.html @@ -1,4 +1,4 @@

    -Lower and upper sides of the board communicate.
    + Lower and upper sides of the board communicate.
    All pawns move forward (up).

    diff --git a/variants/Clorange/rules.html b/variants/Clorange/rules.html index f10e7f6..541862e 100644 --- a/variants/Clorange/rules.html +++ b/variants/Clorange/rules.html @@ -1,8 +1,12 @@ -

    Captured pieces can be landed later in a non-capturing form;
    -they regain their ability to capture when captured again.

    +

    + Captured pieces can be landed later in a non-capturing form;
    + they regain their ability to capture when captured again. +

    - - chessvariants page. - +

    + + chessvariants page. + +

    Fergus Duniho (1999).

    diff --git a/variants/Copycat/rules.html b/variants/Copycat/rules.html index 43d1f25..230d353 100644 --- a/variants/Copycat/rules.html +++ b/variants/Copycat/rules.html @@ -3,6 +3,10 @@ it borrows powers from it and can move (and capture) like it.

    -

    Students from the UCF Chess Club (2020).

    +

    + Students from the + UCF Chess Club + (2020). +

    See also their Discord server :-)

    diff --git a/variants/Crazyhouse/rules.html b/variants/Crazyhouse/rules.html index 148015a..f4d239f 100644 --- a/variants/Crazyhouse/rules.html +++ b/variants/Crazyhouse/rules.html @@ -2,6 +2,8 @@

    Promoted pawns return on the board as pawns.

    - - lichess page. - +

    + + lichess page. + +

    diff --git a/variants/Cwda/complete_rules.html b/variants/Cwda/complete_rules.html index 9114c05..2276050 100644 --- a/variants/Cwda/complete_rules.html +++ b/variants/Cwda/complete_rules.html @@ -5,7 +5,6 @@ -

    Different Armies Rules

    @@ -30,7 +29,12 @@

    The Colorbound Clobberers

    -
    +
    + + + + +
    • Rook = bishop + dabbabah = "bede" (D),
    • @@ -53,8 +57,11 @@
    -
    -
    fen:8/8/8/3F4/8/8/8/8 b7,c6,b5,f5,d3,d7,b3,c4,e4,f3,e6,f7:
    +
    +
    +
    Moves of the Fad.
    @@ -67,7 +74,12 @@

    The Nutty Knights

    -
    +
    + + + + +
    • Rook = rook forward and sideways + king backwards = "charging rook" (G),
    • @@ -79,17 +91,29 @@
    • Queen = rook forward and sideways + knight forward + king = "colonel" (L).
    -
    -
    fen:8/8/8/8/3G4/8/8/8 d5,d6,d7,d8,c4,b4,a4,e4,f4,g4,h4,c3,d3,e3:
    -
    fen:8/8/8/8/4i3/8/8/8 d6,d2,f6,f2,d3,d5,f5,f3:
    +
    +
    +
    +
    +
    Moves of the Charging rook on the left, and of the Fibnif on the right.
    -
    -
    fen:8/8/8/8/3T4/8/8/8 b5,c6,e6,f5,c4,e4,c3,d3,e3:
    -
    fen:8/8/8/8/4c3/8/8/8 e5,e6,e7,e8,d4,c4,b4,a4,f4,g4,h4,d6,c5,f6,g5,d5,f5,d3,e3,f3:
    +
    +
    +
    +
    +
    Moves of the Charging knight on the left, and of the Colonel on the right.
    @@ -97,7 +121,12 @@

    The Remarkable Rookies

    -
    +
    + + + + +
    • Rook = rook limited to 4 squares = "short rook" (S),
    • @@ -106,9 +135,15 @@
    • Queen = rook + knight = "chancellor" (O).
    -
    -
    fen:8/8/8/3y4/8/8/8/8 d3,b5,d7,f5,c5,d6,e5,d4:
    -
    fen:8/8/8/4H3/8/8/8/8 c5,e7,g5,e3,b5,e8,h5,e2,d4,d6,f6,f4:
    +
    +
    +
    +
    +
    Moves of the Woody rook on the left, and of the Half-duck on the right.
    @@ -120,7 +155,12 @@

    Source

    -

    Chess with different armies on chessvariants.com.

    +

    + + Chess with different armies + + on chessvariants.com. +

    diff --git a/variants/Cwda/rules.html b/variants/Cwda/rules.html index cbd2d72..dac6d17 100644 --- a/variants/Cwda/rules.html +++ b/variants/Cwda/rules.html @@ -5,8 +5,10 @@ .

    - - Full rules description. - +

    + + Full rules description. + +

    Ralph Betza (1996).

    diff --git a/variants/Dark/rules.html b/variants/Dark/rules.html index 137a626..66d2828 100644 --- a/variants/Dark/rules.html +++ b/variants/Dark/rules.html @@ -2,8 +2,10 @@

    Win by capturing the enemy king.

    - - Wikipedia page. - +

    + + Wikipedia page. + +

    Jens Baek Nielsen (1997).

    diff --git a/variants/Doublemove/rules.html b/variants/Doublemove/rules.html index 5ac21d4..2a74cbf 100644 --- a/variants/Doublemove/rules.html +++ b/variants/Doublemove/rules.html @@ -1,7 +1,9 @@

    After the initial white move, each player moves twice on each turn.

    - - chessvariants page. - +

    + + chessvariants page. + +

    Albert Fortis (1922).

    diff --git a/variants/Giveaway/rules.html b/variants/Giveaway/rules.html index 3e257bd..54e40aa 100644 --- a/variants/Giveaway/rules.html +++ b/variants/Giveaway/rules.html @@ -1,5 +1,7 @@

    Win by losing all your material, or get stalemated.

    - - lichess page. - +

    + + lichess page. + +

    diff --git a/variants/Hex/rules.html b/variants/Hex/rules.html index 15a91b1..b4d7628 100644 --- a/variants/Hex/rules.html +++ b/variants/Hex/rules.html @@ -1,11 +1,15 @@

    Win by connecting both edges of your color.

    - - Detailed rules. - +

    + + Detailed rules. + +

    - - A Strategy Guide. - +

    + + A Strategy Guide. + +

    Piet Hein (1942).

    diff --git a/variants/Madrasi/rules.html b/variants/Madrasi/rules.html index 741869c..96627ff 100644 --- a/variants/Madrasi/rules.html +++ b/variants/Madrasi/rules.html @@ -1,7 +1,9 @@

    Pieces of same nature attacking each other are immobilized.

    - - Wikipedia page. - +

    + + Wikipedia page. + +

    Abdul J. Karwathar (1979).

    diff --git a/variants/Progressive/rules.html b/variants/Progressive/rules.html index 0521495..b957f45 100644 --- a/variants/Progressive/rules.html +++ b/variants/Progressive/rules.html @@ -3,6 +3,8 @@ then White play 3, and so on.

    - - Wikipedia page. - +

    + + Wikipedia page. + +

    diff --git a/variants/Recycle/rules.html b/variants/Recycle/rules.html index ceea70c..badd18b 100644 --- a/variants/Recycle/rules.html +++ b/variants/Recycle/rules.html @@ -3,8 +3,10 @@ can be self-captured and dropped later in the game.

    - - chessvariants page. - +

    + + chessvariants page. + +

    Robert Huber (2000).

    diff --git a/variants/Refusal/rules.html b/variants/Refusal/rules.html index 5c0b533..0eadaef 100644 --- a/variants/Refusal/rules.html +++ b/variants/Refusal/rules.html @@ -3,8 +3,10 @@ Different pawn promotions count as different moves.

    - - chessvariants page. - +

    + + chessvariants page. + +

    Fred Galvin (1958).

    diff --git a/variants/Rifle/rules.html b/variants/Rifle/rules.html index 650264b..79084a5 100644 --- a/variants/Rifle/rules.html +++ b/variants/Rifle/rules.html @@ -1,7 +1,9 @@

    Pieces capture (as usual) without moving.

    - - chessvariants page. - +

    + + chessvariants page. + +

    William Buehler Seabrook (1921).

    diff --git a/variants/Suction/rules.html b/variants/Suction/rules.html index a9cfb2e..9ca71e4 100644 --- a/variants/Suction/rules.html +++ b/variants/Suction/rules.html @@ -5,8 +5,10 @@

    Win by bringing the enemy king on your first rank.

    - - chessvariants page. - +

    + + chessvariants page. + +

    Nathaniel Virgo (2018).

    diff --git a/variants/_Antiking/rules.html b/variants/_Antiking/rules.html index e850c5e..e52edbb 100644 --- a/variants/_Antiking/rules.html +++ b/variants/_Antiking/rules.html @@ -18,8 +18,10 @@ - - chessvariants page. - +

    + + chessvariants page. + +

    Peter Aronson (2002).

    -- 2.44.0 From 5212758164eaa08e382b7bc281f87999c8af352b Mon Sep 17 00:00:00 2001 From: Benjamin Auder Date: Sat, 30 Dec 2023 20:58:25 +0100 Subject: [PATCH 04/16] Draft Diamond variant --- base_rules.js | 15 ++++-- variants.js | 2 +- variants/Diamond/class.js | 96 +++++++++++++++++++++++++++++++++++++ variants/Diamond/rules.html | 13 +++++ variants/Diamond/style.css | 1 + 5 files changed, 122 insertions(+), 5 deletions(-) create mode 100644 variants/Diamond/class.js create mode 100644 variants/Diamond/rules.html create mode 100644 variants/Diamond/style.css diff --git a/base_rules.js b/base_rules.js index 757707d..0f89cc4 100644 --- a/base_rules.js +++ b/base_rules.js @@ -579,11 +579,18 @@ export default class ChessRules { // Get SVG board (background, no pieces) getSvgChessboard() { - const flipped = this.flippedBoard; let board = ` `; + board += this.getBaseSvgChessboard(); + board += ""; + 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)) @@ -605,7 +612,6 @@ export default class ChessRules { />`; } } - board += ""; return board; } @@ -2341,10 +2347,11 @@ export default class ChessRules { if (this.options["teleport"]) { if ( this.subTurnTeleport == 1 && - move.vanish.length > move.appear.length && + move.vanish.length == 2 && + move.appear.length == 1 && move.vanish[1].c == this.turn ) { - const v = move.vanish[move.vanish.length - 1]; + const v = move.vanish[1]; this.captured = {x: v.x, y: v.y, c: v.c, p: v.p}; this.subTurnTeleport = 2; return; diff --git a/variants.js b/variants.js index 524538c..c9cdc98 100644 --- a/variants.js +++ b/variants.js @@ -41,7 +41,7 @@ const variants = [ {name: 'Cylinder', desc: 'Neverending rows'}, {name: 'Cwda', desc: 'New teams', disp: 'Different armies'}, {name: 'Dark', desc: 'In the shadow'}, -// {name: 'Diamond', desc: 'Rotating board'}, + {name: 'Diamond', desc: 'Rotating board'}, // {name: 'Dice', desc: 'Roll the dice'}, // {name: 'Discoduel', desc: 'Enter the disco', disp: 'Disco Duel'}, // {name: 'Dobutsu', desc: "Let's catch the Lion!"}, diff --git a/variants/Diamond/class.js b/variants/Diamond/class.js new file mode 100644 index 0000000..5145184 --- /dev/null +++ b/variants/Diamond/class.js @@ -0,0 +1,96 @@ +import ChessRules from "/base_rules.js"; +import {ArrayFun} from "/utils/array.js"; +import {Random} from "/utils/alea.js"; + +export default class DiamondRules extends ChessRules { + + get hasFlags() { + return false; + } + + get hasEnpassant() { + return false; + } + + getSvgChessboard() { + const diagonal = 10 * this.size.y * Math.sqrt(2); + const halfDiag = 0.5 * diagonal; + const deltaTrans = 10 * this.size.y * (Math.sqrt(2) - 1) / 2; + let board = ` + `; + board += ``; + board += this.getBaseSvgChessboard(); + board += ""; + return board; + } + + getPieceWidth(rwidth) { + return (0.95 * rwidth / (Math.sqrt(2) * this.size.y)); + } + + getPixelPosition(i, j, r) { + if (i < 0 || j < 0 || typeof i == "string") + return super.getPixelPosition(i, j, r); + const sqSize = this.getPieceWidth(r.width) / 0.95; + const flipped = this.flippedBoard; + i = (flipped ? this.size.x - 1 - i : i); + j = (flipped ? this.size.y - 1 - j : j); + const sq2 = Math.sqrt(2); + const shift = [- sqSize / 2, sqSize * (sq2 - 1) / 2]; + const x = (j - i) * sqSize / sq2 + shift[0] + r.width / 2; + const y = (i + j) * sqSize / sq2 + shift[1]; + return [r.x + x, r.y + y]; + } + + genRandInitBaseFen() { + if (this.options["randomness"] == 0) { + return { + fen: "krbp4/rqnp4/nbpp4/pppp4/4PPPP/4PPBN/4PNQR/4PBRK", + o: {} + }; + } + let pieces = { w: new Array(8), b: new Array(8) }; + for (let c of ["w", "b"]) { + if (c == 'b' && options.randomness == 1) { + pieces['b'] = pieces['w']; + break; + } + // Get random squares for every piece, totally freely + let positions = Random.shuffle(ArrayFun.range(8)); + const composition = ['b', 'b', 'r', 'r', 'n', 'n', 'k', 'q']; + const rem2 = positions[0] % 2; + if (rem2 == positions[1] % 2) { + // Fix bishops (on different colors) + for (let i=2; i<8; i++) { + if (positions[i] % 2 != rem2) { + [positions[1], positions[i]] = [positions[i], positions[1]]; + break; + } + } + } + for (let i = 0; i < 8; i++) + pieces[c][positions[i]] = composition[i]; + } + const fen = ( + pieces["b"].slice(0, 3).join("") + "p4/" + + pieces["b"].slice(3, 6).join("") + "p4/" + + pieces["b"].slice(6, 8).join("") + "pp4/" + + "pppp4/4PPPP/" + + "4PP" + pieces["w"].slice(6, 8).reverse().join("").toUpperCase() + "/" + + "4P" + pieces["w"].slice(3, 6).reverse().join("").toUpperCase() + "/" + + "4P" + pieces["w"].slice(0, 3).reverse().join("").toUpperCase()); + return { fen: fen, o: {} }; + } + + pieces(color, x, y) { + let res = super.pieces(color, x, y); + const pawnShift = this.getPawnShift(color || 'w'); + res['p'].moves = [{steps: [[pawnShift, pawnShift]], range: 1}]; + res['p'].attack = [{steps: [[0, pawnShift], [pawnShift, 0]], range: 1}]; + return res; + } + +}; diff --git a/variants/Diamond/rules.html b/variants/Diamond/rules.html new file mode 100644 index 0000000..9f172b1 --- /dev/null +++ b/variants/Diamond/rules.html @@ -0,0 +1,13 @@ +

    The board is rotated by 45°, and then the game follow usual rules.

    + +

    Pawns move forward "one diagonal", and capture forward "orthogonally".

    + +

    + See + + Diamond Chess + + on chessvariants.com. +

    + +

    James Alexander Porterfield Rynd (1886).

    diff --git a/variants/Diamond/style.css b/variants/Diamond/style.css new file mode 100644 index 0000000..a3550bc --- /dev/null +++ b/variants/Diamond/style.css @@ -0,0 +1 @@ +@import url("/base_pieces.css"); -- 2.44.0 From d01282a527e60af95f2a71deee1fbac9c0dd26be Mon Sep 17 00:00:00 2001 From: Benjamin Auder Date: Mon, 1 Jan 2024 08:51:47 +0100 Subject: [PATCH 05/16] Draft Dice chess --- variants.js | 2 +- variants/Dice/class.js | 108 +++++++++++++++++++++++++++++++++++++++ variants/Dice/rules.html | 3 ++ variants/Dice/style.css | 12 +++++ 4 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 variants/Dice/class.js create mode 100644 variants/Dice/rules.html create mode 100644 variants/Dice/style.css diff --git a/variants.js b/variants.js index c9cdc98..cad081a 100644 --- a/variants.js +++ b/variants.js @@ -42,7 +42,7 @@ const variants = [ {name: 'Cwda', desc: 'New teams', disp: 'Different armies'}, {name: 'Dark', desc: 'In the shadow'}, {name: 'Diamond', desc: 'Rotating board'}, -// {name: 'Dice', desc: 'Roll the dice'}, + {name: 'Dice', desc: 'Roll the dice'}, // {name: 'Discoduel', desc: 'Enter the disco', disp: 'Disco Duel'}, // {name: 'Dobutsu', desc: "Let's catch the Lion!"}, // {name: 'Doublearmy', desc: '64 pieces on the board', disp: 'Double Army'}, diff --git a/variants/Dice/class.js b/variants/Dice/class.js new file mode 100644 index 0000000..8c3eed4 --- /dev/null +++ b/variants/Dice/class.js @@ -0,0 +1,108 @@ +import ChessRules from "/base_rules.js"; +import {Random} from "/utils/alea.js"; + +export default class DiceRules extends ChessRules { + + static get Options() { + let res = C.Options; + res.select["defaut"] = 2; + return { + select: res.select, + input: [ + { + label: "Biased alea", + variable: "biased", + type: "checkbox", + defaut: true + }, + { + label: "Falling pawn", + variable: "pawnfall", + type: "checkbox", + defaut: false + } + ], + styles: [ + "atomic", + "capture", + "crazyhouse", + "cylinder", + "madrasi", + "recycle", + "rifle", + "zen" + ] + }; + } + + getPartFen(o) { + let toplay = ''; + if (o.init) { + let canMove = (this.options["biased"] + ? Array(8).fill('p').concat(Array(2).fill('n')) + : ['p', 'n']); + toplay = canMove[Random.randInt(canMove.length)]; + } + return Object.assign( + { toplay: (o.init ? toplay : this.getRandomPiece(this.turn)) }, + super.getPartFen(o) + ); + } + + constructor(o) { + super(o); + this.afterPlay = (move_s, newTurn, ops) => { + // Movestack contains only one move: + move_s[0].toplay = this.getRandomPiece(this.turn); + super.displayMessage(this.message, move_s[0].toplay); + o.afterPlay(move_s, newTurn, ops); + }; + } + + setOtherVariables(fenParsed) { + super.setOtherVariables(fenParsed); + this.toplay = fenParsed.toplay; + this.message = document.createElement("div"); + C.AddClass_es(this.message, "piece-text"); + this.message.innerHTML = this.toplay; + let container = document.getElementById(this.containerId); + container.appendChild(this.message); + } + + getRandomPiece(color) { + // Find pieces which can move and roll a (biased) dice + let canMove = []; + for (let i=0; i<8; i++) { + for (let j=0; j<8; j++) { + if (this.board[i][j] != "" && this.getColor(i, j) == color) { + const piece = this.getPiece(i, j); + if (this.findDestSquares([i, j], {one: true})) + canMove.push(piece); + } + } + } + if (!this.options["biased"]) + canMove = [...new Set(canMove)]; + return canMove[Random.randInt(canMove.length)]; + } + + postProcessPotentialMoves(moves) { + return super.postProcessPotentialMoves(moves).filter(m => { + return ( + (m.appear.length >= 1 && m.appear[0].p == this.toplay) || + (m.vanish.length >= 1 && m.vanish[0].p == this.toplay) + ); + }); + } + + filterValid(moves) { + return moves; + } + + playReceivedMove(moves, callback) { + this.toplay = moves[0].toplay; //only one move + super.displayMessage(this.message, this.toplay); + super.playReceivedMove(moves, callback); + } + +}; diff --git a/variants/Dice/rules.html b/variants/Dice/rules.html new file mode 100644 index 0000000..04e8682 --- /dev/null +++ b/variants/Dice/rules.html @@ -0,0 +1,3 @@ +

    Play the piece type determined by a dice roll.

    + +

    There is no check or checkmate: the goal is to capture the king.

    diff --git a/variants/Dice/style.css b/variants/Dice/style.css new file mode 100644 index 0000000..5881bc3 --- /dev/null +++ b/variants/Dice/style.css @@ -0,0 +1,12 @@ +@import url("/base_pieces.css"); + +div.piece-text { + position: relative; + margin-top: 15px; + width: 100%; + text-align: center; + background-color: transparent; + color: darkred; + font-weight: bold; + font-size: 2em; +} -- 2.44.0 From 7fbcb53de45ba7b7aed99d6087928779713810b1 Mon Sep 17 00:00:00 2001 From: Benjamin Auder Date: Mon, 1 Jan 2024 16:34:18 +0100 Subject: [PATCH 06/16] update --- variants/Dice/class.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/variants/Dice/class.js b/variants/Dice/class.js index 8c3eed4..02e4f6d 100644 --- a/variants/Dice/class.js +++ b/variants/Dice/class.js @@ -54,7 +54,8 @@ export default class DiceRules extends ChessRules { this.afterPlay = (move_s, newTurn, ops) => { // Movestack contains only one move: move_s[0].toplay = this.getRandomPiece(this.turn); - super.displayMessage(this.message, move_s[0].toplay); + super.displayMessage( + this.message, "To play: " + move_s[0].toplay.toUpperCase()); o.afterPlay(move_s, newTurn, ops); }; } @@ -64,7 +65,7 @@ export default class DiceRules extends ChessRules { this.toplay = fenParsed.toplay; this.message = document.createElement("div"); C.AddClass_es(this.message, "piece-text"); - this.message.innerHTML = this.toplay; + this.message.innerHTML = "To play: " + this.toplay.toUpperCase(); let container = document.getElementById(this.containerId); container.appendChild(this.message); } @@ -101,7 +102,8 @@ export default class DiceRules extends ChessRules { playReceivedMove(moves, callback) { this.toplay = moves[0].toplay; //only one move - super.displayMessage(this.message, this.toplay); + super.displayMessage( + this.message, "To play: " + this.toplay.toUpperCase()); super.playReceivedMove(moves, callback); } -- 2.44.0 From 04d93b7bb3b64ecdf3fb7219eee42879f0200b88 Mon Sep 17 00:00:00 2001 From: Benjamin Auder Date: Tue, 2 Jan 2024 13:08:07 +0100 Subject: [PATCH 07/16] update --- variants/Dice/class.js | 36 +++++++++++++++++++++++++++++++----- variants/Dice/style.css | 13 ++++++++++++- 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/variants/Dice/class.js b/variants/Dice/class.js index 02e4f6d..1bb6f1f 100644 --- a/variants/Dice/class.js +++ b/variants/Dice/class.js @@ -54,20 +54,47 @@ export default class DiceRules extends ChessRules { this.afterPlay = (move_s, newTurn, ops) => { // Movestack contains only one move: move_s[0].toplay = this.getRandomPiece(this.turn); - super.displayMessage( - this.message, "To play: " + move_s[0].toplay.toUpperCase()); + this.toplay = move_s[0].toplay; + this.displayMessage(move_s[0].toplay, + C.GetOppTurn(move_s[0].appear[0].c)); o.afterPlay(move_s, newTurn, ops); }; } + static get PieceToUnicode() { + return { + 'K': "♔", + 'Q': "♕", + 'R': "♖", + 'B': "♗", + 'N': "♘", + 'P': "♙", + 'k': "♚", + 'q': "♛", + 'r': "♜", + 'b': "♝", + 'n': "♞", + 'p': "♟" + }; + } + + displayMessage(piece, color) { + if (color == 'w') + piece = piece.toUpperCase(); + super.displayMessage(this.message, + 'to play: ' + + '' + V.PieceToUnicode[piece] + '' + ); + } + setOtherVariables(fenParsed) { super.setOtherVariables(fenParsed); this.toplay = fenParsed.toplay; this.message = document.createElement("div"); C.AddClass_es(this.message, "piece-text"); - this.message.innerHTML = "To play: " + this.toplay.toUpperCase(); let container = document.getElementById(this.containerId); container.appendChild(this.message); + this.displayMessage(this.toplay, fenParsed.turn); } getRandomPiece(color) { @@ -102,8 +129,7 @@ export default class DiceRules extends ChessRules { playReceivedMove(moves, callback) { this.toplay = moves[0].toplay; //only one move - super.displayMessage( - this.message, "To play: " + this.toplay.toUpperCase()); + this.displayMessage(this.toplay, C.GetOppTurn(moves[0].appear[0].c)); super.playReceivedMove(moves, callback); } diff --git a/variants/Dice/style.css b/variants/Dice/style.css index 5881bc3..c9ed898 100644 --- a/variants/Dice/style.css +++ b/variants/Dice/style.css @@ -1,5 +1,11 @@ @import url("/base_pieces.css"); +/* doesn't work: +@font-face { + font-family: chess-font; + src: url(/assets/FreeSerifBold-rdMp.otf); +} */ + div.piece-text { position: relative; margin-top: 15px; @@ -8,5 +14,10 @@ div.piece-text { background-color: transparent; color: darkred; font-weight: bold; - font-size: 2em; + font-size: 1.7em; } + +/* +div.piece-text > span.symb { + font-family: chess-font; +} */ -- 2.44.0 From 03883a0d1495bc6e6fadc3a11aa99286aba5c9e1 Mon Sep 17 00:00:00 2001 From: Benjamin Auder Date: Tue, 2 Jan 2024 16:03:28 +0100 Subject: [PATCH 08/16] Fix Dice display --- variants/Dice/class.js | 32 ++++++++++++-------------------- variants/Dice/style.css | 11 ++++++----- 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/variants/Dice/class.js b/variants/Dice/class.js index 1bb6f1f..53836eb 100644 --- a/variants/Dice/class.js +++ b/variants/Dice/class.js @@ -61,29 +61,21 @@ export default class DiceRules extends ChessRules { }; } - static get PieceToUnicode() { - return { - 'K': "♔", - 'Q': "♕", - 'R': "♖", - 'B': "♗", - 'N': "♘", - 'P': "♙", - 'k': "♚", - 'q': "♛", - 'r': "♜", - 'b': "♝", - 'n': "♞", - 'p': "♟" - }; - } - displayMessage(piece, color) { - if (color == 'w') - piece = piece.toUpperCase(); + if (color == 'b') { + const blackPieceToCode = { + 'k': 'l', + 'p': 'o', + 'n': 'm', + 'b': 'v', + 'q': 'w', + 'r': 't' + }; + piece = blackPieceToCode[piece]; + } super.displayMessage(this.message, 'to play: ' + - '' + V.PieceToUnicode[piece] + '' + '' + piece + '' ); } diff --git a/variants/Dice/style.css b/variants/Dice/style.css index c9ed898..ad11010 100644 --- a/variants/Dice/style.css +++ b/variants/Dice/style.css @@ -1,10 +1,9 @@ @import url("/base_pieces.css"); -/* doesn't work: @font-face { font-family: chess-font; - src: url(/assets/FreeSerifBold-rdMp.otf); -} */ + src: url(/assets/MERIFONT.TTF); +} div.piece-text { position: relative; @@ -17,7 +16,9 @@ div.piece-text { font-size: 1.7em; } -/* div.piece-text > span.symb { font-family: chess-font; -} */ + display: inline-block; + position: relative; + top: 5px; +} -- 2.44.0 From 130a166fd08355be5f2dfc923777c1c6d03f09ce Mon Sep 17 00:00:00 2001 From: Benjamin Auder Date: Wed, 3 Jan 2024 01:40:00 +0100 Subject: [PATCH 09/16] Chakart: fixing attempt --- variants/Chakart/class.js | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/variants/Chakart/class.js b/variants/Chakart/class.js index 2b502b6..3454d8f 100644 --- a/variants/Chakart/class.js +++ b/variants/Chakart/class.js @@ -130,6 +130,12 @@ export default class ChakartRules extends ChessRules { ); } + isKing(x, y, p) { + if (!p) + p = this.getPiece(x, y); + return ['k', 'l'].includes(p); + } + genRandInitBaseFen() { const s = FenUtil.setupPieces( ['r', 'n', 'b', 'q', 'k', 'b', 'n', 'r'], @@ -630,19 +636,25 @@ export default class ChakartRules extends ChessRules { }); break; case "koopa": - // Reverse move + // Reverse move, if possible em = new Move({ - appear: [ - new PiPo({ - x: move.start.x, y: move.start.y, c: color, p: move.appear[0].p - }) - ], + appear: [], vanish: [ new PiPo({ x: move.end.x, y: move.end.y, c: color, p: move.appear[0].p }) - ] + ], + end: {x: move.start.x, y: move.start.y} //may be irrelevant }); + em.koopa = true; //avoid applying effect + if (move.vanish.length == 0) + // After toadette+drop, just erase piece + break; + em.appear.push( + new PiPo({ + x: move.start.x, y: move.start.y, c: color, p: move.appear[0].p + }) + ); if (this.board[move.start.x][move.start.y] != "") { // Pawn or knight let something on init square em.vanish.push(new PiPo({ @@ -652,7 +664,6 @@ export default class ChakartRules extends ChessRules { p: this.getPiece(move.start.x, move.start.y) })); } - em.koopa = true; //avoid applying effect break; case "chomp": // Eat piece -- 2.44.0 From 3232aba3419f129c70d5edd9a4ded1fefc146ea0 Mon Sep 17 00:00:00 2001 From: Benjamin Auder Date: Wed, 3 Jan 2024 15:38:58 +0100 Subject: [PATCH 10/16] Add Discoduel, draft Dobutsu, some code cleaning --- base_rules.js | 20 +- pieces/Dobutsu/LICENSE.txt | 395 ++++++++++++++++++++++++++++++++ pieces/Dobutsu/README.md | 13 ++ pieces/Dobutsu/chick.svg | 139 +++++++++++ pieces/Dobutsu/elephant.svg | 176 ++++++++++++++ pieces/Dobutsu/giraffe.svg | 186 +++++++++++++++ pieces/Dobutsu/hen.svg | 156 +++++++++++++ pieces/Dobutsu/lion.svg | 201 ++++++++++++++++ pieces/Dobutsu/rev_chick.svg | 139 +++++++++++ pieces/Dobutsu/rev_elephant.svg | 176 ++++++++++++++ pieces/Dobutsu/rev_giraffe.svg | 186 +++++++++++++++ pieces/Dobutsu/rev_hen.svg | 156 +++++++++++++ pieces/Dobutsu/rev_lion.svg | 201 ++++++++++++++++ utils/array.js | 8 +- variants.js | 4 +- variants/Avalanche/class.js | 2 +- variants/Chaining/class.js | 4 +- variants/Clorange/class.js | 13 +- variants/Convert/class.js | 4 +- variants/Coregal/class.js | 4 +- variants/Discoduel/class.js | 51 +++++ variants/Discoduel/rules.html | 5 + variants/Discoduel/style.css | 1 + variants/Dobutsu/class.js | 100 ++++++++ variants/Dobutsu/rules.html | 12 + variants/Dobutsu/style.css | 34 +++ 26 files changed, 2355 insertions(+), 31 deletions(-) create mode 100644 pieces/Dobutsu/LICENSE.txt create mode 100644 pieces/Dobutsu/README.md create mode 100644 pieces/Dobutsu/chick.svg create mode 100644 pieces/Dobutsu/elephant.svg create mode 100644 pieces/Dobutsu/giraffe.svg create mode 100644 pieces/Dobutsu/hen.svg create mode 100644 pieces/Dobutsu/lion.svg create mode 100644 pieces/Dobutsu/rev_chick.svg create mode 100644 pieces/Dobutsu/rev_elephant.svg create mode 100644 pieces/Dobutsu/rev_giraffe.svg create mode 100644 pieces/Dobutsu/rev_hen.svg create mode 100644 pieces/Dobutsu/rev_lion.svg create mode 100644 variants/Discoduel/class.js create mode 100644 variants/Discoduel/rules.html create mode 100644 variants/Discoduel/style.css create mode 100644 variants/Dobutsu/class.js create mode 100644 variants/Dobutsu/rules.html create mode 100644 variants/Dobutsu/style.css diff --git a/base_rules.js b/base_rules.js index 0f89cc4..217d055 100644 --- a/base_rules.js +++ b/base_rules.js @@ -338,7 +338,7 @@ export default class ChessRules { getReserveFen(o) { if (o.init) - return "000000000000"; + return Array(2 * V.ReserveArray.length).fill('0').join(""); return ( ['w', 'b'].map(c => Object.values(this.reserve[c]).join("")).join("") ); @@ -416,14 +416,14 @@ export default class ChessRules { } // Some additional variables from FEN (variant dependant) - setOtherVariables(fenParsed, pieceArray) { + setOtherVariables(fenParsed) { // 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, pieceArray); + this.initReserves(fenParsed.reserve); if (this.options["crazyhouse"]) this.initIspawn(fenParsed.ispawn); if (this.options["teleport"]) { @@ -441,14 +441,16 @@ export default class ChessRules { } // ordering as in pieces() p,r,n,b,q,k - initReserves(reserveStr, pieceArray) { - if (!pieceArray) - pieceArray = ['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 = pieceArray.length; + const L = V.ReserveArray.length; this.reserve = { - w: ArrayFun.toObject(pieceArray, counts.slice(0, L)), - b: ArrayFun.toObject(pieceArray, counts.slice(L, 2 * L)) + w: ArrayFun.toObject(V.ReserveArray, counts.slice(0, L)), + b: ArrayFun.toObject(V.ReserveArray, counts.slice(L, 2 * L)) }; } diff --git a/pieces/Dobutsu/LICENSE.txt b/pieces/Dobutsu/LICENSE.txt new file mode 100644 index 0000000..2f244ac --- /dev/null +++ b/pieces/Dobutsu/LICENSE.txt @@ -0,0 +1,395 @@ +Attribution 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More_considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution 4.0 International Public License ("Public License"). To the +extent this Public License may be interpreted as a contract, You are +granted the Licensed Rights in consideration of Your acceptance of +these terms and conditions, and the Licensor grants You such rights in +consideration of benefits the Licensor receives from making the +Licensed Material available under these terms and conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + d. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + e. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + f. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + g. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + h. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + i. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + j. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + k. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part; and + + b. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + 4. If You Share Adapted Material You produce, the Adapter's + License You apply must not prevent recipients of the Adapted + Material from complying with this Public License. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material; and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + + +======================================================================= + +Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the “Licensor.” The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses. + +Creative Commons may be contacted at creativecommons.org. diff --git a/pieces/Dobutsu/README.md b/pieces/Dobutsu/README.md new file mode 100644 index 0000000..73ed708 --- /dev/null +++ b/pieces/Dobutsu/README.md @@ -0,0 +1,13 @@ +[Couch Tomato - I presume] + +I recreated all of the original [Doubutsu](https://en.wikipedia.org/wiki/D%C5%8Dbutsu_sh%C5%8Dgi) pieces in Inkscape SVG format. + +Credits: the original Doubutsu pieces were created by [Madoka Kitato](https://en.wikipedia.org/wiki/Madoka_Kitao). + +(also: [screenshot of the gshogi version](https://raw.githubusercontent.com/Ka-hu/shogi-pieces/master/_screenshots/scrot_doubutsu_gshogi.png)) + +![doubutsu screenshot](https://raw.githubusercontent.com/Ka-hu/shogi-pieces/master/_screenshots/scrot_doubutsu_xboard.png) + +## License + +Where it's not stated otherwise, my work is lincensed under [CC-BY-4.0](https://choosealicense.com/licenses/cc-by-4.0) diff --git a/pieces/Dobutsu/chick.svg b/pieces/Dobutsu/chick.svg new file mode 100644 index 0000000..69358c7 --- /dev/null +++ b/pieces/Dobutsu/chick.svg @@ -0,0 +1,139 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pieces/Dobutsu/elephant.svg b/pieces/Dobutsu/elephant.svg new file mode 100644 index 0000000..c7eb6dc --- /dev/null +++ b/pieces/Dobutsu/elephant.svg @@ -0,0 +1,176 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pieces/Dobutsu/giraffe.svg b/pieces/Dobutsu/giraffe.svg new file mode 100644 index 0000000..14a55a9 --- /dev/null +++ b/pieces/Dobutsu/giraffe.svg @@ -0,0 +1,186 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pieces/Dobutsu/hen.svg b/pieces/Dobutsu/hen.svg new file mode 100644 index 0000000..7256bc8 --- /dev/null +++ b/pieces/Dobutsu/hen.svg @@ -0,0 +1,156 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pieces/Dobutsu/lion.svg b/pieces/Dobutsu/lion.svg new file mode 100644 index 0000000..8324454 --- /dev/null +++ b/pieces/Dobutsu/lion.svg @@ -0,0 +1,201 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pieces/Dobutsu/rev_chick.svg b/pieces/Dobutsu/rev_chick.svg new file mode 100644 index 0000000..bbefcfc --- /dev/null +++ b/pieces/Dobutsu/rev_chick.svg @@ -0,0 +1,139 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pieces/Dobutsu/rev_elephant.svg b/pieces/Dobutsu/rev_elephant.svg new file mode 100644 index 0000000..c8b0b3c --- /dev/null +++ b/pieces/Dobutsu/rev_elephant.svg @@ -0,0 +1,176 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pieces/Dobutsu/rev_giraffe.svg b/pieces/Dobutsu/rev_giraffe.svg new file mode 100644 index 0000000..f6eb024 --- /dev/null +++ b/pieces/Dobutsu/rev_giraffe.svg @@ -0,0 +1,186 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pieces/Dobutsu/rev_hen.svg b/pieces/Dobutsu/rev_hen.svg new file mode 100644 index 0000000..e172f8b --- /dev/null +++ b/pieces/Dobutsu/rev_hen.svg @@ -0,0 +1,156 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pieces/Dobutsu/rev_lion.svg b/pieces/Dobutsu/rev_lion.svg new file mode 100644 index 0000000..33c11d3 --- /dev/null +++ b/pieces/Dobutsu/rev_lion.svg @@ -0,0 +1,201 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/utils/array.js b/utils/array.js index c2cb25f..af8462e 100644 --- a/utils/array.js +++ b/utils/array.js @@ -5,8 +5,12 @@ export const ArrayFun = { return [...Array(size1)].map(() => Array(size2).fill(initElem)); }, - range: function(max) { - return [...Array(max).keys()]; + range: function(min, max) { + if (!max) { + max = min; + min = 0; + } + return [...Array(max - min).keys()].map(k => k + min); }, toObject: function(keys, values) { diff --git a/variants.js b/variants.js index cad081a..f42033e 100644 --- a/variants.js +++ b/variants.js @@ -43,8 +43,8 @@ const variants = [ {name: 'Dark', desc: 'In the shadow'}, {name: 'Diamond', desc: 'Rotating board'}, {name: 'Dice', desc: 'Roll the dice'}, -// {name: 'Discoduel', desc: 'Enter the disco', disp: 'Disco Duel'}, -// {name: 'Dobutsu', desc: "Let's catch the Lion!"}, + {name: 'Discoduel', desc: 'Enter the disco', disp: 'Disco Duel'}, + {name: 'Dobutsu', desc: "Let's catch the Lion!"}, // {name: 'Doublearmy', desc: '64 pieces on the board', disp: 'Double Army'}, {name: 'Doublemove', desc: 'Double moves'}, // {name: 'Dynamo', desc: 'Push and pull'}, diff --git a/variants/Avalanche/class.js b/variants/Avalanche/class.js index ee80550..8a4981f 100644 --- a/variants/Avalanche/class.js +++ b/variants/Avalanche/class.js @@ -167,7 +167,7 @@ export default class AvalancheRules extends ChessRules { } } - atLeastOneMove(color, lastMove) { + atLeastOneMove(color) { if (this.subTurn == 0) return true; return super.atLeastOneMove(color); diff --git a/variants/Chaining/class.js b/variants/Chaining/class.js index 9d771da..4ae7208 100644 --- a/variants/Chaining/class.js +++ b/variants/Chaining/class.js @@ -20,8 +20,8 @@ export default class ChainingRules extends ChessRules { return true; //self captures induce chaining } - setOtherVariables(fenParsed, pieceArray) { - super.setOtherVariables(fenParsed, pieceArray); + setOtherVariables(fenParsed) { + super.setOtherVariables(fenParsed); // Stack of "last move" only for intermediate chaining this.lastMoveEnd = []; } diff --git a/variants/Clorange/class.js b/variants/Clorange/class.js index 485bbd6..e8506db 100644 --- a/variants/Clorange/class.js +++ b/variants/Clorange/class.js @@ -14,14 +14,6 @@ export default class ClorangeRules extends ChessRules { return true; } - getReserveFen(o) { - if (o.init) - return "00000000000000000000"; - return ( - ["w","b"].map(c => Object.values(this.reserve[c]).join("")).join("") - ); - } - pieces(color, x, y) { let res = super.pieces(color, x, y); res['s'] = {"class": "nv-pawn", moveas: "p"}; @@ -38,9 +30,8 @@ export default class ClorangeRules extends ChessRules { static get NV_PIECES() { return ['s', 'u', 'o', 'c', 't']; } - - setOtherVariables(fen) { - super.setOtherVariables(fen, V.V_PIECES.concat(V.NV_PIECES)); + static get ReserveArray() { + return V.V_PIECES.concat(V.NV_PIECES); } // Forbid non-violent pieces to capture diff --git a/variants/Convert/class.js b/variants/Convert/class.js index bc99c63..cd2d1a9 100644 --- a/variants/Convert/class.js +++ b/variants/Convert/class.js @@ -15,8 +15,8 @@ export default class ConvertRules extends ChessRules { return false; } - setOtherVariables(fenParsed, pieceArray) { - super.setOtherVariables(fenParsed, pieceArray); + setOtherVariables(fenParsed) { + super.setOtherVariables(fenParsed); // Stack of "last move" only for intermediate chaining this.lastMoveEnd = []; } diff --git a/variants/Coregal/class.js b/variants/Coregal/class.js index 23f67c7..bbc35a4 100644 --- a/variants/Coregal/class.js +++ b/variants/Coregal/class.js @@ -61,8 +61,8 @@ export default class CoregalRules extends ChessRules { ); } - setOtherVariables(fenParsed, pieceArray) { - super.setOtherVariables(fenParsed, pieceArray); + setOtherVariables(fenParsed) { + super.setOtherVariables(fenParsed); this.relPos = { 'w': { 'k': fenParsed.relpos[0], diff --git a/variants/Discoduel/class.js b/variants/Discoduel/class.js new file mode 100644 index 0000000..c081b31 --- /dev/null +++ b/variants/Discoduel/class.js @@ -0,0 +1,51 @@ +import ChessRules from "/base_rules.js"; +import {ArrayFun} from "/utils/array.js" + +export default class DiscoduelRules extends ChessRules { + + static get Options() { + return {}; //nothing would make sense + } + + get pawnPromotions() { + return ['p']; + } + + get hasFlags() { + return false; + } + + genRandInitBaseFen() { + return { + fen: "1n4n1/8/8/8/8/8/PPPPPPPP/8", + o: {} + }; + } + + getPotentialMovesFrom([x, y]) { + const moves = super.getPotentialMovesFrom([x, y]); + if (this.turn == 'b') + // Prevent pawn captures on last rank: + return moves.filter(m => m.vanish.length == 1 || m.vanish[1].x != 0); + return moves; + } + + filterValid(moves) { + return moves; + } + + getCurrentScore() { + // No real winning condition (promotions count...) + if ( + ArrayFun.range(1, this.size.x).every(row_idx => { + this.board[row_idx].every(square => square.charAt(0) != 'w') + }) + || + !this.atLeastOneMove(this.turn) + ) { + return "1/2"; + } + return "*"; + } + +}; diff --git a/variants/Discoduel/rules.html b/variants/Discoduel/rules.html new file mode 100644 index 0000000..490d279 --- /dev/null +++ b/variants/Discoduel/rules.html @@ -0,0 +1,5 @@ +

    + Eight pawns try to promote, while the knights attempts to prevent them. + A pawn reaching last rank does not transform, but become immune to captures. +

    +

    Goal: "promoting" as many pawns as possible.

    diff --git a/variants/Discoduel/style.css b/variants/Discoduel/style.css new file mode 100644 index 0000000..a3550bc --- /dev/null +++ b/variants/Discoduel/style.css @@ -0,0 +1 @@ +@import url("/base_pieces.css"); diff --git a/variants/Dobutsu/class.js b/variants/Dobutsu/class.js new file mode 100644 index 0000000..7632a17 --- /dev/null +++ b/variants/Dobutsu/class.js @@ -0,0 +1,100 @@ +import ChessRules from "/base_rules.js"; + +export default class DobutsuRules extends ChessRules { + + static get Options() { + return {}; + } + + get hasFlags() { + return false; + } + + get hasEnpassant() { + return false; + } + + pieces(color, x, y) { + const pawnShift = this.getPawnShift(color || 'w'); + // NOTE: classs change according to playerColor (orientation) + const mySide = (this.playerColor == color); + return { + 'c': { + "class": (mySide ? "" : "rev-") + "chick", + both: [{steps: [[pawnShift, 0]], range: 1}] + }, + 'h': { + "class": (mySide ? "" : "rev-") + "hen", + both: [ + { + steps: [ + [pawnShift, 1], [pawnShift, -1], + [0, 1], [0, -1], [1, 0], [-1, 0] + ], + range: 1 + } + ] + }, + 'e': { + "class": (mySide ? "" : "rev-") + "elephant", + both: [{steps: [[-1, 1], [-1, -1], [1, 1], [1, -1]], range: 1}] + }, + 'g': { + "class": (mySide ? "" : "rev-") + "giraffe", + both: [{steps: [[0, 1], [0, -1], [1, 0], [-1, 0]], range: 1}] + }, + 'l': { + "class": (mySide ? "" : "rev-") + "lion", + both: [{ + steps: [[-1, 1], [-1, -1], [1, 1], [1, -1], + [0, 1], [0, -1], [1, 0], [-1, 0]], + range: 1 + }] + } + }; + } + + isKing(x, y, p) { + if (!p) + p = this.getPiece(x, y); + return (p == 'l'); + } + + static get ReserveArray() { + return ['p', 'h', 'e', 'g']; + } + + constructor(o) { + o.options = {crazyhouse: true, taking: true}; + super(o); + } + + get pawnPromotions() { + return ['h']; + } + + genRandInitBaseFen() { + return { + fen: "gle/1c1/1C1/ELG", + o: {} + }; + } + + get size() { + return {x: 4, y: 4}; + } + + getCurrentScore(move_s) { + const res = super.getCurrentScore(move_s); + if (res != '*') + return res; + const oppCol = C.GetOppTurn(this.turn); + const oppLastRank = (oppCol == 'b' ? 3 : 0); + for (let j=0; j < this.size.y; j++) { + if (this.board[oppLastRank][j] == oppCol + 'l') + return (oppCol == 'w' ? "1-0" : "0-1"); + } + return "*"; + } + +}; diff --git a/variants/Dobutsu/rules.html b/variants/Dobutsu/rules.html new file mode 100644 index 0000000..45bbc5d --- /dev/null +++ b/variants/Dobutsu/rules.html @@ -0,0 +1,12 @@ +

    + Simplified Shogi game. Goal: capture the Lion. + Pieces move as indicated on them (red arrows). +

    + +

    Captured units can be landed on the board later.

    + +

    + + Wikipedia page + . +

    diff --git a/variants/Dobutsu/style.css b/variants/Dobutsu/style.css new file mode 100644 index 0000000..fb861f1 --- /dev/null +++ b/variants/Dobutsu/style.css @@ -0,0 +1,34 @@ +piece.chick { + background-image: url('/pieces/Dobutsu/chick.svg'); +} +piece.rev-chick { + background-image: url('/pieces/Dobutsu/rev_chick.svg'); +} + +piece.hen { + background-image: url('/pieces/Dobutsu/hen.svg'); +} +piece.rev-hen { + background-image: url('/pieces/Dobutsu/rev_hen.svg'); +} + +piece.elephant { + background-image: url('/pieces/Dobutsu/elephant.svg'); +} +piece.rev-elephant { + background-image: url('/pieces/Dobutsu/rev_elephant.svg'); +} + +piece.giraffe { + background-image: url('/pieces/Dobutsu/giraffe.svg'); +} +piece.rev-giraffe { + background-image: url('/pieces/Dobutsu/rev_giraffe.svg'); +} + +piece.lion { + background-image: url('/pieces/Dobutsu/lion.svg'); +} +piece.rev-lion { + background-image: url('/pieces/Dobutsu/rev_lion.svg'); +} -- 2.44.0 From c4d2eb5bdf1b23d8c4a9d09322f84a9e0da9d60c Mon Sep 17 00:00:00 2001 From: Benjamin Auder Date: Wed, 3 Jan 2024 17:10:33 +0100 Subject: [PATCH 11/16] Fix Dobutsu --- base_rules.js | 17 +++++++++-------- variants/Dobutsu/class.js | 21 ++++++++++----------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/base_rules.js b/base_rules.js index 217d055..9a364e8 100644 --- a/base_rules.js +++ b/base_rules.js @@ -465,7 +465,7 @@ export default class ChessRules { // VISUAL UTILS getPieceWidth(rwidth) { - return (rwidth / this.size.y); + return (rwidth / Math.max(this.size.x, this.size.y)); } getReserveSquareSize(rwidth, nbR) { @@ -856,9 +856,10 @@ export default class ChessRules { y = (this.playerColor == i ? y = r.height + 5 : - 5 - rsqSize); } else { - const sqSize = r.width / this.size.y; + 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; + 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]; @@ -2284,11 +2285,6 @@ export default class ChessRules { if (this.hasCastle) this.updateCastleFlags(move); if (this.options["crazyhouse"]) { - move.vanish.forEach(v => { - const square = C.CoordsToSquare({x: v.x, y: v.y}); - if (this.ispawn[square]) - delete this.ispawn[square]; - }); if (move.appear.length > 0 && move.vanish.length > 0) { // Assumption: something is moving const initSquare = C.CoordsToSquare(move.start); @@ -2307,6 +2303,11 @@ export default class ChessRules { delete this.ispawn[destSquare]; } } + move.vanish.forEach(v => { + const square = C.CoordsToSquare({x: v.x, y: v.y}); + if (this.ispawn[square]) + delete this.ispawn[square]; + }); } const minSize = Math.min(move.appear.length, move.vanish.length); if ( diff --git a/variants/Dobutsu/class.js b/variants/Dobutsu/class.js index 7632a17..29b0708 100644 --- a/variants/Dobutsu/class.js +++ b/variants/Dobutsu/class.js @@ -19,7 +19,7 @@ export default class DobutsuRules extends ChessRules { // NOTE: classs change according to playerColor (orientation) const mySide = (this.playerColor == color); return { - 'c': { + 'p': { "class": (mySide ? "" : "rev-") + "chick", both: [{steps: [[pawnShift, 0]], range: 1}] }, @@ -43,7 +43,7 @@ export default class DobutsuRules extends ChessRules { "class": (mySide ? "" : "rev-") + "giraffe", both: [{steps: [[0, 1], [0, -1], [1, 0], [-1, 0]], range: 1}] }, - 'l': { + 'k': { "class": (mySide ? "" : "rev-") + "lion", both: [{ steps: [[-1, 1], [-1, -1], [1, 1], [1, -1], @@ -54,16 +54,15 @@ export default class DobutsuRules extends ChessRules { }; } - isKing(x, y, p) { - if (!p) - p = this.getPiece(x, y); - return (p == 'l'); - } - static get ReserveArray() { return ['p', 'h', 'e', 'g']; } + updateReserve(color, piece, count) { + if (piece != 'k') + super.updateReserve(color, piece, count); + } + constructor(o) { o.options = {crazyhouse: true, taking: true}; super(o); @@ -75,13 +74,13 @@ export default class DobutsuRules extends ChessRules { genRandInitBaseFen() { return { - fen: "gle/1c1/1C1/ELG", + fen: "gke/1p1/1P1/EKG", o: {} }; } get size() { - return {x: 4, y: 4}; + return {x: 4, y: 3}; } getCurrentScore(move_s) { @@ -91,7 +90,7 @@ export default class DobutsuRules extends ChessRules { const oppCol = C.GetOppTurn(this.turn); const oppLastRank = (oppCol == 'b' ? 3 : 0); for (let j=0; j < this.size.y; j++) { - if (this.board[oppLastRank][j] == oppCol + 'l') + if (this.board[oppLastRank][j] == oppCol + 'k') return (oppCol == 'w' ? "1-0" : "0-1"); } return "*"; -- 2.44.0 From 4fcd7ab062f5250757804d633df01bd0d06da137 Mon Sep 17 00:00:00 2001 From: Benjamin Auder Date: Thu, 4 Jan 2024 10:23:47 +0100 Subject: [PATCH 12/16] Fix Discoduel --- variants/Discoduel/class.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/variants/Discoduel/class.js b/variants/Discoduel/class.js index c081b31..ec96a43 100644 --- a/variants/Discoduel/class.js +++ b/variants/Discoduel/class.js @@ -38,7 +38,9 @@ export default class DiscoduelRules extends ChessRules { // No real winning condition (promotions count...) if ( ArrayFun.range(1, this.size.x).every(row_idx => { - this.board[row_idx].every(square => square.charAt(0) != 'w') + return this.board[row_idx].every(square => { + return (!square || square.charAt(0) != 'w'); + }) }) || !this.atLeastOneMove(this.turn) -- 2.44.0 From d66135396f3a6e140947545630004ce11f8eee7b Mon Sep 17 00:00:00 2001 From: Benjamin Auder Date: Thu, 4 Jan 2024 10:37:28 +0100 Subject: [PATCH 13/16] Fix Dobutsu, extend Align4 --- variants/Align4/class.js | 19 +++++++++++++++++++ variants/Dobutsu/class.js | 15 ++++++++++----- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/variants/Align4/class.js b/variants/Align4/class.js index 09a79ed..f5b8f83 100644 --- a/variants/Align4/class.js +++ b/variants/Align4/class.js @@ -13,6 +13,14 @@ export default class Align4Rules extends ChessRules { {label: "Random", value: 1} ] }], + input: [ + { + label: "Pawn first", + variable: "pawnfirst", + type: "checkbox", + defaut: false + } + ], styles: ["atomic", "capture", "cylinder"] }; } @@ -39,6 +47,17 @@ export default class Align4Rules extends ChessRules { // Just do not update any reserve (infinite supply) updateReserve() {} + canDrop([c, p], [i, j]) { + return ( + this.board[i][j] == "" && + ( + p != "p" || this.options["pawnfirst"] || + (c == 'w' && i < this.size.x - 1) || + (c == 'b' && i > 0) + ) + ); + } + getCurrentScore(move_s) { const score = super.getCurrentScore(move_s); if (score != "*") diff --git a/variants/Dobutsu/class.js b/variants/Dobutsu/class.js index 29b0708..d8ceafa 100644 --- a/variants/Dobutsu/class.js +++ b/variants/Dobutsu/class.js @@ -87,11 +87,16 @@ export default class DobutsuRules extends ChessRules { const res = super.getCurrentScore(move_s); if (res != '*') return res; - const oppCol = C.GetOppTurn(this.turn); - const oppLastRank = (oppCol == 'b' ? 3 : 0); - for (let j=0; j < this.size.y; j++) { - if (this.board[oppLastRank][j] == oppCol + 'k') - return (oppCol == 'w' ? "1-0" : "0-1"); + for (let lastRank of [0, 3]) { + const color = (lastRank == 0 ? 'w' : 'b'); + for (let j=0; j < this.size.y; j++) { + if ( + this.board[lastRank][j] == color + 'k' && + !this.underAttack([lastRank, j], [C.GetOppTurn(color)]) + ) { + return (color == 'w' ? "1-0" : "0-1"); + } + } } return "*"; } -- 2.44.0 From 66ab134b7ab3ba00204fb316ba7636c904331d6c Mon Sep 17 00:00:00 2001 From: Benjamin Auder Date: Thu, 4 Jan 2024 11:19:10 +0100 Subject: [PATCH 14/16] Add Doublearmy. Start thinking about Dynamo --- README.md | 10 +- TODO | 3 - initialize.sh | 8 + pieces/black_commoner.svg | 105 ++++ pieces/white_commoner.svg | 94 +++ variants.js | 4 +- variants/Doublearmy/class.js | 43 ++ variants/Doublearmy/rules.html | 6 + variants/Doublearmy/style.css | 9 + variants/Dynamo/class.js | 921 ++++++++++++++++++++++++++++ variants/Dynamo/complete_rules.html | 142 +++++ variants/Dynamo/rules.html | 24 + variants/Dynamo/style.css | 1 + 13 files changed, 1359 insertions(+), 11 deletions(-) create mode 100755 initialize.sh create mode 100644 pieces/black_commoner.svg create mode 100644 pieces/white_commoner.svg create mode 100644 variants/Doublearmy/class.js create mode 100644 variants/Doublearmy/rules.html create mode 100644 variants/Doublearmy/style.css create mode 100644 variants/Dynamo/class.js create mode 100644 variants/Dynamo/complete_rules.html create mode 100644 variants/Dynamo/rules.html create mode 100644 variants/Dynamo/style.css diff --git a/README.md b/README.md index 4636ac4..0b900c5 100644 --- a/README.md +++ b/README.md @@ -9,12 +9,10 @@ PHP + Node.js + npm. ## Usage -```wget https://xogo.live/assets.zip && unzip assets.zip```
    -```wget https://xogo.live/extras.zip && unzip extras.zip```
    -Rename parameters.js.dist → parameters.js, and edit file.
    -```npm i``` +Initialisation (done once): -Generate some pieces:
    -```python generateSVG.py``` in pieces/Avalam +```./initialize.sh``` + +You may want to edit the parameters.js file. Then: ```./start.sh``` (and later, ```./stop.sh```) diff --git a/TODO b/TODO index fac46e3..8afe466 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,3 @@ -add variants : -Dark Racing Kings ? Checkered-Teleport ? - Hmm... non ? --> Otage, Emergo, Pacosako : fonction "buildPiece(arg1, arg2)" returns HTML element with 2 SVG or SVG + number ==> plus simple : deux classes, images superposées. diff --git a/initialize.sh b/initialize.sh new file mode 100755 index 0000000..b7a9f4f --- /dev/null +++ b/initialize.sh @@ -0,0 +1,8 @@ +!#/bin/sh + +wget https://xogo.live/assets.zip && unzip assets.zip +wget https://xogo.live/extras.zip && unzip extras.zip +cp parameters.js.dist parameters.js +npm i +cd pieces/Avalam && python generateSVG.py +#cd pieces/Emergo && python generateSVG.py diff --git a/pieces/black_commoner.svg b/pieces/black_commoner.svg new file mode 100644 index 0000000..0995449 --- /dev/null +++ b/pieces/black_commoner.svg @@ -0,0 +1,105 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pieces/white_commoner.svg b/pieces/white_commoner.svg new file mode 100644 index 0000000..12f2b27 --- /dev/null +++ b/pieces/white_commoner.svg @@ -0,0 +1,94 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/variants.js b/variants.js index f42033e..10cf42a 100644 --- a/variants.js +++ b/variants.js @@ -45,9 +45,9 @@ const variants = [ {name: 'Dice', desc: 'Roll the dice'}, {name: 'Discoduel', desc: 'Enter the disco', disp: 'Disco Duel'}, {name: 'Dobutsu', desc: "Let's catch the Lion!"}, -// {name: 'Doublearmy', desc: '64 pieces on the board', disp: 'Double Army'}, + {name: 'Doublearmy', desc: '64 pieces on the board', disp: 'Double Army'}, {name: 'Doublemove', desc: 'Double moves'}, -// {name: 'Dynamo', desc: 'Push and pull'}, + {name: 'Dynamo', desc: 'Push and pull'}, // {name: 'Eightpieces', desc: 'Each piece is unique', disp: '8 Pieces'}, // {name: 'Emergo', desc: 'Stacking Checkers variant'}, // {name: 'Empire', desc: 'Empire versus Kingdom'}, diff --git a/variants/Doublearmy/class.js b/variants/Doublearmy/class.js new file mode 100644 index 0000000..abbb564 --- /dev/null +++ b/variants/Doublearmy/class.js @@ -0,0 +1,43 @@ +import ChessRules from "/base_rules.js"; + +export default class DoublearmyRules extends ChessRules { + + static get Options() { + return { + select: C.Options.select, + input: C.Options.input, + styles: C.Options.styles.filter(s => s != "madrasi") + }; + } + + pieces(color, x, y) { + let res = super.pieces(color, x, y); + return Object.assign( + { + 'c': { + "class": "commoner", + moveas: 'k' + } + }, + res + ); + } + + genRandInitBaseFen() { + const s = super.genRandInitBaseFen(); + const rows = s.fen.split('/'); + return { + fen: + rows[0] + "/" + + rows[1] + "/" + + rows[0].replace('k', 'c') + "/" + + rows[1] + "/" + + rows[6] + "/" + + rows[7].replace('K', 'C') + "/" + + rows[6] + "/" + + rows[7], + o: s.o + }; + } + +}; diff --git a/variants/Doublearmy/rules.html b/variants/Doublearmy/rules.html new file mode 100644 index 0000000..b9908ab --- /dev/null +++ b/variants/Doublearmy/rules.html @@ -0,0 +1,6 @@ +

    + The four middle ranks contain a replica of the initial pieces. + The central "king" has no royal status, and is thus named "commoner". +

    + +

    Vincent Rothuis (2020).

    diff --git a/variants/Doublearmy/style.css b/variants/Doublearmy/style.css new file mode 100644 index 0000000..e50c2f4 --- /dev/null +++ b/variants/Doublearmy/style.css @@ -0,0 +1,9 @@ +@import url("/base_pieces.css"); + +piece.black.commoner { + background-image: url('/pieces/black_commoner.svg'); +} + +piece.white.commoner { + background-image: url('/pieces/white_commoner.svg'); +} diff --git a/variants/Dynamo/class.js b/variants/Dynamo/class.js new file mode 100644 index 0000000..0996a70 --- /dev/null +++ b/variants/Dynamo/class.js @@ -0,0 +1,921 @@ +import ChessRules from "/base_rules.js"; + +export default class DynamoRules extends ChessRules { + + // TODO? later, allow to push out pawns on a and h files + get hasEnpassant() { + return false; + } + +/// TODO::: + + canIplay(side, [x, y]) { + // Sometimes opponent's pieces can be moved directly + return this.turn == side; + } + + setOtherVariables(fen) { + super.setOtherVariables(fen); + this.subTurn = 1; + // Local stack of "action moves" + this.amoves = []; + const amove = V.ParseFen(fen).amove; + if (amove != "-") { + const amoveParts = amove.split("/"); + let move = { + // No need for start & end + appear: [], + vanish: [] + }; + [0, 1].map(i => { + if (amoveParts[i] != "-") { + amoveParts[i].split(".").forEach(av => { + // Format is "bpe3" + const xy = V.SquareToCoords(av.substr(2)); + move[i == 0 ? "appear" : "vanish"].push( + new PiPo({ + x: xy.x, + y: xy.y, + c: av[0], + p: av[1] + }) + ); + }); + } + }); + this.amoves.push(move); + } + // Stack "first moves" (on subTurn 1) to merge and check opposite moves + this.firstMove = []; + } + + static ParseFen(fen) { + return Object.assign( + ChessRules.ParseFen(fen), + { amove: fen.split(" ")[4] } + ); + } + + static IsGoodFen(fen) { + if (!ChessRules.IsGoodFen(fen)) return false; + const fenParts = fen.split(" "); + if (fenParts.length != 5) return false; + if (fenParts[4] != "-") { + // TODO: a single regexp instead. + // Format is [bpa2[.wpd3]] || '-'/[bbc3[.wrd5]] || '-' + const amoveParts = fenParts[4].split("/"); + if (amoveParts.length != 2) return false; + for (let part of amoveParts) { + if (part != "-") { + for (let psq of part.split(".")) + if (!psq.match(/^[a-z]{3}[1-8]$/)) return false; + } + } + } + return true; + } + + getFen() { + return super.getFen() + " " + this.getAmoveFen(); + } + + getFenForRepeat() { + return super.getFenForRepeat() + "_" + this.getAmoveFen(); + } + + getAmoveFen() { + const L = this.amoves.length; + if (L == 0) return "-"; + return ( + ["appear","vanish"].map( + mpart => { + if (this.amoves[L-1][mpart].length == 0) return "-"; + return ( + this.amoves[L-1][mpart].map( + av => { + const square = V.CoordsToSquare({ x: av.x, y: av.y }); + return av.c + av.p + square; + } + ).join(".") + ); + } + ).join("/") + ); + } + + canTake() { + // Captures don't occur (only pulls & pushes) + return false; + } + + // Step is right, just add (push/pull) moves in this direction + // Direction is assumed normalized. + getMovesInDirection([x, y], [dx, dy], nbSteps) { + nbSteps = nbSteps || 8; //max 8 steps anyway + let [i, j] = [x + dx, y + dy]; + let moves = []; + const color = this.getColor(x, y); + const piece = this.getPiece(x, y); + const lastRank = (color == 'w' ? 0 : 7); + let counter = 1; + while (V.OnBoard(i, j) && this.board[i][j] == V.EMPTY) { + if (i == lastRank && piece == V.PAWN) { + // Promotion by push or pull + V.PawnSpecs.promotions.forEach(p => { + let move = super.getBasicMove([x, y], [i, j], { c: color, p: p }); + moves.push(move); + }); + } + else moves.push(super.getBasicMove([x, y], [i, j])); + if (++counter > nbSteps) break; + i += dx; + j += dy; + } + if (!V.OnBoard(i, j) && piece != V.KING) { + // Add special "exit" move, by "taking king" + moves.push( + new Move({ + start: { x: x, y: y }, + end: { x: this.kingPos[color][0], y: this.kingPos[color][1] }, + appear: [], + vanish: [{ x: x, y: y, c: color, p: piece }] + }) + ); + } + return moves; + } + + // Normalize direction to know the step + getNormalizedDirection([dx, dy]) { + const absDir = [Math.abs(dx), Math.abs(dy)]; + let divisor = 0; + if (absDir[0] != 0 && absDir[1] != 0 && absDir[0] != absDir[1]) + // Knight + divisor = Math.min(absDir[0], absDir[1]); + else + // Standard slider (or maybe a pawn or king: same) + divisor = Math.max(absDir[0], absDir[1]); + return [dx / divisor, dy / divisor]; + } + + // There was something on x2,y2, maybe our color, pushed or (self)pulled + isAprioriValidExit([x1, y1], [x2, y2], color2, piece2) { + const color1 = this.getColor(x1, y1); + const pawnShift = (color1 == 'w' ? -1 : 1); + const lastRank = (color1 == 'w' ? 0 : 7); + const deltaX = Math.abs(x1 - x2); + const deltaY = Math.abs(y1 - y2); + const checkSlider = () => { + const dir = this.getNormalizedDirection([x2 - x1, y2 - y1]); + let [i, j] = [x1 + dir[0], y1 + dir[1]]; + while (V.OnBoard(i, j) && this.board[i][j] == V.EMPTY) { + i += dir[0]; + j += dir[1]; + } + return !V.OnBoard(i, j); + }; + switch (piece2 || this.getPiece(x1, y1)) { + case V.PAWN: + return ( + x1 + pawnShift == x2 && + ( + (color1 == color2 && x2 == lastRank && y1 == y2) || + ( + color1 != color2 && + deltaY == 1 && + !V.OnBoard(2 * x2 - x1, 2 * y2 - y1) + ) + ) + ); + case V.ROOK: + if (x1 != x2 && y1 != y2) return false; + return checkSlider(); + case V.KNIGHT: + return ( + deltaX + deltaY == 3 && + (deltaX == 1 || deltaY == 1) && + !V.OnBoard(2 * x2 - x1, 2 * y2 - y1) + ); + case V.BISHOP: + if (deltaX != deltaY) return false; + return checkSlider(); + case V.QUEEN: + if (deltaX != 0 && deltaY != 0 && deltaX != deltaY) return false; + return checkSlider(); + case V.KING: + return ( + deltaX <= 1 && + deltaY <= 1 && + !V.OnBoard(2 * x2 - x1, 2 * y2 - y1) + ); + } + return false; + } + + isAprioriValidVertical([x1, y1], x2) { + const piece = this.getPiece(x1, y1); + const deltaX = Math.abs(x1 - x2); + const startRank = (this.getColor(x1, y1) == 'w' ? 6 : 1); + return ( + [V.QUEEN, V.ROOK].includes(piece) || + ( + [V.KING, V.PAWN].includes(piece) && + ( + deltaX == 1 || + (deltaX == 2 && piece == V.PAWN && x1 == startRank) + ) + ) + ); + } + + // NOTE: for pushes, play the pushed piece first. + // for pulls: play the piece doing the action first + // NOTE: to push a piece out of the board, make it slide until its king + getPotentialMovesFrom([x, y]) { + const color = this.turn; + const sqCol = this.getColor(x, y); + const pawnShift = (color == 'w' ? -1 : 1); + const pawnStartRank = (color == 'w' ? 6 : 1); + const getMoveHash = (m) => { + return V.CoordsToSquare(m.start) + V.CoordsToSquare(m.end); + }; + if (this.subTurn == 1) { + const addMoves = (dir, nbSteps) => { + const newMoves = + this.getMovesInDirection([x, y], [-dir[0], -dir[1]], nbSteps) + .filter(m => !movesHash[getMoveHash(m)]); + newMoves.forEach(m => { movesHash[getMoveHash(m)] = true; }); + Array.prototype.push.apply(moves, newMoves); + }; + // Free to play any move (if piece of my color): + let moves = + sqCol == color + ? super.getPotentialMovesFrom([x, y]) + : []; + // There may be several suicide moves: keep only one + let hasExit = false; + moves = moves.filter(m => { + const suicide = (m.appear.length == 0); + if (suicide) { + if (hasExit) return false; + hasExit = true; + } + return true; + }); + // Structure to avoid adding moves twice (can be action & move) + let movesHash = {}; + moves.forEach(m => { movesHash[getMoveHash(m)] = true; }); + // [x, y] is pushed by 'color' + for (let step of V.steps[V.KNIGHT]) { + const [i, j] = [x + step[0], y + step[1]]; + if ( + V.OnBoard(i, j) && + this.board[i][j] != V.EMPTY && + this.getColor(i, j) == color && + this.getPiece(i, j) == V.KNIGHT + ) { + addMoves(step, 1); + } + } + for (let step of V.steps[V.ROOK].concat(V.steps[V.BISHOP])) { + let [i, j] = [x + step[0], y + step[1]]; + while (V.OnBoard(i, j) && this.board[i][j] == V.EMPTY) { + i += step[0]; + j += step[1]; + } + if ( + V.OnBoard(i, j) && + this.board[i][j] != V.EMPTY && + this.getColor(i, j) == color + ) { + const deltaX = Math.abs(i - x); + const deltaY = Math.abs(j - y); + switch (this.getPiece(i, j)) { + case V.PAWN: + if ( + (x - i) / deltaX == pawnShift && + deltaX <= 2 && + deltaY <= 1 + ) { + if (sqCol == color && deltaY == 0) { + // Pushed forward + const maxSteps = (i == pawnStartRank && deltaX == 1 ? 2 : 1); + addMoves(step, maxSteps); + } + else if (sqCol != color && deltaY == 1 && deltaX == 1) + // Pushed diagonally + addMoves(step, 1); + } + break; + case V.ROOK: + if (deltaX == 0 || deltaY == 0) addMoves(step); + break; + case V.BISHOP: + if (deltaX == deltaY) addMoves(step); + break; + case V.QUEEN: + // All steps are valid for a queen: + addMoves(step); + break; + case V.KING: + if (deltaX <= 1 && deltaY <= 1) addMoves(step, 1); + break; + } + } + } + return moves; + } + // If subTurn == 2 then we should have a first move, + // which restrict what we can play now: only in the first move direction + const L = this.firstMove.length; + const fm = this.firstMove[L-1]; + if ( + (fm.appear.length == 2 && fm.vanish.length == 2) || + (fm.vanish[0].c == sqCol && sqCol != color) + ) { + // Castle or again opponent color: no move playable then. + return []; + } + const piece = this.getPiece(x, y); + const getPushExit = () => { + // Piece at subTurn 1 exited: can I have caused the exit? + if ( + this.isAprioriValidExit( + [x, y], + [fm.start.x, fm.start.y], + fm.vanish[0].c + ) + ) { + // Seems so: + const dir = this.getNormalizedDirection( + [fm.start.x - x, fm.start.y - y]); + const nbSteps = + [V.PAWN, V.KING, V.KNIGHT].includes(piece) + ? 1 + : null; + return this.getMovesInDirection([x, y], dir, nbSteps); + } + return []; + } + const getPushMoves = () => { + // Piece from subTurn 1 is still on board: + const dirM = this.getNormalizedDirection( + [fm.end.x - fm.start.x, fm.end.y - fm.start.y]); + const dir = this.getNormalizedDirection( + [fm.start.x - x, fm.start.y - y]); + // Normalized directions should match + if (dir[0] == dirM[0] && dir[1] == dirM[1]) { + // We don't know if first move is a pushed piece or normal move, + // so still must check if the push is valid. + const deltaX = Math.abs(fm.start.x - x); + const deltaY = Math.abs(fm.start.y - y); + switch (piece) { + case V.PAWN: + if (x == pawnStartRank) { + if ( + (fm.start.x - x) * pawnShift < 0 || + deltaX >= 3 || + deltaY >= 2 || + (fm.vanish[0].c == color && deltaY > 0) || + (fm.vanish[0].c != color && deltaY == 0) || + Math.abs(fm.end.x - fm.start.x) > deltaX || + fm.end.y - fm.start.y != fm.start.y - y + ) { + return []; + } + } + else { + if ( + fm.start.x - x != pawnShift || + deltaY >= 2 || + (fm.vanish[0].c == color && deltaY == 1) || + (fm.vanish[0].c != color && deltaY == 0) || + fm.end.x - fm.start.x != pawnShift || + fm.end.y - fm.start.y != fm.start.y - y + ) { + return []; + } + } + break; + case V.KNIGHT: + if ( + (deltaX + deltaY != 3 || (deltaX == 0 && deltaY == 0)) || + (fm.end.x - fm.start.x != fm.start.x - x) || + (fm.end.y - fm.start.y != fm.start.y - y) + ) { + return []; + } + break; + case V.KING: + if ( + (deltaX >= 2 || deltaY >= 2) || + (fm.end.x - fm.start.x != fm.start.x - x) || + (fm.end.y - fm.start.y != fm.start.y - y) + ) { + return []; + } + break; + case V.BISHOP: + if (deltaX != deltaY) return []; + break; + case V.ROOK: + if (deltaX != 0 && deltaY != 0) return []; + break; + case V.QUEEN: + if (deltaX != deltaY && deltaX != 0 && deltaY != 0) return []; + break; + } + // Nothing should stand between [x, y] and the square fm.start + let [i, j] = [x + dir[0], y + dir[1]]; + while ( + (i != fm.start.x || j != fm.start.y) && + this.board[i][j] == V.EMPTY + ) { + i += dir[0]; + j += dir[1]; + } + if (i == fm.start.x && j == fm.start.y) + return this.getMovesInDirection([x, y], dir); + } + return []; + } + const getPullExit = () => { + // Piece at subTurn 1 exited: can I be pulled? + // Note: kings cannot suicide, so fm.vanish[0].p is not KING. + // Could be PAWN though, if a pawn was pushed out of board. + if ( + fm.vanish[0].p != V.PAWN && //pawns cannot pull + this.isAprioriValidExit( + [x, y], + [fm.start.x, fm.start.y], + fm.vanish[0].c, + fm.vanish[0].p + ) + ) { + // Seems so: + const dir = this.getNormalizedDirection( + [fm.start.x - x, fm.start.y - y]); + const nbSteps = (fm.vanish[0].p == V.KNIGHT ? 1 : null); + return this.getMovesInDirection([x, y], dir, nbSteps); + } + return []; + }; + const getPullMoves = () => { + if (fm.vanish[0].p == V.PAWN) + // pawns cannot pull + return []; + const dirM = this.getNormalizedDirection( + [fm.end.x - fm.start.x, fm.end.y - fm.start.y]); + const dir = this.getNormalizedDirection( + [fm.start.x - x, fm.start.y - y]); + // Normalized directions should match + if (dir[0] == dirM[0] && dir[1] == dirM[1]) { + // Am I at the right distance? + const deltaX = Math.abs(x - fm.start.x); + const deltaY = Math.abs(y - fm.start.y); + if ( + (fm.vanish[0].p == V.KING && (deltaX > 1 || deltaY > 1)) || + (fm.vanish[0].p == V.KNIGHT && + (deltaX + deltaY != 3 || deltaX == 0 || deltaY == 0)) + ) { + return []; + } + // Nothing should stand between [x, y] and the square fm.start + let [i, j] = [x + dir[0], y + dir[1]]; + while ( + (i != fm.start.x || j != fm.start.y) && + this.board[i][j] == V.EMPTY + ) { + i += dir[0]; + j += dir[1]; + } + if (i == fm.start.x && j == fm.start.y) + return this.getMovesInDirection([x, y], dir); + } + return []; + }; + if (fm.vanish[0].c != color) { + // Only possible action is a push: + if (fm.appear.length == 0) return getPushExit(); + return getPushMoves(); + } + else if (sqCol != color) { + // Only possible action is a pull, considering moving piece abilities + if (fm.appear.length == 0) return getPullExit(); + return getPullMoves(); + } + else { + // My color + my color: both actions possible + // Structure to avoid adding moves twice (can be action & move) + let movesHash = {}; + if (fm.appear.length == 0) { + const pushes = getPushExit(); + pushes.forEach(m => { movesHash[getMoveHash(m)] = true; }); + return ( + pushes.concat(getPullExit().filter(m => !movesHash[getMoveHash(m)])) + ); + } + const pushes = getPushMoves(); + pushes.forEach(m => { movesHash[getMoveHash(m)] = true; }); + return ( + pushes.concat(getPullMoves().filter(m => !movesHash[getMoveHash(m)])) + ); + } + return []; + } + + getSlideNJumpMoves([x, y], steps, oneStep) { + let moves = []; + const c = this.getColor(x, y); + const piece = this.getPiece(x, y); + outerLoop: for (let step of steps) { + let i = x + step[0]; + let j = y + step[1]; + while (V.OnBoard(i, j) && this.board[i][j] == V.EMPTY) { + moves.push(this.getBasicMove([x, y], [i, j])); + if (oneStep) continue outerLoop; + i += step[0]; + j += step[1]; + } + if (V.OnBoard(i, j)) { + if (this.canTake([x, y], [i, j])) + moves.push(this.getBasicMove([x, y], [i, j])); + } + else { + // Add potential board exit (suicide), except for the king + if (piece != V.KING) { + moves.push({ + start: { x: x, y: y}, + end: { x: this.kingPos[c][0], y: this.kingPos[c][1] }, + appear: [], + vanish: [ + new PiPo({ + x: x, + y: y, + c: c, + p: piece + }) + ] + }); + } + } + } + return moves; + } + + // Does m2 un-do m1 ? (to disallow undoing actions) + oppositeMoves(m1, m2) { + const isEqual = (av1, av2) => { + for (let av of av1) { + const avInAv2 = av2.find(elt => { + return ( + elt.x == av.x && + elt.y == av.y && + elt.c == av.c && + elt.p == av.p + ); + }); + if (!avInAv2) return false; + } + return true; + }; + // All appear and vanish arrays must have the same length + const mL = m1.appear.length; + return ( + m2.appear.length == mL && + m1.vanish.length == mL && + m2.vanish.length == mL && + isEqual(m1.appear, m2.vanish) && + isEqual(m1.vanish, m2.appear) + ); + } + + getAmove(move1, move2) { + // Just merge (one is action one is move, one may be empty) + return { + appear: move1.appear.concat(move2.appear), + vanish: move1.vanish.concat(move2.vanish) + } + } + + filterValid(moves) { + const color = this.turn; + const La = this.amoves.length; + if (this.subTurn == 1) { + return moves.filter(m => { + // A move is valid either if it doesn't result in a check, + // or if a second move is possible to counter the check + // (not undoing a potential move + action of the opponent) + this.play(m); + let res = this.underCheck(color); + if (this.subTurn == 2) { + let isOpposite = La > 0 && this.oppositeMoves(this.amoves[La-1], m); + if (res || isOpposite) { + const moves2 = this.getAllPotentialMoves(); + for (let m2 of moves2) { + this.play(m2); + const res2 = this.underCheck(color); + const amove = this.getAmove(m, m2); + isOpposite = + La > 0 && this.oppositeMoves(this.amoves[La-1], amove); + this.undo(m2); + if (!res2 && !isOpposite) { + res = false; + break; + } + } + } + } + this.undo(m); + return !res; + }); + } + if (La == 0) return super.filterValid(moves); + const Lf = this.firstMove.length; + return ( + super.filterValid( + moves.filter(m => { + // Move shouldn't undo another: + const amove = this.getAmove(this.firstMove[Lf-1], m); + return !this.oppositeMoves(this.amoves[La-1], amove); + }) + ) + ); + } + + isAttackedBySlideNJump([x, y], color, piece, steps, oneStep) { + for (let step of steps) { + let rx = x + step[0], + ry = y + step[1]; + while (V.OnBoard(rx, ry) && this.board[rx][ry] == V.EMPTY && !oneStep) { + rx += step[0]; + ry += step[1]; + } + if ( + V.OnBoard(rx, ry) && + this.getPiece(rx, ry) == piece && + this.getColor(rx, ry) == color + ) { + // Continue some steps in the same direction (pull) + rx += step[0]; + ry += step[1]; + while ( + V.OnBoard(rx, ry) && + this.board[rx][ry] == V.EMPTY && + !oneStep + ) { + rx += step[0]; + ry += step[1]; + } + if (!V.OnBoard(rx, ry)) return true; + // Step in the other direction (push) + rx = x - step[0]; + ry = y - step[1]; + while ( + V.OnBoard(rx, ry) && + this.board[rx][ry] == V.EMPTY && + !oneStep + ) { + rx -= step[0]; + ry -= step[1]; + } + if (!V.OnBoard(rx, ry)) return true; + } + } + return false; + } + + isAttackedByPawn([x, y], color) { + // The king can be pushed out by a pawn on last rank or near the edge + const pawnShift = (color == "w" ? 1 : -1); + for (let i of [-1, 1]) { + if ( + V.OnBoard(x + pawnShift, y + i) && + this.board[x + pawnShift][y + i] != V.EMPTY && + this.getPiece(x + pawnShift, y + i) == V.PAWN && + this.getColor(x + pawnShift, y + i) == color + ) { + if (!V.OnBoard(x - pawnShift, y - i)) return true; + } + } + return false; + } + + static OnTheEdge(x, y) { + return (x == 0 || x == 7 || y == 0 || y == 7); + } + + isAttackedByKing([x, y], color) { + // Attacked if I'm on the edge and the opponent king just next, + // but not on the edge. + if (V.OnTheEdge(x, y)) { + for (let step of V.steps[V.ROOK].concat(V.steps[V.BISHOP])) { + const [i, j] = [x + step[0], y + step[1]]; + if ( + V.OnBoard(i, j) && + !V.OnTheEdge(i, j) && + this.board[i][j] != V.EMPTY && + this.getPiece(i, j) == V.KING + // NOTE: since only one king of each color, and (x, y) is occupied + // by our king, no need to check other king's color. + ) { + return true; + } + } + } + return false; + } + + // No consideration of color: all pieces could be played + getAllPotentialMoves() { + let potentialMoves = []; + for (let i = 0; i < V.size.x; i++) { + for (let j = 0; j < V.size.y; j++) { + if (this.board[i][j] != V.EMPTY) { + Array.prototype.push.apply( + potentialMoves, + this.getPotentialMovesFrom([i, j]) + ); + } + } + } + return potentialMoves; + } + + getEmptyMove() { + return new Move({ + start: { x: -1, y: -1 }, + end: { x: -1, y: -1 }, + appear: [], + vanish: [] + }); + } + + doClick(square) { + // A click to promote a piece on subTurn 2 would trigger this. + // For now it would then return [NaN, NaN] because surrounding squares + // have no IDs in the promotion modal. TODO: improve this? + if (isNaN(square[0])) return null; + // If subTurn == 2 && square is empty && !underCheck && !isOpposite, + // then return an empty move, allowing to "pass" subTurn2 + const La = this.amoves.length; + const Lf = this.firstMove.length; + if ( + this.subTurn == 2 && + this.board[square[0]][square[1]] == V.EMPTY && + !this.underCheck(this.turn) && + (La == 0 || !this.oppositeMoves(this.amoves[La-1], this.firstMove[Lf-1])) + ) { + return this.getEmptyMove(); + } + return null; + } + + play(move) { + if (this.subTurn == 1 && move.vanish.length == 0) { + // Patch to work with old format: (TODO: remove later) + move.ignore = true; + return; + } + const color = this.turn; + move.subTurn = this.subTurn; //for undo + const gotoNext = (mv) => { + const L = this.firstMove.length; + this.amoves.push(this.getAmove(this.firstMove[L-1], mv)); + this.turn = V.GetOppCol(color); + this.subTurn = 1; + this.movesCount++; + }; + move.flags = JSON.stringify(this.aggregateFlags()); + V.PlayOnBoard(this.board, move); + if (this.subTurn == 2) gotoNext(move); + else { + this.subTurn = 2; + this.firstMove.push(move); + this.toNewKingPos(move); + if ( + // Condition is true on empty arrays: + this.getAllPotentialMoves().every(m => { + V.PlayOnBoard(this.board, m); + this.toNewKingPos(m); + const res = this.underCheck(color); + V.UndoOnBoard(this.board, m); + this.toOldKingPos(m); + return res; + }) + ) { + // No valid move at subTurn 2 + gotoNext(this.getEmptyMove()); + } + this.toOldKingPos(move); + } + this.postPlay(move); + } + + toNewKingPos(move) { + for (let a of move.appear) + if (a.p == V.KING) this.kingPos[a.c] = [a.x, a.y]; + } + + postPlay(move) { + if (move.start.x < 0) return; + this.toNewKingPos(move); + this.updateCastleFlags(move); + } + + updateCastleFlags(move) { + const firstRank = { 'w': V.size.x - 1, 'b': 0 }; + for (let v of move.vanish) { + if (v.p == V.KING) this.castleFlags[v.c] = [V.size.y, V.size.y]; + else if (v.x == firstRank[v.c] && this.castleFlags[v.c].includes(v.y)) { + const flagIdx = (v.y == this.castleFlags[v.c][0] ? 0 : 1); + this.castleFlags[v.c][flagIdx] = V.size.y; + } + } + } + + undo(move) { + if (!!move.ignore) return; //TODO: remove that later + this.disaggregateFlags(JSON.parse(move.flags)); + V.UndoOnBoard(this.board, move); + if (this.subTurn == 1) { + this.amoves.pop(); + this.turn = V.GetOppCol(this.turn); + this.movesCount--; + } + if (move.subTurn == 1) this.firstMove.pop(); + this.subTurn = move.subTurn; + this.toOldKingPos(move); + } + + toOldKingPos(move) { + // (Potentially) Reset king position + for (let v of move.vanish) + if (v.p == V.KING) this.kingPos[v.c] = [v.x, v.y]; + } + + getComputerMove() { + let moves = this.getAllValidMoves(); + if (moves.length == 0) return null; + // "Search" at depth 1 for now + const maxeval = V.INFINITY; + const color = this.turn; + const emptyMove = { + start: { x: -1, y: -1 }, + end: { x: -1, y: -1 }, + appear: [], + vanish: [] + }; + moves.forEach(m => { + this.play(m); + if (this.turn != color) m.eval = this.evalPosition(); + else { + m.eval = (color == "w" ? -1 : 1) * maxeval; + const moves2 = this.getAllValidMoves().concat([emptyMove]); + m.next = moves2[0]; + moves2.forEach(m2 => { + this.play(m2); + const score = this.getCurrentScore(); + let mvEval = 0; + if (score != "1/2") { + if (score != "*") mvEval = (score == "1-0" ? 1 : -1) * maxeval; + else mvEval = this.evalPosition(); + } + if ( + (color == 'w' && mvEval > m.eval) || + (color == 'b' && mvEval < m.eval) + ) { + m.eval = mvEval; + m.next = m2; + } + this.undo(m2); + }); + } + this.undo(m); + }); + moves.sort((a, b) => { + return (color == "w" ? 1 : -1) * (b.eval - a.eval); + }); + let candidates = [0]; + for (let i = 1; i < moves.length && moves[i].eval == moves[0].eval; i++) + candidates.push(i); + const mIdx = candidates[randInt(candidates.length)]; + if (!moves[mIdx].next) return moves[mIdx]; + const move2 = moves[mIdx].next; + delete moves[mIdx]["next"]; + return [moves[mIdx], move2]; + } + + getNotation(move) { + if (move.start.x < 0) + // A second move is always required, but may be empty + return "-"; + const initialSquare = V.CoordsToSquare(move.start); + const finalSquare = V.CoordsToSquare(move.end); + if (move.appear.length == 0) + // Pushed or pulled out of the board + return initialSquare + "R"; + return move.appear[0].p.toUpperCase() + initialSquare + finalSquare; + } + +}; diff --git a/variants/Dynamo/complete_rules.html b/variants/Dynamo/complete_rules.html new file mode 100644 index 0000000..68e9cc0 --- /dev/null +++ b/variants/Dynamo/complete_rules.html @@ -0,0 +1,142 @@ + + + Dynamo Rules + + + + +
    +

    Dynamo Rules

    + +

    + Pieces have the same movement as in orthodox chess, but they cannot + take other pieces in the usual way. Instead of the normal captures, pieces + can pull or push other pieces, potentially off the board. + The goal is to send the enemy king off the board. +

    + +

    Each turn, a player has the following options:

    +
      +
    • + Move one of his pieces normally, then optionally pull something as an + effect of this move. +
    • +
    • + Push any piece with one of his pieces, then optionally follow the pushed + piece. +
    • + +

      + It seems easier to understand with some examples. For a detailed + introduction please visit + + this page + (in French). +

      + +
      +
      +
      +
      Possible "pawn moves" in the initial position.
      +
      + +

      + The e2 pawn can move to e3 and e4 as usual. It can also slide diagonally, + being pushed by the bishop or the queen (which may or may not move along + this line afterward). It can also go to c3, being pushed by the knight from + g1; then the knight can move to e2, or stay motionless. + Finally, the pawn can "take the king": this is a special move indicating that + you want it to exit the board. Indeed it could be pushed off the board by the + bishop or the queen. +

      + +

      + Note: if an action is possible but you don't want to play a second part in + a move, click on any empty square: this will send an empty move. +

      + +
      +
      +
      +
      +
      +
      + Pulling the d5 pawn to c3 (left: before, right: after). +
      +
      + +
        +
      • Pawns cannot pull (because they only move forward).
      • +
      • + When they could reach the square beyond the edge, + pieces can exit the board by themselves, possibly dragging another piece + out (friendly or enemy). +
      • +
      + +
      +
      +
      +
      + Check: the queen threatens to pull the king off the board + along the a4-e8 diagonal. +
      +
      + +

      + It is forbidden to undo a "move + action". For example here, white could + push back the black bishop on g7 but not return to d4 then. +

      + +
      +
      +
      +
      +
      + Pushing the d4 bishop to b2 (left: before, right: after). +
      +
      + +

      + Castling is possible as long as the king and rook have not moved and + haven't been pushed or pulled (this differs from the chessvariants + description). +

      + +

      End of the game

      + +

      + The game ends when a push or pull action threatens to send the king off the + board, and he has no way to escape it. +

      + +
      +
      +
      +
      Dynamo checkmate ("Dynamate" :) )
      +
      + +

      + The king cannot "take" on g4: this would just push the queen one step to the + left, and she would then push the king beyond the 'h' file. + There are no en-passant captures. +

      + +

      Source

      + +

      + + Dynamo chess + + on chessvariants.com. The short description given on + this page + might help too. +

      diff --git a/variants/Dynamo/rules.html b/variants/Dynamo/rules.html new file mode 100644 index 0000000..4a78e5a --- /dev/null +++ b/variants/Dynamo/rules.html @@ -0,0 +1,24 @@ +

      + Moves are potentially played in two times: + move a piece, and / or push or pull something with that unit. +

      + +

      Each turn, a player has the following options:

      +
        +
      • + Move one of his pieces normally, + then optionally pull something as an effect of this move. +
      • +
      • + Push any piece with one of his pieces, + then optionally follow the pushed piece. +
      • +
      + +

      + + Full rules description. + +

      + +

      Hans Kluever and Peter Kahl (1968).

      diff --git a/variants/Dynamo/style.css b/variants/Dynamo/style.css new file mode 100644 index 0000000..a3550bc --- /dev/null +++ b/variants/Dynamo/style.css @@ -0,0 +1 @@ +@import url("/base_pieces.css"); -- 2.44.0 From 939e06bf9febef0a7935c7f6a58c5e28dee4dedc Mon Sep 17 00:00:00 2001 From: Benjamin Auder Date: Fri, 5 Jan 2024 09:58:16 +0100 Subject: [PATCH 15/16] Start working on Dynamo --- base_rules.js | 22 ++- variants/Dynamo/class.js | 289 +++++---------------------------------- 2 files changed, 52 insertions(+), 259 deletions(-) diff --git a/base_rules.js b/base_rules.js index 9a364e8..3d8e463 100644 --- a/base_rules.js +++ b/base_rules.js @@ -175,6 +175,22 @@ export default class ChessRules { return Object.values(cd).map(c => c.toString(36)).join(""); } + // c10 --> 02 (assuming 10 rows) + static SquareFromUsual(sq) { + return ( + (this.size.x - parseInt(sq.substring(1), 10)).toString(36) + + (sq.charCodeAt(0) - 97).toString(36) + ); + } + + // 02 --> c10 + static UsualFromSquare(sq) { + return ( + String.fromCharCode(parseInt(sq.charAt(1), 36) + 97) + + (this.size.x - parseInt(sq.charAt(0), 36)).toString(10) + ); + } + coordsToId(cd) { if (typeof cd.x == "number") { return ( @@ -651,10 +667,8 @@ export default class ChessRules { this[arrName] = ArrayFun.init(this.size.x, this.size.y, null); if (arrName == "d_pieces") this.marks.forEach((m) => { - const formattedSquare = - (this.size.x - parseInt(m.substring(1), 10)).toString(36) + - (m.charCodeAt(0) - 97).toString(36); - const mCoords = V.SquareToCoords(formattedSquare); + const formattedSquare = C.SquareFromUsual(m); + const mCoords = C.SquareToCoords(formattedSquare); addPiece(mCoords.x, mCoords.y, arrName, "mark"); }); }; diff --git a/variants/Dynamo/class.js b/variants/Dynamo/class.js index 0996a70..05f2aed 100644 --- a/variants/Dynamo/class.js +++ b/variants/Dynamo/class.js @@ -2,110 +2,51 @@ import ChessRules from "/base_rules.js"; export default class DynamoRules extends ChessRules { - // TODO? later, allow to push out pawns on a and h files - get hasEnpassant() { - return false; + static get Options() { + // TODO } -/// TODO::: + get hasEnpassant() { + return this.options["enpassant"]; + } - canIplay(side, [x, y]) { + canIplay(x, y) { // Sometimes opponent's pieces can be moved directly - return this.turn == side; + return this.playerColor == this.turn; + } + + canTake() { + // Captures don't occur (only pulls & pushes) + return false; } - setOtherVariables(fen) { - super.setOtherVariables(fen); + setOtherVariables(fenParsed) { + super.setOtherVariables(fenParsed); this.subTurn = 1; - // Local stack of "action moves" - this.amoves = []; - const amove = V.ParseFen(fen).amove; - if (amove != "-") { - const amoveParts = amove.split("/"); - let move = { - // No need for start & end - appear: [], - vanish: [] - }; - [0, 1].map(i => { - if (amoveParts[i] != "-") { - amoveParts[i].split(".").forEach(av => { - // Format is "bpe3" - const xy = V.SquareToCoords(av.substr(2)); - move[i == 0 ? "appear" : "vanish"].push( - new PiPo({ - x: xy.x, - y: xy.y, - c: av[0], - p: av[1] - }) - ); - }); - } + // Last action format: e2h5/d1g4 for queen on d1 pushing pawn to h5 + // for example, and moving herself to g4. If just move: e2h5 + this.lastAction = []; + if (fenParsed.amove != '-') { + this.lastAction = fenParsed.amove.split('/').map(a => { + return { + c1: C.SquareToCoords(C.SquareFromUsual(a.substr(0, 2))), + c2: C.SquareToCoords(C.SquareFromUsual(a.substr(2, 2))) + }; }); - this.amoves.push(move); } - // Stack "first moves" (on subTurn 1) to merge and check opposite moves - this.firstMove = []; - } - - static ParseFen(fen) { - return Object.assign( - ChessRules.ParseFen(fen), - { amove: fen.split(" ")[4] } - ); } - static IsGoodFen(fen) { - if (!ChessRules.IsGoodFen(fen)) return false; - const fenParts = fen.split(" "); - if (fenParts.length != 5) return false; - if (fenParts[4] != "-") { - // TODO: a single regexp instead. - // Format is [bpa2[.wpd3]] || '-'/[bbc3[.wrd5]] || '-' - const amoveParts = fenParts[4].split("/"); - if (amoveParts.length != 2) return false; - for (let part of amoveParts) { - if (part != "-") { - for (let psq of part.split(".")) - if (!psq.match(/^[a-z]{3}[1-8]$/)) return false; - } - } + getPartFen(o) { + let res = super.getPartFen(o); + if (o.init) + res["amove"] = '-'; + else { + res["amove"] = this.lastAction.map(a => { + C.UsualFromSquare(C.CoordsToSquare(a.c1)) + + C.UsualFromSquare(C.CoordsToSquare(a.c2)) + }).join('/'); } - return true; - } - - getFen() { - return super.getFen() + " " + this.getAmoveFen(); - } - - getFenForRepeat() { - return super.getFenForRepeat() + "_" + this.getAmoveFen(); - } - - getAmoveFen() { - const L = this.amoves.length; - if (L == 0) return "-"; - return ( - ["appear","vanish"].map( - mpart => { - if (this.amoves[L-1][mpart].length == 0) return "-"; - return ( - this.amoves[L-1][mpart].map( - av => { - const square = V.CoordsToSquare({ x: av.x, y: av.y }); - return av.c + av.p + square; - } - ).join(".") - ); - } - ).join("/") - ); - } - - canTake() { - // Captures don't occur (only pulls & pushes) - return false; + return res; } // Step is right, just add (push/pull) moves in this direction @@ -590,6 +531,7 @@ export default class DynamoRules extends ChessRules { ); } + // TODO: just stack in this.lastAction instead getAmove(move1, move2) { // Just merge (one is action one is move, one may be empty) return { @@ -643,105 +585,6 @@ export default class DynamoRules extends ChessRules { ); } - isAttackedBySlideNJump([x, y], color, piece, steps, oneStep) { - for (let step of steps) { - let rx = x + step[0], - ry = y + step[1]; - while (V.OnBoard(rx, ry) && this.board[rx][ry] == V.EMPTY && !oneStep) { - rx += step[0]; - ry += step[1]; - } - if ( - V.OnBoard(rx, ry) && - this.getPiece(rx, ry) == piece && - this.getColor(rx, ry) == color - ) { - // Continue some steps in the same direction (pull) - rx += step[0]; - ry += step[1]; - while ( - V.OnBoard(rx, ry) && - this.board[rx][ry] == V.EMPTY && - !oneStep - ) { - rx += step[0]; - ry += step[1]; - } - if (!V.OnBoard(rx, ry)) return true; - // Step in the other direction (push) - rx = x - step[0]; - ry = y - step[1]; - while ( - V.OnBoard(rx, ry) && - this.board[rx][ry] == V.EMPTY && - !oneStep - ) { - rx -= step[0]; - ry -= step[1]; - } - if (!V.OnBoard(rx, ry)) return true; - } - } - return false; - } - - isAttackedByPawn([x, y], color) { - // The king can be pushed out by a pawn on last rank or near the edge - const pawnShift = (color == "w" ? 1 : -1); - for (let i of [-1, 1]) { - if ( - V.OnBoard(x + pawnShift, y + i) && - this.board[x + pawnShift][y + i] != V.EMPTY && - this.getPiece(x + pawnShift, y + i) == V.PAWN && - this.getColor(x + pawnShift, y + i) == color - ) { - if (!V.OnBoard(x - pawnShift, y - i)) return true; - } - } - return false; - } - - static OnTheEdge(x, y) { - return (x == 0 || x == 7 || y == 0 || y == 7); - } - - isAttackedByKing([x, y], color) { - // Attacked if I'm on the edge and the opponent king just next, - // but not on the edge. - if (V.OnTheEdge(x, y)) { - for (let step of V.steps[V.ROOK].concat(V.steps[V.BISHOP])) { - const [i, j] = [x + step[0], y + step[1]]; - if ( - V.OnBoard(i, j) && - !V.OnTheEdge(i, j) && - this.board[i][j] != V.EMPTY && - this.getPiece(i, j) == V.KING - // NOTE: since only one king of each color, and (x, y) is occupied - // by our king, no need to check other king's color. - ) { - return true; - } - } - } - return false; - } - - // No consideration of color: all pieces could be played - getAllPotentialMoves() { - let potentialMoves = []; - for (let i = 0; i < V.size.x; i++) { - for (let j = 0; j < V.size.y; j++) { - if (this.board[i][j] != V.EMPTY) { - Array.prototype.push.apply( - potentialMoves, - this.getPotentialMovesFrom([i, j]) - ); - } - } - } - return potentialMoves; - } - getEmptyMove() { return new Move({ start: { x: -1, y: -1 }, @@ -854,68 +697,4 @@ export default class DynamoRules extends ChessRules { if (v.p == V.KING) this.kingPos[v.c] = [v.x, v.y]; } - getComputerMove() { - let moves = this.getAllValidMoves(); - if (moves.length == 0) return null; - // "Search" at depth 1 for now - const maxeval = V.INFINITY; - const color = this.turn; - const emptyMove = { - start: { x: -1, y: -1 }, - end: { x: -1, y: -1 }, - appear: [], - vanish: [] - }; - moves.forEach(m => { - this.play(m); - if (this.turn != color) m.eval = this.evalPosition(); - else { - m.eval = (color == "w" ? -1 : 1) * maxeval; - const moves2 = this.getAllValidMoves().concat([emptyMove]); - m.next = moves2[0]; - moves2.forEach(m2 => { - this.play(m2); - const score = this.getCurrentScore(); - let mvEval = 0; - if (score != "1/2") { - if (score != "*") mvEval = (score == "1-0" ? 1 : -1) * maxeval; - else mvEval = this.evalPosition(); - } - if ( - (color == 'w' && mvEval > m.eval) || - (color == 'b' && mvEval < m.eval) - ) { - m.eval = mvEval; - m.next = m2; - } - this.undo(m2); - }); - } - this.undo(m); - }); - moves.sort((a, b) => { - return (color == "w" ? 1 : -1) * (b.eval - a.eval); - }); - let candidates = [0]; - for (let i = 1; i < moves.length && moves[i].eval == moves[0].eval; i++) - candidates.push(i); - const mIdx = candidates[randInt(candidates.length)]; - if (!moves[mIdx].next) return moves[mIdx]; - const move2 = moves[mIdx].next; - delete moves[mIdx]["next"]; - return [moves[mIdx], move2]; - } - - getNotation(move) { - if (move.start.x < 0) - // A second move is always required, but may be empty - return "-"; - const initialSquare = V.CoordsToSquare(move.start); - const finalSquare = V.CoordsToSquare(move.end); - if (move.appear.length == 0) - // Pushed or pulled out of the board - return initialSquare + "R"; - return move.appear[0].p.toUpperCase() + initialSquare + finalSquare; - } - }; -- 2.44.0 From 253e65f6c4f342e5ac8230d7340ed413354f9c7f Mon Sep 17 00:00:00 2001 From: Benjamin Auder Date: Fri, 19 Jan 2024 17:53:42 +0100 Subject: [PATCH 16/16] New variant idea --- TODO | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/TODO b/TODO index 8afe466..f49a584 100644 --- a/TODO +++ b/TODO @@ -4,3 +4,7 @@ Otage, Emergo, Pacosako : fonction "buildPiece(arg1, arg2)" returns HTML element https://fr.wikipedia.org/wiki/Unlur Yoxii ? + +Idée new variant: "bed" random moves and "capture" (opponent?) pieces which cannot move on next turn (sleeping). (Crazybed ?) +one "bed" per player. +one turn = place bed (potentially with opponent piece), then normal move, then random bed move - dropping potential piece on initial square (awaken). -- 2.44.0