1 import { ChessRules
, PiPo
, Move
} from "@/base_rules";
2 import { ArrayFun
} from "@/utils/array";
3 import { randInt
, shuffle
} from "@/utils/alea";
5 export const VariantRules
= class CircularRules
extends ChessRules
{
6 static get HasFlags() {
10 static get HasEnpassant() {
14 // TODO: CanFlip --> also for racing kings (answer is false)
16 // TODO: shuffle on 1st and 5th ranks
17 static GenRandInitFen() {
18 let pieces
= { w: new Array(8), b: new Array(8) };
19 // Shuffle pieces on first and last rank
20 for (let c
of ["w", "b"]) {
21 let positions
= ArrayFun
.range(8);
23 // Get random squares for bishops
24 let randIndex
= 2 * randInt(4);
25 const bishop1Pos
= positions
[randIndex
];
26 // The second bishop must be on a square of different color
27 let randIndex_tmp
= 2 * randInt(4) + 1;
28 const bishop2Pos
= positions
[randIndex_tmp
];
29 // Remove chosen squares
30 positions
.splice(Math
.max(randIndex
, randIndex_tmp
), 1);
31 positions
.splice(Math
.min(randIndex
, randIndex_tmp
), 1);
33 // Get random squares for knights
34 randIndex
= randInt(6);
35 const knight1Pos
= positions
[randIndex
];
36 positions
.splice(randIndex
, 1);
37 randIndex
= randInt(5);
38 const knight2Pos
= positions
[randIndex
];
39 positions
.splice(randIndex
, 1);
41 // Get random square for queen
42 randIndex
= randInt(4);
43 const queenPos
= positions
[randIndex
];
44 positions
.splice(randIndex
, 1);
46 // Rooks and king positions are now fixed,
47 // because of the ordering rook-king-rook
48 const rook1Pos
= positions
[0];
49 const kingPos
= positions
[1];
50 const rook2Pos
= positions
[2];
52 // Finally put the shuffled pieces in the board array
53 pieces
[c
][rook1Pos
] = "r";
54 pieces
[c
][knight1Pos
] = "n";
55 pieces
[c
][bishop1Pos
] = "b";
56 pieces
[c
][queenPos
] = "q";
57 pieces
[c
][kingPos
] = "k";
58 pieces
[c
][bishop2Pos
] = "b";
59 pieces
[c
][knight2Pos
] = "n";
60 pieces
[c
][rook2Pos
] = "r";
63 pieces
["b"].join("") +
64 "/pppppppp/8/8/8/8/PPPPPPPP/" +
65 pieces
["w"].join("").toUpperCase() +
70 // TODO: adapt this for a circular board
71 getSlideNJumpMoves([x
, y
], steps
, oneStep
) {
73 outerLoop: for (let step
of steps
) {
76 while (V
.OnBoard(i
, j
) && this.board
[i
][j
] == V
.EMPTY
) {
77 moves
.push(this.getBasicMove([x
, y
], [i
, j
]));
78 if (oneStep
!== undefined) continue outerLoop
;
82 if (V
.OnBoard(i
, j
) && this.canTake([x
, y
], [i
, j
]))
83 moves
.push(this.getBasicMove([x
, y
], [i
, j
]));
88 // TODO: adapt: all pawns go in thz same direction!
89 getPotentialPawnMoves([x
, y
]) {
90 const color
= this.turn
;
92 const [sizeX
, sizeY
] = [V
.size
.x
, V
.size
.y
];
93 const shiftX
= color
== "w" ? -1 : 1;
94 const firstRank
= color
== "w" ? sizeX
- 1 : 0;
95 const startRank
= color
== "w" ? sizeX
- 2 : 1;
96 const lastRank
= color
== "w" ? 0 : sizeX
- 1;
97 const pawnColor
= this.getColor(x
, y
); //can be different for checkered
99 // NOTE: next condition is generally true (no pawn on last rank)
100 if (x
+ shiftX
>= 0 && x
+ shiftX
< sizeX
) {
102 x
+ shiftX
== lastRank
103 ? [V
.ROOK
, V
.KNIGHT
, V
.BISHOP
, V
.QUEEN
]
105 // One square forward
106 if (this.board
[x
+ shiftX
][y
] == V
.EMPTY
) {
107 for (let piece
of finalPieces
) {
109 this.getBasicMove([x
, y
], [x
+ shiftX
, y
], {
115 // Next condition because pawns on 1st rank can generally jump
117 [startRank
, firstRank
].includes(x
) &&
118 this.board
[x
+ 2 * shiftX
][y
] == V
.EMPTY
121 moves
.push(this.getBasicMove([x
, y
], [x
+ 2 * shiftX
, y
]));
125 for (let shiftY
of [-1, 1]) {
128 y
+ shiftY
< sizeY
&&
129 this.board
[x
+ shiftX
][y
+ shiftY
] != V
.EMPTY
&&
130 this.canTake([x
, y
], [x
+ shiftX
, y
+ shiftY
])
132 for (let piece
of finalPieces
) {
134 this.getBasicMove([x
, y
], [x
+ shiftX
, y
+ shiftY
], {
147 // What are the king moves from square x,y ?
148 getPotentialKingMoves(sq
) {
149 return this.getSlideNJumpMoves(
151 V
.steps
[V
.ROOK
].concat(V
.steps
[V
.BISHOP
]),
156 // TODO: check boundaries here as well
157 isAttackedByPawn([x
, y
], colors
) {
158 for (let c
of colors
) {
159 let pawnShift
= c
== "w" ? 1 : -1;
160 if (x
+ pawnShift
>= 0 && x
+ pawnShift
< V
.size
.x
) {
161 for (let i
of [-1, 1]) {
165 this.getPiece(x
+ pawnShift
, y
+ i
) == V
.PAWN
&&
166 this.getColor(x
+ pawnShift
, y
+ i
) == c
176 // TODO: adapt this function
177 isAttackedBySlideNJump([x
, y
], colors
, piece
, steps
, oneStep
) {
178 for (let step
of steps
) {
179 let rx
= x
+ step
[0],
181 while (V
.OnBoard(rx
, ry
) && this.board
[rx
][ry
] == V
.EMPTY
&& !oneStep
) {
187 this.getPiece(rx
, ry
) === piece
&&
188 colors
.includes(this.getColor(rx
, ry
))