From: Benjamin Auder <benjamin.auder@somewhere> Date: Wed, 6 Jul 2022 11:35:48 +0000 (+0200) Subject: Draft Bario (unfinished) X-Git-Url: https://git.auder.net/variants/current/doc/css/img/pieces/%7B%7B?a=commitdiff_plain;h=dc10e429231932c19da6d1ff2ce98c7a042829ab;p=xogo.git Draft Bario (unfinished) --- diff --git a/base_rules.js b/base_rules.js index 8eed3d3..dc25e54 100644 --- a/base_rules.js +++ b/base_rules.js @@ -208,7 +208,7 @@ export default class ChessRules { baseFen.o = Object.assign({init: true}, baseFen.o); const parts = this.getPartFen(baseFen.o); return ( - baseFen.fen + + baseFen.fen + " w 0" + (Object.keys(parts).length > 0 ? (" " + JSON.stringify(parts)) : "") ); } @@ -218,7 +218,7 @@ export default class ChessRules { let fen, flags = "0707"; if (!this.options.randomness) // Deterministic: - fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w 0"; + fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR"; else { // Randomize @@ -271,8 +271,7 @@ export default class ChessRules { fen = ( pieces["b"].join("") + "/pppppppp/8/8/8/8/PPPPPPPP/" + - pieces["w"].join("").toUpperCase() + - " w 0" + pieces["w"].join("").toUpperCase() ); } return { fen: fen, o: {flags: flags} }; @@ -477,17 +476,15 @@ export default class ChessRules { } // ordering as in pieces() p,r,n,b,q,k - initReserves(reserveStr) { + initReserves(reserveStr, pieceArray) { + if (!pieceArray) + pieceArray = ['p', 'r', 'n', 'b', 'q', 'k']; const counts = reserveStr.split("").map(c => parseInt(c, 36)); - this.reserve = { w: {}, b: {} }; - const pieceName = ['p', 'r', 'n', 'b', 'q', 'k']; - const L = pieceName.length; - for (let i of ArrayFun.range(2 * L)) { - if (i < L) - this.reserve['w'][pieceName[i]] = counts[i]; - else - this.reserve['b'][pieceName[i-L]] = counts[i]; - } + const L = pieceArray.length; + this.reserve = { + w: ArrayFun.toObject(pieceArray, counts.slice(0, L)), + b: ArrayFun.toObject(pieceArray, counts.slice(L, 2 * L)) + }; } initIspawn(ispawnStr) { diff --git a/pieces/Atarigo/CREDITS b/pieces/Go/CREDITS similarity index 100% rename from pieces/Atarigo/CREDITS rename to pieces/Go/CREDITS diff --git a/pieces/Atarigo/black_stone.svg b/pieces/Go/black_stone.svg similarity index 100% rename from pieces/Atarigo/black_stone.svg rename to pieces/Go/black_stone.svg diff --git a/pieces/Atarigo/white_stone.svg b/pieces/Go/white_stone.svg similarity index 100% rename from pieces/Atarigo/white_stone.svg rename to pieces/Go/white_stone.svg diff --git a/pieces/Chakart/mystery_black.svg b/pieces/black_mystery.svg similarity index 100% rename from pieces/Chakart/mystery_black.svg rename to pieces/black_mystery.svg diff --git a/pieces/Chakart/mystery_white.svg b/pieces/white_mystery.svg similarity index 100% rename from pieces/Chakart/mystery_white.svg rename to pieces/white_mystery.svg diff --git a/variants.js b/variants.js index b65a564..8fe9d95 100644 --- a/variants.js +++ b/variants.js @@ -14,9 +14,8 @@ const variants = [ {name: 'Atomic', desc: 'Explosive captures'}, {name: 'Avalam', desc: 'Build towers'}, {name: 'Avalanche', desc: 'Pawnfalls'}, -// {name: 'Ball', desc: 'Score a goal'}, // {name: 'Balaklava', desc: 'Meet the Mammoth'}, -// {name: 'Bario', desc: 'A quantum story'}, + {name: 'Bario', desc: 'A quantum story'}, {name: "Balanced", desc: "balanced chess"}, // {name: 'Baroque', desc: 'Exotic captures'},*/ {name: "Benedict", desc: "Change colors"}, diff --git a/variants/Alapo/class.js b/variants/Alapo/class.js index 1c7c048..199a169 100644 --- a/variants/Alapo/class.js +++ b/variants/Alapo/class.js @@ -31,7 +31,7 @@ export default class AlapoRules extends ChessRules { genRandInitBaseFen() { let fen = ""; if (this.options["randomness"] == 0) - fen = "rbqqbr/tcssct/6/6/TCSSCT/RBQQBR w 0"; + fen = "rbqqbr/tcssct/6/6/TCSSCT/RBQQBR"; else { const piece2pawn = { r: 't', @@ -75,8 +75,7 @@ export default class AlapoRules extends ChessRules { pieces["b"].map(p => piece2pawn[p]).join("") + "/6/6/" + pieces["w"].map(p => piece2pawn[p].toUpperCase()).join("") + "/" + - pieces["w"].join("").toUpperCase() + - " w 0" + pieces["w"].join("").toUpperCase() ); } return { fen: fen, o: {} }; diff --git a/variants/Antiking1/class.js b/variants/Antiking1/class.js index 9d981e8..323b826 100644 --- a/variants/Antiking1/class.js +++ b/variants/Antiking1/class.js @@ -31,7 +31,7 @@ export default class Antiking1Rules extends AbstractAntikingRules { genRandInitBaseFen() { // Always deterministic setup return { - fen: "2prbkqA/2p1nnbr/2pppppp/8/8/PPPPPP2/RBNN1P2/aQKBRP2 w 0", + fen: "2prbkqA/2p1nnbr/2pppppp/8/8/PPPPPP2/RBNN1P2/aQKBRP2", o: {"flags": "KAka"} }; } diff --git a/variants/Apocalypse/class.js b/variants/Apocalypse/class.js index 0600991..5f1e7e2 100644 --- a/variants/Apocalypse/class.js +++ b/variants/Apocalypse/class.js @@ -40,7 +40,7 @@ export default class ApocalypseRules extends ChessRules { genRandInitBaseFen() { return { - fen: "npppn/p3p/5/P3P/NPPPN w 0", + fen: "npppn/p3p/5/P3P/NPPPN", o: {} }; } diff --git a/variants/Atarigo/style.css b/variants/Atarigo/style.css index 6ce83d8..c72abda 100644 --- a/variants/Atarigo/style.css +++ b/variants/Atarigo/style.css @@ -3,9 +3,9 @@ } piece.white.stone { - background-image: url('/pieces/Atarigo/black_stone.svg'); + background-image: url('/pieces/Go/black_stone.svg'); } piece.black.stone { - background-image: url('/pieces/Atarigo/white_stone.svg'); + background-image: url('/pieces/Go/white_stone.svg'); } diff --git a/variants/Avalam/class.js b/variants/Avalam/class.js index f35df83..95993e0 100644 --- a/variants/Avalam/class.js +++ b/variants/Avalam/class.js @@ -66,10 +66,10 @@ export default class AvalamRules extends ChessRules { genRandInitBaseFen() { let fen = ""; if (this.freefill) - fen = "9/".repeat(8) + "9 w 0"; + fen = "9/".repeat(8) + "9"; else if (this.options["randomness"] == 0) { fen = "2Bb5/1BbBb4/1bBbBbB2/1BbBbBbBb/BbBb1bBbB/" + - "bBbBbBbB1/2BbBbBb1/4bBbB1/5bB2 w 0"; + "bBbBbBbB1/2BbBbBb1/4bBbB1/5bB2"; } else { const pieces = ('B'.repeat(24) + 'b'.repeat(24)).split(""); @@ -79,8 +79,7 @@ export default class AvalamRules extends ChessRules { "4/1" + a.substr(6, 6) + "2/1" + a.substr(12, 8) + "/" + a.substr(20, 4) + "1" + a.substr(24, 4) + "/" + a.substr(28, 8) + "1/2" + a.substr(36, 6) + - "1/4" + a.substr(42, 4) + "1/5" + a.substr(46, 2) + - "2 w 0" + "1/4" + a.substr(42, 4) + "1/5" + a.substr(46, 2) + "2" ); } return { fen: fen, o: {} }; diff --git a/variants/Avalanche/class.js b/variants/Avalanche/class.js index ea2b9dd..a1d4d54 100644 --- a/variants/Avalanche/class.js +++ b/variants/Avalanche/class.js @@ -1,5 +1,4 @@ import ChessRules from "/base_rules.js"; -import {Random} from "/utils/alea.js"; import PiPo from "/utils/PiPo.js"; import Move from "/utils/Move.js"; diff --git a/variants/Bario/class.js b/variants/Bario/class.js new file mode 100644 index 0000000..80a3cce --- /dev/null +++ b/variants/Bario/class.js @@ -0,0 +1,238 @@ +import ChessRules from "/base_rules.js"; +import PiPo from "/utils/PiPo.js"; +import Move from "/utils/Move.js"; + +export default class BarioRules extends ChessRules { + + static get Options() { + return { + // TODO: Zen too? + styles: [ + "atomic", "cannibal", "capture", "cylinder", + "dark", "madrasi", "rifle", "teleport" + ] + }; + } + + // Does not really seem necessary (although the author mention it) + // Instead, first move = pick a square for the king. + get hasFlags() { + return false; + } + get hasReserve() { + return true; + } + + pieces(color, x, y) { + return Object.assign( + { + 'u': { + "class": "undefined", + moves: [] + } + }, + super.pieces(color, x, y) + ); + } + + get onlyClick() { + return this.movesCount <= 1; + } + + // Initiate the game by choosing a square for the king: + doClick(coords) { + const color = this.turn; + if ( + this.movesCount <= 1 && + ( + (color == 'w' && coords.x == this.size.x - 1) || + (color == 'b' && coords.x == 0) + ) + ) { + return new Move({ + appear: [ new PiPo({x: coords.x, y: coords.y, c: color, p: 'k' }) ], + vanish: [ new PiPo({x: coords.x, y: coords.y, c: color, p: 'u' }) ] + }); + } + return null; + } + + genRandInitBaseFen() { + return { + fen: "uuuuuuuu/pppppppp/8/8/8/8/PPPPPPPP/UUUUUUUU", + o: {} + } + } + + getPartFen(o) { + return Object.assign( + { + captureUndef: (o.init || !this.captureUndef) + ? "-" + : C.CoordsToSquare(this.captureUndef) + }, + super.getPartFen(o) + ); + } + + getReserveFen(o) { + if (o.init) + return "22212221"; + return ( + ["w","b"].map(c => Object.values(this.reserve[c]).join("")).join("") + ); + } + + initReserves(reserveStr) { + super.initReserves(reserveStr, ['r', 'n', 'b', 'q']); + } + + setOtherVariables(fenParsed) { + super.setOtherVariables(fenParsed); + this.captureUndef = fenParsed.captureUndef == '-' + ? null : + C.SquareToCoords(fenParsed.captureUndef); + this.definition = null; + } + + canDrop([c, p], [i, j]) { + switch (this.subTurn) { + case 0: + return i == this.captureUndef.x && j == this.captureUndef.y; + case 1: + return this.getPiece(i, j) == 'u' && c == this.getColor(i, j); + } + return false; //never reached + } + + getPotentialMovesFrom([x, y]) { + if (this.movesCount <= 1) + return []; + let moves = []; + switch (this.subTurn) { + case 0: + if (typeof x == "string") + moves = this.getDropMovesFrom([x, y]); + break; + case 1: + // Both normal move (from defined piece) and definition allowed + if (typeof x == "string") + moves = this.getDropMovesFrom([x, y]); + else if (this.getPiece(x, y) != 'u') + moves = super.getPotentialMovesFrom([x, y]); + break; + case 2: + // We can only move the just-defined piece + if (x == this.definition.x && y == this.definition.y) + moves = super.getPotentialMovesFrom([x, y]); + break; + } + return moves; + } + + filterValid(moves) { + if (this.movesCount <= 1 || this.subTurn == 0) + return moves; + if (this.subTurn == 1) { + // Remove defining moves with un-movable def piece + moves = moves.filter(m => { + if (m.vanish.length >= 2 || m.vanish[0].p != 'u') + return true; + this.playOnBoard(m); + const canMove = super.filterValid( + super.getPotentialMovesFrom([m.end.x, m.end.y])).length >= 1; + this.undoOnBoard(m); + return canMove; + }); + } + return super.filterValid(moves); + } + + atLeastOneMove(color) { + if (this.subTurn != 1) + return true; + return super.atLeastOneMove(color); + } + + // TODO: this method fails to detect undefined checks + underCheck(square_s, oppCol) { + if (super.underCheck(square_s, oppCol)) + return true; + // Check potential specializations of undefined using reserve: + const allAttacks = Array.prototype.concat.apply( + ['r', 'n', 'b', 'q'].map(p => this.pieces()[p].moves[0])); + const [x, y] = [square_s[0], square_s[1]]; + for (let i=0; i<this.size.x; i++) { + for (let j=0; j<this.size.y; j++) { + if ( + this.board[i][j] != "" && + this.getColor(i, j) == oppCol && + this.getPiece(i, j) == 'u' + ) { + for (let stepDef of allAttacks) { + for (let s of stepDef.steps) { + if (!super.compatibleStep([i, j], [x, y], s, stepDef.range)) + continue; + if ( + super.findDestSquares( + [i, j], + { + captureTarget: [x, y], + captureSteps: [{steps: [s], range: stepDef.range}], + segments: false, + attackOnly: true, + one: false + } + ) + ) { + return true; + } + } + } + } + } + } + return false; + } + + // TODO: missing "undefined reset" check (is everything defined? If yes, reset if enough variety) + postPlay(move) { + const color = this.turn; + const toNextPlayer = () => { + this.turn = C.GetOppCol(color); + this.movesCount++; + }; + if (this.movesCount <= 1) { + toNextPlayer(); + return; + } + const captureUndef = ( + move.vanish.length == 2 && + move.vanish[1].c != color && + move.vanish[1].p == 'u' + ); + if (typeof move.start.x == "number" && !captureUndef) + // Normal move (including Teleport) + super.postPlay(move); + else if (typeof move.start.x == "string") { + this.reserve[color][move.appear[0].p]--; + if (move.vanish.length == 1 && move.vanish[0].p == 'u') + this.definition = move.end; + this.subTurn++; + } + else { + this.subTurn = 0; + this.captureUndef = move.end; + toNextPlayer(); + } + } + + isLastMove() { + return true; //called only on normal moves (not Teleport) + } + + getCurrentScore(move_s) { + return (this.movesCount <= 2 ? "*" : super.getCurrentScore(move_s)); + } + +}; diff --git a/variants/Bario/rules.html b/variants/Bario/rules.html new file mode 100644 index 0000000..c65158e --- /dev/null +++ b/variants/Bario/rules.html @@ -0,0 +1 @@ +<p>TODO</p> diff --git a/variants/Bario/style.css b/variants/Bario/style.css new file mode 100644 index 0000000..76aab16 --- /dev/null +++ b/variants/Bario/style.css @@ -0,0 +1,8 @@ +@import url("/base_pieces.css"); + +piece.white.undefined { + background-image: url('/pieces/white_mystery.svg'); +} +piece.black.undefined { + background-image: url('/pieces/black_mystery.svg'); +} diff --git a/variants/Chakart/style.css b/variants/Chakart/style.css index 91ad633..f1a38bc 100644 --- a/variants/Chakart/style.css +++ b/variants/Chakart/style.css @@ -32,11 +32,11 @@ piece.remote-capture { background-image: url('/pieces/Chakart/shell.svg'); } -piece.mystery.white { - background-image: url('/pieces/Chakart/mystery_white.svg'); +piece.white.mystery { + background-image: url('/pieces/white_mystery.svg'); } -piece.mystery.black { - background-image: url('/pieces/Chakart/mystery_black.svg'); +piece.black.mystery { + background-image: url('/pieces/black_mystery.svg'); } div.bonus-text { diff --git a/variants/Giveaway/class.js b/variants/Giveaway/class.js index 15a8998..39f586c 100644 --- a/variants/Giveaway/class.js +++ b/variants/Giveaway/class.js @@ -42,7 +42,7 @@ export default class GiveawayRules extends ChessRules { let fen = ""; if (this.options["randomness"] == 0) - fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w 0"; + fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR"; else { let pieces = { w: new Array(8), b: new Array(8) }; for (let c of ["w", "b"]) { @@ -69,8 +69,7 @@ export default class GiveawayRules extends ChessRules { fen = ( pieces["b"].join("") + "/pppppppp/8/8/8/8/PPPPPPPP/" + - pieces["w"].join("").toUpperCase() + - " w 0" + pieces["w"].join("").toUpperCase() ); } return { fen: fen, o: {} }; diff --git a/variants/Hex/class.js b/variants/Hex/class.js index b82af41..774de17 100644 --- a/variants/Hex/class.js +++ b/variants/Hex/class.js @@ -78,7 +78,7 @@ export default class HexRules extends AbstractClickFillRules { // NOTE: size.x == size.y (square boards) const emptyCount = C.FenEmptySquares(this.size.x); return { - fen: (emptyCount + "/").repeat(this.size.x).slice(0, -1) + " w 0", + fen: (emptyCount + "/").repeat(this.size.x - 1) + emptyCount, o: {} }; }