X-Git-Url: https://git.auder.net/?a=blobdiff_plain;f=client%2Fsrc%2Fvariants%2FBall.js;h=ceddb61a8e3be97099c24f6f53002250ee18b671;hb=107dc1bd5361e2538b1551bdcc37c1e90a444b83;hp=5a23e9f83b7f7022d8f6346de5920218f7572090;hpb=305ede7ec3753fc669b7c86af5b5c5b2fc78a164;p=vchess.git diff --git a/client/src/variants/Ball.js b/client/src/variants/Ball.js index 5a23e9f8..ceddb61a 100644 --- a/client/src/variants/Ball.js +++ b/client/src/variants/Ball.js @@ -1,26 +1,37 @@ import { ChessRules, Move, PiPo } from "@/base_rules"; -import { WildebeestRules } from "@/variants/Wildebeest"; import { ArrayFun } from "@/utils/array"; import { shuffle } from "@/utils/alea"; export class BallRules extends ChessRules { + static get Lines() { + return [ + // White goal: + [[0, 3], [0, 6]], + [[0, 6], [1, 6]], + [[1, 6], [1, 3]], + [[1, 3], [0, 3]], + // Black goal: + [[9, 3], [9, 6]], + [[9, 6], [8, 6]], + [[8, 6], [8, 3]], + [[8, 3], [9, 3]] + ]; + } + static get PawnSpecs() { return Object.assign( {}, ChessRules.PawnSpecs, - { promotions: ChessRules.PawnSpecs.promotions.concat([V.WILDEBEEST]) } + { promotions: ChessRules.PawnSpecs.promotions.concat([V.PHOENIX]) } ); } static get HasFlags() { return false; } - static get HasCastle() { - return false; - } - static get WILDEBEEST() { - return 'w'; + static get PHOENIX() { + return 'h'; } static get BALL() { @@ -39,10 +50,10 @@ export class BallRules extends ChessRules { 'p': 's', 'r': 'u', 'n': 'o', - 'b': 'c', + 'b': 'd', 'q': 't', 'k': 'l', - 'w': 'y' + 'h': 'i' }; } @@ -51,16 +62,16 @@ export class BallRules extends ChessRules { 's': 'p', 'u': 'r', 'o': 'n', - 'c': 'b', + 'd': 'b', 't': 'q', 'l': 'k', - 'y': 'w' + 'i': 'h' }; } static get PIECES() { return ChessRules.PIECES - .concat([V.WILDEBEEST]) + .concat([V.PHOENIX]) .concat(Object.keys(V.HAS_BALL_DECODE)) .concat(['a']); } @@ -109,27 +120,34 @@ export class BallRules extends ChessRules { let prefix = ""; const withPrefix = Object.keys(V.HAS_BALL_DECODE) - .concat([V.WILDEBEEST]) + .concat([V.PHOENIX]) .concat(['a']); if (withPrefix.includes(b[1])) prefix = "Ball/"; return prefix + b; } canTake([x1, y1], [x2, y2]) { - // Capture enemy or pass ball to friendly pieces + if (this.getColor(x1, y1) !== this.getColor(x2, y2)) { + // The piece holding the ball cannot capture: + return ( + !(Object.keys(V.HAS_BALL_DECODE) + .includes(this.board[x1][y1].charAt(1))) + ); + } + // Pass: possible only if one of the friendly pieces has the ball return ( - this.getColor(x1, y1) !== this.getColor(x2, y2) || - Object.keys(V.HAS_BALL_DECODE).includes(this.board[x1][y1].charAt(1)) + Object.keys(V.HAS_BALL_DECODE).includes(this.board[x1][y1].charAt(1)) || + Object.keys(V.HAS_BALL_DECODE).includes(this.board[x2][y2].charAt(1)) ); } - getCheckSquares(color) { + getCheckSquares() { return []; } static GenRandInitFen(randomness) { if (randomness == 0) - return "rnbqkwnbr/ppppppppp/9/9/4a4/9/9/PPPPPPPPP/RNBQKWNBR w 0 -"; + return "hbnrqrnhb/ppppppppp/9/9/4a4/9/9/PPPPPPPPP/HBNRQRNHB w 0 -"; let pieces = { w: new Array(9), b: new Array(9) }; for (let c of ["w", "b"]) { @@ -138,17 +156,26 @@ export class BallRules extends ChessRules { break; } - // Get random squares for every piece, totally freely + // Get random squares for every piece, with bishops and phoenixes + // on different colors: let positions = shuffle(ArrayFun.range(9)); - const composition = ['b', 'b', 'r', 'r', 'n', 'n', 'k', 'q', 'w']; - const rem2 = positions[0] % 2; + const composition = ['b', 'b', 'h', 'h', 'n', 'n', 'r', 'r', 'q']; + let rem2 = positions[0] % 2; if (rem2 == positions[1] % 2) { // Fix bishops (on different colors) - for (let i=2; i<9; i++) { + for (let i=4; i<9; i++) { if (positions[i] % 2 != rem2) [positions[1], positions[i]] = [positions[i], positions[1]]; } } + rem2 = positions[2] % 2; + if (rem2 == positions[3] % 2) { + // Fix phoenixes too: + for (let i=4; i<9; i++) { + if (positions[i] % 2 != rem2) + [positions[3], positions[i]] = [positions[i], positions[3]]; + } + } for (let i = 0; i < 9; i++) pieces[c][positions[i]] = composition[i]; } return ( @@ -160,7 +187,7 @@ export class BallRules extends ChessRules { ); } - scanKings(fen) {} + scanKings() {} static get size() { return { x: 9, y: 9 }; @@ -174,7 +201,23 @@ export class BallRules extends ChessRules { } static get steps() { - return WildebeestRules.steps; + return Object.assign( + {}, + ChessRules.steps, + // Add phoenix moves + { + h: [ + [-2, -2], + [-2, 2], + [2, -2], + [2, 2], + [-1, 0], + [1, 0], + [0, -1], + [0, 1] + ] + } + ); } // Because of the ball, getPiece() could be wrong: @@ -217,15 +260,29 @@ export class BallRules extends ChessRules { ); } - // Post-processing: maybe the ball was taken, or a piece + ball + // Post-processing: maybe the ball was taken, or a piece + ball, + // or maybe a pass (ball <--> piece) if (mv.vanish.length == 2) { if ( // Take the ball? mv.vanish[1].c == 'a' || - // Capture a ball-holding piece? + // Capture a ball-holding piece? If friendly one, then adjust Object.keys(V.HAS_BALL_DECODE).includes(mv.vanish[1].p) ) { mv.appear[0].p = V.HAS_BALL_CODE[mv.appear[0].p]; + if (mv.vanish[1].c == mv.vanish[0].c) { + // "Capturing" self => pass + mv.appear[0].x = mv.start.x; + mv.appear[0].y = mv.start.y; + mv.appear.push( + new PiPo({ + x: mv.end.x, + y: mv.end.y, + p: V.HAS_BALL_DECODE[mv.vanish[1].p], + c: mv.vanish[0].c + }) + ); + } } else if (mv.vanish[1].c == mv.vanish[0].c) { // Pass the ball: the passing unit does not disappear mv.appear.push(JSON.parse(JSON.stringify(mv.vanish[0]))); @@ -242,17 +299,33 @@ export class BallRules extends ChessRules { // So base implementation is fine. getPotentialMovesFrom([x, y]) { - if (this.getPiece(x, y) == V.WILDEBEEST) - return this.getPotentialWildebeestMoves([x, y]); + if (this.getPiece(x, y) == V.PHOENIX) + return this.getPotentialPhoenixMoves([x, y]); return super.getPotentialMovesFrom([x, y]); } - getPotentialWildebeestMoves(sq) { - return this.getSlideNJumpMoves( - sq, - V.steps[V.KNIGHT].concat(V.steps[WildebeestRules.CAMEL]), - "oneStep" - ); + // "Sliders": at most 3 steps + getSlideNJumpMoves([x, y], steps, oneStep) { + let moves = []; + outerLoop: for (let step of steps) { + let i = x + step[0]; + let j = y + step[1]; + let stepCount = 1; + while (V.OnBoard(i, j) && this.board[i][j] == V.EMPTY) { + moves.push(this.getBasicMove([x, y], [i, j])); + if (oneStep || stepCount == 3) continue outerLoop; + i += step[0]; + j += step[1]; + stepCount++; + } + if (V.OnBoard(i, j) && this.canTake([x, y], [i, j])) + moves.push(this.getBasicMove([x, y], [i, j])); + } + return moves; + } + + getPotentialPhoenixMoves(sq) { + return this.getSlideNJumpMoves(sq, V.steps[V.PHOENIX], "oneStep"); } filterValid(moves) { @@ -288,12 +361,11 @@ export class BallRules extends ChessRules { static get VALUES() { return { p: 1, - r: 5, + r: 3, n: 3, - b: 3, - q: 9, - w: 7, - k: 5, + b: 2, + q: 5, + h: 3, a: 0 //ball: neutral }; }