From 8f57fbf250093488064401d503f1c621b122e95a Mon Sep 17 00:00:00 2001 From: Benjamin Auder Date: Sat, 4 Jun 2022 16:47:12 +0200 Subject: [PATCH] Add Giveaway. Preparing for Chakart a little more --- app.js | 9 +- base_rules.js | 3 +- variants.js | 3 +- variants/Absorption/class.js | 1 + variants/Atomic/class.js | 8 +- variants/Chakart/class.js | 164 ++++++----------------------------- variants/Giveaway/class.js | 96 ++++++++++++++++++++ variants/Giveaway/rules.html | 1 + variants/Giveaway/style.css | 1 + 9 files changed, 134 insertions(+), 152 deletions(-) create mode 100644 variants/Giveaway/class.js create mode 100644 variants/Giveaway/rules.html create mode 100644 variants/Giveaway/style.css diff --git a/app.js b/app.js index 79aa6e0..09d7815 100644 --- a/app.js +++ b/app.js @@ -454,7 +454,7 @@ function notifyMe(code) { let curMoves = [], lastFen; -const afterPlay = (move) => { +const afterPlay = (move_s) => { const callbackAfterSend = () => { curMoves = []; const result = vr.getCurrentScore(move); @@ -466,7 +466,12 @@ const afterPlay = (move) => { } }; // Pack into one moves array, then send - curMoves.push(move); + if (Array.isArray(move_s)) + // Array of simple moves (e.g. Chakart) + Array.prototype.push.apply(curMoves, move_s); + else + // Usual case + curMoves.push(move_s); if (vr.turn != playerColor) { toggleTurnIndicator(false); send("newmove", diff --git a/base_rules.js b/base_rules.js index 30e9ee5..dac7bb4 100644 --- a/base_rules.js +++ b/base_rules.js @@ -175,8 +175,6 @@ export default class ChessRules { // Setup the initial random-or-not (asymmetric-or-not) position genRandInitFen(seed) { - Random.setSeed(seed); - let fen, flags = "0707"; if (!this.options.randomness) // Deterministic: @@ -184,6 +182,7 @@ export default class ChessRules { else { // Randomize + Random.setSeed(seed); let pieces = {w: new Array(8), b: new Array(8)}; flags = ""; // Shuffle pieces on first (and last rank if randomness == 2) diff --git a/variants.js b/variants.js index 3fced3d..13dac98 100644 --- a/variants.js +++ b/variants.js @@ -62,6 +62,7 @@ const variants = [ // {name: 'Fugue', desc: 'Baroque Music'}, // {name: 'Fullcavalry', desc: 'Lancers everywhere', disp: 'Full Cavalry'}, // {name: 'Fusion', desc: 'Fusion pieces (v1)'}, + {name: 'Giveaway', desc: 'Lose all pieces'}, // {name: 'Gomoku', desc: 'Align five stones'}, // {name: 'Grand', desc: 'Big board'}, // {name: 'Grasshopper', desc: 'Long jumps over pieces'}, @@ -86,7 +87,6 @@ const variants = [ // {name: 'Konane', desc: 'Hawaiian Checkers'}, // {name: 'Koopa', desc: 'Stun & kick pieces'}, // {name: 'Koth', desc: 'King of the Hill', disp:'King of the Hill'}, -// {name: 'Losers', desc: 'Get strong at self-mate'}, // {name: 'Madhouse', desc: 'Rearrange enemy pieces'}, {name: 'Madrasi', desc: 'Paralyzed pieces'}, // {name: 'Magnetic', desc: 'Laws of attraction'}, @@ -137,7 +137,6 @@ const variants = [ // {name: 'Spartan', desc: 'Spartan versus Persians'}, // {name: 'Squatter', desc: 'Squat last rank'}, // {name: 'Stealthbomb', desc: 'Beware the bomb'}, -// {name: 'Suicide', desc: 'Lose all pieces'}, // {name: 'Suction', desc: 'Attract opposite king'}, // {name: 'Swap', desc: 'Dangerous captures'}, // {name: 'Switching', desc: "Exchange pieces' positions"}, diff --git a/variants/Absorption/class.js b/variants/Absorption/class.js index 3e8d391..66278db 100644 --- a/variants/Absorption/class.js +++ b/variants/Absorption/class.js @@ -5,6 +5,7 @@ export default class AbsorptionRules extends ChessRules { static get Options() { return { select: C.Options.select, + input: C.Options.input, styles: [ "balance", "capture", diff --git a/variants/Atomic/class.js b/variants/Atomic/class.js index cc339ff..5c73de2 100644 --- a/variants/Atomic/class.js +++ b/variants/Atomic/class.js @@ -13,14 +13,8 @@ export default class AtomicRules extends ChessRules { variable: "rempawn", type: "checkbox", defaut: false - }, - { - label: "Falling pawn", - variable: "pawnfall", - type: "checkbox", - defaut: false } - ], + ].concat(C.Options.input.filter(i => i.variable == "pawnfall")), styles: C.Options.styles.filter(s => s != "atomic") }; } diff --git a/variants/Chakart/class.js b/variants/Chakart/class.js index 69a2e4c..3cc4a1e 100644 --- a/variants/Chakart/class.js +++ b/variants/Chakart/class.js @@ -1,16 +1,13 @@ import ChessRules from "/base_rules"; import GiveawayRules from "/variants/Giveaway"; +import { ArrayFun } from "/utils/array.js"; +import { Random } from "/utils/alea.js"; +import PiPo from "/utils/PiPo.js"; +import Move from "/utils/Move.js"; // TODO + display bonus messages // + animation + multi-moves for bananas/bombs/mushrooms - - -import { ArrayFun } from "/utils/array"; -import { randInt } from "/utils/alea"; -import PiPo from "/utils/PiPo.js"; -import Move from "/utils/Move.js"; - export class ChakartRules extends ChessRules { static get Options() { @@ -30,9 +27,10 @@ export class ChakartRules extends ChessRules { }; } - static get PawnSpecs() { - return SuicideRules.PawnSpecs; + get pawnPromotions() { + return ['q', 'r', 'n', 'b', 'k']; } + get hasCastle() { return false; } @@ -80,7 +78,7 @@ export class ChakartRules extends ChessRules { return 'm'; } - static fen2board(f) { + fen2board(f) { return ( f.charCodeAt() <= 90 ? "w" + f.toLowerCase() @@ -88,89 +86,13 @@ export class ChakartRules extends ChessRules { ); } - static get PIECES() { - return ( - ChessRules.PIECES.concat( - Object.keys(V.IMMOBILIZE_DECODE)).concat( - [V.BANANA, V.BOMB, V.EGG, V.MUSHROOM, V.INVISIBLE_QUEEN]) - ); - } - - getPpath(b) { - let prefix = ""; - if ( - b[0] == 'a' || - b[1] == V.INVISIBLE_QUEEN || - Object.keys(V.IMMOBILIZE_DECODE).includes(b[1]) - ) { - prefix = "Chakart/"; - } - return prefix + b; - } - - getPPpath(m) { - if (!!m.promoteInto) return m.promoteInto; - if (m.appear.length == 0 && m.vanish.length == 1) - // King 'remote shell capture', on an adjacent square: - return this.getPpath(m.vanish[0].c + m.vanish[0].p); - let piece = m.appear[0].p; - if (Object.keys(V.IMMOBILIZE_DECODE).includes(piece)) - // Promotion by capture into immobilized piece: do not reveal! - piece = V.IMMOBILIZE_DECODE[piece]; - return this.getPpath(m.appear[0].c + piece); - } - - static ParseFen(fen) { - const fenParts = fen.split(" "); - return Object.assign( - ChessRules.ParseFen(fen), - { captured: fenParts[4] } - ); - } - - static IsGoodFen(fen) { - if (!ChessRules.IsGoodFen(fen)) return false; - const captured = V.ParseFen(fen).captured; - if (!captured || !captured.match(/^[0-9]{12,12}$/)) return false; - return true; - } - - // King can be l or L (immobilized) --> similar to Alice variant - static IsGoodPosition(position) { - if (position.length == 0) return false; - const rows = position.split("/"); - if (rows.length != V.size.x) return false; - let kings = { "k": 0, "K": 0, 'l': 0, 'L': 0 }; - for (let row of rows) { - let sumElts = 0; - for (let i = 0; i < row.length; i++) { - if (['K', 'k', 'L', 'l'].includes(row[i])) kings[row[i]]++; - if (V.PIECES.includes(row[i].toLowerCase())) sumElts++; - else { - const num = parseInt(row[i], 10); - if (isNaN(num)) return false; - sumElts += num; - } - } - if (sumElts != V.size.y) return false; - } - if (kings['k'] + kings['l'] == 0 || kings['K'] + kings['L'] == 0) - return false; - return true; - } - - static IsGoodFlags(flags) { - // 4 for Peach + Mario w, b - return !!flags.match(/^[01]{4,4}$/); - } - setFlags(fenflags) { // King can send shell? Queen can be invisible? this.powerFlags = { - w: { 'k': false, 'q': false }, - b: { 'k': false, 'q': false } + w: {k: false, q: false}, + b: {k: false, q: false} }; - for (let c of ["w", "b"]) { + for (let c of ['w', 'b']) { for (let p of ['k', 'q']) { this.powerFlags[c][p] = fenflags.charAt((c == "w" ? 0 : 2) + (p == 'k' ? 0 : 1)) == "1"; @@ -190,50 +112,28 @@ export class ChakartRules extends ChessRules { return super.getFen() + " " + this.getCapturedFen(); } - getFenForRepeat() { - return super.getFenForRepeat() + "_" + this.getCapturedFen(); - } - getCapturedFen() { - let counts = [...Array(12).fill(0)]; - let i = 0; - for (let p of V.RESERVE_PIECES) { - counts[i] = this.captured["w"][p]; - counts[6 + i] = this.captured["b"][p]; - i++; - } - return counts.join(""); + const res = ['w', 'b'].map(c => { + Object.values(this.captured[c]) + }); + return res[0].concat(res[1]).join(""); } - scanKings() {} - - setOtherVariables(fen) { - super.setOtherVariables(fen); + setOtherVariables(fenParsed) { + super.setOtherVariables(fenParsed); // Initialize captured pieces' counts from FEN - const captured = - V.ParseFen(fen).captured.split("").map(x => parseInt(x, 10)); + const allCapts = fenParsed.captured.split("").map(x => parseInt(x, 10)); + const pieces = ['p', 'r', 'n', 'b', 'q', 'k']; this.captured = { - w: { - [V.PAWN]: captured[0], - [V.ROOK]: captured[1], - [V.KNIGHT]: captured[2], - [V.BISHOP]: captured[3], - [V.QUEEN]: captured[4], - [V.KING]: captured[5] - }, - b: { - [V.PAWN]: captured[6], - [V.ROOK]: captured[7], - [V.KNIGHT]: captured[8], - [V.BISHOP]: captured[9], - [V.QUEEN]: captured[10], - [V.KING]: captured[11] - } + w: Array.toObject(pieces, allCapts.slice(0, 6)), + b: Array.toObject(pieces, allCapts.slice(6, 12)) }; this.effects = []; - this.subTurn = 1; } + + // TODO from here :::::::: + getFlagsFen() { let fen = ""; // Add power flags @@ -242,20 +142,6 @@ export class ChakartRules extends ChessRules { return fen; } - getColor(i, j) { - if (i >= V.size.x) return i == V.size.x ? "w" : "b"; - return this.board[i][j].charAt(0); - } - - getPiece(i, j) { - if (i >= V.size.x) return V.RESERVE_PIECES[j]; - return this.board[i][j].charAt(1); - } - - getReservePpath(index, color) { - return color + V.RESERVE_PIECES[index]; - } - static get RESERVE_PIECES() { return [V.PAWN, V.ROOK, V.KNIGHT, V.BISHOP, V.QUEEN, V.KING]; } @@ -1167,7 +1053,7 @@ export class ChakartRules extends ChessRules { } genRandInitFen(seed) { - const gr = new GiveawayRules({}, true); + const gr = new GiveawayRules({mode: "suicide"}, true); return ( gr.genRandInitFen(seed).slice(0, -1) + // Add Peach + Mario flags + capture counts diff --git a/variants/Giveaway/class.js b/variants/Giveaway/class.js new file mode 100644 index 0000000..77f5c74 --- /dev/null +++ b/variants/Giveaway/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 GiveawayRules extends ChessRules { + + static get Options() { + return { + select: [ + { + label: "Mode", + variable: "mode", + defaut: "suicide", + options: [ + {label: "Suicide", value: "suicide"}, + {label: "Losers", value: "losers"} + ] + } + ].concat(C.Options.select), + input: C.Options.input.filter(i => i.variable == "pawnfall"), + styles: [ + "atomic", "cannibal", "cylinder", "dark", + "madrasi", "rifle", "teleport", "zen" + ] + }; + } + + get hasFlags() { + return this.options["mode"] == "losers"; + } + + get pawnPromotions() { + let res = ['q', 'r', 'n', 'b']; + if (this.options["mode"] == "suicide") + res.push('k'); + return res; + } + + genRandInitFen(seed) { + if (this.options["randomness"] == 0) { + return ( + 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w 0 {"enpassant":"-"}' + ); + } + + Random.setSeed(seed); + let pieces = { w: new Array(8), b: new Array(8) }; + for (let c of ["w", "b"]) { + if (c == 'b' && this.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]; + } + return ( + pieces["b"].join("") + + "/pppppppp/8/8/8/8/PPPPPPPP/" + + pieces["w"].join("").toUpperCase() + + // En-passant allowed, but no flags + ' w 0 {"enpassant":"-"}' + ); + } + + constructor(o) { + o.options["capture"] = true; + super(o); + } + + underCheck([x, y], oppCol) { + if (this.options["mode"] == "suicide") + return false; + return super.underCheck([x, y], oppCol); + } + + getCurrentScore() { + if (this.atLeastOneMove()) return "*"; + // No valid move: the side who cannot move wins + return (this.turn == "w" ? "1-0" : "0-1"); + } + +}; diff --git a/variants/Giveaway/rules.html b/variants/Giveaway/rules.html new file mode 100644 index 0000000..920b382 --- /dev/null +++ b/variants/Giveaway/rules.html @@ -0,0 +1 @@ +

Win by losing all your material, or get stalemated.

diff --git a/variants/Giveaway/style.css b/variants/Giveaway/style.css new file mode 100644 index 0000000..a3550bc --- /dev/null +++ b/variants/Giveaway/style.css @@ -0,0 +1 @@ +@import url("/base_pieces.css"); -- 2.44.0