1 import { ChessRules
, Move
, PiPo
} from "@/base_rules";
2 import { ArrayFun
} from "@/utils/array";
3 import { randInt
} from "@/utils/alea";
5 export class ColorboundRules
extends ChessRules
{
7 static get PawnSpecs() {
13 ChessRules
.PawnSpecs
.promotions
.concat(
14 [V
.C_ROOK
, V
.C_KNIGHT
, V
.C_BISHOP
, V
.C_QUEEN
])
20 if ([V
.C_ROOK
, V
.C_KNIGHT
, V
.C_BISHOP
, V
.C_QUEEN
].includes(b
[1]))
21 return "Colorbound/" + b
;
25 static GenRandInitFen(randomness
) {
27 return "dhaskahd/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w 0 ahah -";
29 // Mapping white --> black (at least at start):
38 let pieces
= { w: new Array(8), b: new Array(8) };
40 // Shuffle pieces on first (and last rank if randomness == 2)
41 for (let c
of ["w", "b"]) {
42 if (c
== 'b' && randomness
== 1) {
43 pieces
['b'] = pieces
['w'].map(p
=> piecesMap
[p
]);
48 // TODO: same code as in base_rules. Should extract and factorize?
50 let positions
= ArrayFun
.range(8);
52 let randIndex
= 2 * randInt(4);
53 const bishop1Pos
= positions
[randIndex
];
54 let randIndex_tmp
= 2 * randInt(4) + 1;
55 const bishop2Pos
= positions
[randIndex_tmp
];
56 positions
.splice(Math
.max(randIndex
, randIndex_tmp
), 1);
57 positions
.splice(Math
.min(randIndex
, randIndex_tmp
), 1);
59 randIndex
= randInt(6);
60 const knight1Pos
= positions
[randIndex
];
61 positions
.splice(randIndex
, 1);
62 randIndex
= randInt(5);
63 const knight2Pos
= positions
[randIndex
];
64 positions
.splice(randIndex
, 1);
66 randIndex
= randInt(4);
67 const queenPos
= positions
[randIndex
];
68 positions
.splice(randIndex
, 1);
70 const rook1Pos
= positions
[0];
71 const kingPos
= positions
[1];
72 const rook2Pos
= positions
[2];
74 pieces
[c
][rook1Pos
] = "r";
75 pieces
[c
][knight1Pos
] = "n";
76 pieces
[c
][bishop1Pos
] = "b";
77 pieces
[c
][queenPos
] = "q";
78 pieces
[c
][kingPos
] = "k";
79 pieces
[c
][bishop2Pos
] = "b";
80 pieces
[c
][knight2Pos
] = "n";
81 pieces
[c
][rook2Pos
] = "r";
82 if (c
== 'b') pieces
[c
] = pieces
[c
].map(p
=> piecesMap
[p
]);
83 flags
+= V
.CoordToColumn(rook1Pos
) + V
.CoordToColumn(rook2Pos
);
85 // Add turn + flags + enpassant
87 pieces
["b"].join("") +
88 "/pppppppp/8/8/8/8/PPPPPPPP/" +
89 pieces
["w"].join("").toUpperCase() +
90 " w 0 " + flags
+ " -"
97 static get C_KNIGHT() {
100 static get C_BISHOP() {
103 static get C_QUEEN() {
107 static get PIECES() {
109 ChessRules
.PIECES
.concat([V
.C_ROOK
, V
.C_KNIGHT
, V
.C_BISHOP
, V
.C_QUEEN
])
113 getPotentialMovesFrom([x
, y
]) {
114 switch (this.getPiece(x
, y
)) {
116 return this.getPotentialC_rookMoves([x
, y
]);
118 return this.getPotentialC_knightMoves([x
, y
]);
120 return this.getPotentialC_bishopMoves([x
, y
]);
122 return this.getPotentialC_queenMoves([x
, y
]);
124 return super.getPotentialMovesFrom([x
, y
]);
130 return Object
.assign(
159 getPotentialC_rookMoves(sq
) {
161 this.getSlideNJumpMoves(sq
, V
.steps
[V
.BISHOP
]).concat(
162 this.getSlideNJumpMoves(sq
, V
.steps
['d'], "oneStep"))
166 getPotentialC_knightMoves(sq
) {
168 this.getSlideNJumpMoves(sq
, V
.steps
['a'], "oneStep").concat(
169 this.getSlideNJumpMoves(sq
, V
.steps
[V
.ROOK
], "oneStep"))
173 getPotentialC_bishopMoves(sq
) {
175 this.getSlideNJumpMoves(sq
, V
.steps
['d'], "oneStep").concat(
176 this.getSlideNJumpMoves(sq
, V
.steps
['a'], "oneStep")).concat(
177 this.getSlideNJumpMoves(sq
, V
.steps
[V
.BISHOP
], "oneStep"))
181 getPotentialC_queenMoves(sq
) {
183 this.getSlideNJumpMoves(sq
, V
.steps
[V
.BISHOP
]).concat(
184 this.getSlideNJumpMoves(sq
, V
.steps
[V
.KNIGHT
], "oneStep"))
188 getCastleMoves([x
, y
]) {
189 const color
= this.getColor(x
, y
);
190 const finalSquares
= [
191 // Black castle long in an unusual way:
192 (color
== 'w' ? [2, 3] : [1, 2]),
193 [V
.size
.y
- 2, V
.size
.y
- 3]
195 return super.getCastleMoves([x
, y
], finalSquares
);
198 isAttacked(sq
, color
) {
200 super.isAttacked(sq
, color
) ||
201 this.isAttackedByC_rook(sq
, color
) ||
202 this.isAttackedByC_knight(sq
, color
) ||
203 this.isAttackedByC_bishop(sq
, color
) ||
204 this.isAttackedByC_queen(sq
, color
)
208 isAttackedByC_rook(sq
, color
) {
210 this.isAttackedBySlideNJump(sq
, color
, V
.C_ROOK
, V
.steps
[V
.BISHOP
]) ||
211 this.isAttackedBySlideNJump(
212 sq
, color
, V
.C_ROOK
, V
.steps
['d'], "oneStep")
216 isAttackedByC_knight(sq
, color
) {
218 this.isAttackedBySlideNJump(
219 sq
, color
, V
.C_KNIGHT
, V
.steps
[V
.ROOK
], "oneStep") ||
220 this.isAttackedBySlideNJump(
221 sq
, color
, V
.C_KNIGHT
, V
.steps
['a'], "oneStep")
225 isAttackedByC_bishop(sq
, color
) {
227 this.isAttackedBySlideNJump(
228 sq
, color
, V
.C_BISHOP
, V
.steps
['d'], "oneStep") ||
229 this.isAttackedBySlideNJump(
230 sq
, color
, V
.C_BISHOP
, V
.steps
['a'], "oneStep") ||
231 this.isAttackedBySlideNJump(
232 sq
, color
, V
.C_BISHOP
, V
.steps
['f'], "oneStep")
236 isAttackedByC_queen(sq
, color
) {
238 this.isAttackedBySlideNJump(sq
, color
, V
.C_QUEEN
, V
.steps
[V
.BISHOP
]) ||
239 this.isAttackedBySlideNJump(
240 sq
, color
, V
.C_QUEEN
, V
.steps
[V
.KNIGHT
], "oneStep")
244 static get VALUES() {
245 return Object
.assign(
257 static get SEARCH_DEPTH() {