357a5eb8eadaaf178b4f88d140d504c2f29fdf98
1 class WildebeestRules
extends ChessRules
5 return ([V
.CAMEL
,V
.WILDEBEEST
].includes(b
[1]) ? "Wildebeest/" : "") + b
;
8 static get size() { return {x:10,y:11}; }
10 static get CAMEL() { return 'c'; }
11 static get WILDEBEEST() { return 'w'; }
15 return ChessRules
.PIECES
.concat([V
.CAMEL
,V
.WILDEBEEST
]);
21 ChessRules
.steps
, //add camel moves:
22 {'c': [ [-3,-1],[-3,1],[-1,-3],[-1,3],[1,-3],[1,3],[3,-1],[3,1] ]}
26 static IsGoodEnpassant(enpassant
)
30 const squares
= enpassant
.split(",");
31 if (squares
.length
> 2)
33 for (let sq
of squares
)
35 const ep
= V
.SquareToCoords(sq
);
36 if (isNaN(ep
.x
) || !V
.OnBoard(ep
))
43 // There may be 2 enPassant squares (if pawn jump 3 squares)
46 const L
= this.epSquares
.length
;
47 if (!this.epSquares
[L
-1])
48 return "-"; //no en-passant
50 this.epSquares
[L
-1].forEach(sq
=> {
51 res
+= V
.CoordsToSquare(sq
) + ",";
53 return res
.slice(0,-1); //remove last comma
56 // En-passant after 2-sq or 3-sq jumps
57 getEpSquare(moveOrSquare
)
61 if (typeof moveOrSquare
=== "string")
63 const square
= moveOrSquare
;
67 square
.split(",").forEach(sq
=> {
68 res
.push(V
.SquareToCoords(sq
));
72 // Argument is a move:
73 const move = moveOrSquare
;
74 const [sx
,sy
,ex
] = [move.start
.x
,move.start
.y
,move.end
.x
];
75 if (this.getPiece(sx
,sy
) == V
.PAWN
&& Math
.abs(sx
- ex
) >= 2)
77 const step
= (ex
-sx
) / Math
.abs(ex
-sx
);
82 if (sx
+ 2*step
!= ex
) //3-squares move
91 return undefined; //default
94 getPotentialMovesFrom([x
,y
])
96 switch (this.getPiece(x
,y
))
99 return this.getPotentialCamelMoves([x
,y
]);
101 return this.getPotentialWildebeestMoves([x
,y
]);
103 return super.getPotentialMovesFrom([x
,y
])
107 // Pawns jump 2 or 3 squares, and promote to queen or wildebeest
108 getPotentialPawnMoves([x
,y
])
110 const color
= this.turn
;
112 const [sizeX
,sizeY
] = [V
.size
.x
,V
.size
.y
];
113 const shift
= (color
== "w" ? -1 : 1);
114 const startRanks
= (color
== "w" ? [sizeX
-2,sizeX
-3] : [1,2]);
115 const lastRank
= (color
== "w" ? 0 : sizeX
-1);
117 if (x
+shift
>= 0 && x
+shift
< sizeX
&& x
+shift
!= lastRank
)
120 if (this.board
[x
+shift
][y
] == V
.EMPTY
)
122 moves
.push(this.getBasicMove([x
,y
], [x
+shift
,y
]));
123 if (startRanks
.includes(x
) && this.board
[x
+2*shift
][y
] == V
.EMPTY
)
126 moves
.push(this.getBasicMove([x
,y
], [x
+2*shift
,y
]));
127 if (x
== startRanks
[0] && this.board
[x
+3*shift
][y
] == V
.EMPTY
)
130 moves
.push(this.getBasicMove([x
,y
], [x
+3*shift
,y
]));
135 if (y
>0 && this.canTake([x
,y
], [x
+shift
,y
-1])
136 && this.board
[x
+shift
][y
-1] != V
.EMPTY
)
138 moves
.push(this.getBasicMove([x
,y
], [x
+shift
,y
-1]));
140 if (y
<sizeY
-1 && this.canTake([x
,y
], [x
+shift
,y
+1])
141 && this.board
[x
+shift
][y
+1] != V
.EMPTY
)
143 moves
.push(this.getBasicMove([x
,y
], [x
+shift
,y
+1]));
147 if (x
+shift
== lastRank
)
150 let promotionPieces
= [V
.QUEEN
,V
.WILDEBEEST
];
151 promotionPieces
.forEach(p
=> {
153 if (this.board
[x
+shift
][y
] == V
.EMPTY
)
154 moves
.push(this.getBasicMove([x
,y
], [x
+shift
,y
], {c:color
,p:p
}));
156 if (y
>0 && this.canTake([x
,y
], [x
+shift
,y
-1])
157 && this.board
[x
+shift
][y
-1] != V
.EMPTY
)
159 moves
.push(this.getBasicMove([x
,y
], [x
+shift
,y
-1], {c:color
,p:p
}));
161 if (y
<sizeY
-1 && this.canTake([x
,y
], [x
+shift
,y
+1])
162 && this.board
[x
+shift
][y
+1] != V
.EMPTY
)
164 moves
.push(this.getBasicMove([x
,y
], [x
+shift
,y
+1], {c:color
,p:p
}));
170 const Lep
= this.epSquares
.length
;
171 const epSquare
= Lep
>0 ? this.epSquares
[Lep
-1] : undefined;
174 for (let epsq
of epSquare
)
176 // TODO: some redundant checks
177 if (epsq
.x
== x
+shift
&& Math
.abs(epsq
.y
- y
) == 1)
179 var enpassantMove
= this.getBasicMove([x
,y
], [x
+shift
,epsq
.y
]);
180 enpassantMove
.vanish
.push({
184 c: this.getColor(x
,epsq
.y
)
186 moves
.push(enpassantMove
);
194 // TODO: wildebeest castle
196 getPotentialCamelMoves(sq
)
198 return this.getSlideNJumpMoves(sq
, V
.steps
[V
.CAMEL
], "oneStep");
201 getPotentialWildebeestMoves(sq
)
203 return this.getSlideNJumpMoves(
204 sq
, V
.steps
[V
.KNIGHT
].concat(V
.steps
[V
.CAMEL
]), "oneStep");
207 isAttacked(sq
, colors
)
209 return super.isAttacked(sq
, colors
)
210 || this.isAttackedByCamel(sq
, colors
)
211 || this.isAttackedByWildebeest(sq
, colors
);
214 isAttackedByCamel(sq
, colors
)
216 return this.isAttackedBySlideNJump(sq
, colors
,
217 V
.CAMEL
, V
.steps
[V
.CAMEL
], "oneStep");
220 isAttackedByWildebeest(sq
, colors
)
222 return this.isAttackedBySlideNJump(sq
, colors
, V
.WILDEBEEST
,
223 V
.steps
[V
.KNIGHT
].concat(V
.steps
[V
.CAMEL
]), "oneStep");
228 // No valid move: game is lost (stalemate is a win)
229 return this.turn
== "w" ? "0-1" : "1-0";
232 static get VALUES() {
233 return Object
.assign(
235 {'c': 3, 'w': 7} //experimental
239 static get SEARCH_DEPTH() { return 2; }
241 static GenRandInitFen()
243 let pieces
= { "w": new Array(10), "b": new Array(10) };
244 for (let c
of ["w","b"])
246 let positions
= _
.range(11);
248 // Get random squares for bishops + camels (different colors)
249 let randIndexes
= _
.sample(_
.range(6), 2).map(i
=> { return 2*i
; });
250 let bishop1Pos
= positions
[randIndexes
[0]];
251 let camel1Pos
= positions
[randIndexes
[1]];
252 // The second bishop (camel) must be on a square of different color
253 let randIndexes_tmp
= _
.sample(_
.range(5), 2).map(i
=> { return 2*i
+1; });
254 let bishop2Pos
= positions
[randIndexes_tmp
[0]];
255 let camel2Pos
= positions
[randIndexes_tmp
[1]];
256 for (let idx
of randIndexes
.concat(randIndexes_tmp
)
257 .sort((a
,b
) => { return b
-a
; })) //largest indices first
259 positions
.splice(idx
, 1);
262 let randIndex
= _
.random(6);
263 let knight1Pos
= positions
[randIndex
];
264 positions
.splice(randIndex
, 1);
265 randIndex
= _
.random(5);
266 let knight2Pos
= positions
[randIndex
];
267 positions
.splice(randIndex
, 1);
269 randIndex
= _
.random(4);
270 let queenPos
= positions
[randIndex
];
271 positions
.splice(randIndex
, 1);
273 // Random square for wildebeest
274 randIndex
= _
.random(3);
275 let wildebeestPos
= positions
[randIndex
];
276 positions
.splice(randIndex
, 1);
278 let rook1Pos
= positions
[0];
279 let kingPos
= positions
[1];
280 let rook2Pos
= positions
[2];
282 pieces
[c
][rook1Pos
] = 'r';
283 pieces
[c
][knight1Pos
] = 'n';
284 pieces
[c
][bishop1Pos
] = 'b';
285 pieces
[c
][queenPos
] = 'q';
286 pieces
[c
][camel1Pos
] = 'c';
287 pieces
[c
][camel2Pos
] = 'c';
288 pieces
[c
][wildebeestPos
] = 'w';
289 pieces
[c
][kingPos
] = 'k';
290 pieces
[c
][bishop2Pos
] = 'b';
291 pieces
[c
][knight2Pos
] = 'n';
292 pieces
[c
][rook2Pos
] = 'r';
294 return pieces
["b"].join("") +
295 "/ppppppppppp/11/11/11/11/11/11/PPPPPPPPPPP/" +
296 pieces
["w"].join("").toUpperCase() +
301 const VariantRules
= WildebeestRules
;