6ed73a8bf8131ccbbe8592d87ef3fb23e21653b2
1 class CheckeredRules
extends ChessRules
6 return b
[0]=='c' ? "Checkered/"+b : b
;
10 const checkered_codes
= {
18 return checkered_codes
[b
[1]];
19 return ChessRules
.board2fen(b
);
23 const checkered_pieces
= {
30 if (Object
.keys(checkered_pieces
).includes(f
))
31 return 'c'+checkered_pieces
[f
];
32 return ChessRules
.fen2board(f
);
38 ChessRules
.GetFlags(fen
), //castle
40 "w": new Array(8), //pawns can move 2 squares
44 const fenFlags
= fen
.split(" ")[1].substr(4); //skip first 4 digits, for castle
45 for (let c
of ['w','b'])
47 for (let i
=0; i
<8; i
++)
48 flags
[1][c
][i
] = (fenFlags
.charAt((c
=='w'?0:8)+i
) == '1');
53 canTake([x1
,y1
], [x2
,y2
])
55 const color1
= this.getColor(x1
,y1
);
56 const color2
= this.getColor(x2
,y2
);
57 // Checkered aren't captured
58 return color1
!= color2
&& color2
!= 'c' && (color1
!= 'c' || color2
!= this.turn
);
61 addCaptures([sx
,sy
], [ex
,ey
], moves
)
63 const piece
= this.getPiece(sx
,sy
);
64 if (piece
!= VariantRules
.KING
)
66 moves
.push(this.getBasicMove([sx
,sy
], [ex
,ey
], {c:'c',p:piece
}));
67 const takePiece
= this.getPiece(ex
,ey
);
68 if (takePiece
!= piece
)
69 moves
.push(this.getBasicMove([sx
,sy
], [ex
,ey
], {c:'c',p:takePiece
}));
72 moves
.push(this.getBasicMove([sx
,sy
], [ex
,ey
]));
75 // Generic method to find possible moves of non-pawn pieces ("sliding or jumping")
76 getSlideNJumpMoves([x
,y
], steps
, oneStep
)
78 const color
= this.getColor(x
,y
);
80 const [sizeX
,sizeY
] = VariantRules
.size
;
82 for (var loop
=0; loop
<steps
.length
; loop
++)
84 let step
= steps
[loop
];
87 while (i
>=0 && i
<sizeX
&& j
>=0 && j
<sizeY
&& this.board
[i
][j
] == VariantRules
.EMPTY
)
89 moves
.push(this.getBasicMove([x
,y
], [i
,j
])); //no capture
90 if (oneStep
!== undefined)
95 if (i
>=0 && i
<8 && j
>=0 && j
<8 && this.canTake([x
,y
], [i
,j
]))
96 this.addCaptures([x
,y
], [i
,j
], moves
);
101 // What are the pawn moves from square x,y considering color "color" ?
102 getPotentialPawnMoves([x
,y
])
104 const color
= this.getColor(x
,y
);
106 var V
= VariantRules
;
107 let [sizeX
,sizeY
] = VariantRules
.size
;
108 const c
= (color
== 'c' ? this.turn : color
);
109 const shift
= (c
== "w" ? -1 : 1);
110 let startRank
= (c
== "w" ? sizeY
-2 : 1);
111 let lastRank
= (c
== "w" ? 0 : sizeY
-1);
113 if (x
+shift
>= 0 && x
+shift
< sizeX
&& x
+shift
!= lastRank
)
116 if (this.board
[x
+shift
][y
] == V
.EMPTY
)
118 moves
.push(this.getBasicMove([x
,y
], [x
+shift
,y
]));
119 if (x
==startRank
&& this.board
[x
+2*shift
][y
] == V
.EMPTY
&& this.flags
[1][c
][y
])
122 moves
.push(this.getBasicMove([x
,y
], [x
+2*shift
,y
]));
126 if (y
>0 && this.canTake([x
,y
], [x
+shift
,y
-1]) && this.board
[x
+shift
][y
-1] != V
.EMPTY
)
127 this.addCaptures([x
,y
], [x
+shift
,y
-1], moves
);
128 if (y
<sizeY
-1 && this.canTake([x
,y
], [x
+shift
,y
+1]) && this.board
[x
+shift
][y
+1] != V
.EMPTY
)
129 this.addCaptures([x
,y
], [x
+shift
,y
+1], moves
);
132 if (x
+shift
== lastRank
)
135 let promotionPieces
= [V
.ROOK
,V
.KNIGHT
,V
.BISHOP
,V
.QUEEN
];
136 promotionPieces
.forEach(p
=> {
138 if (this.board
[x
+shift
][y
] == V
.EMPTY
)
139 moves
.push(this.getBasicMove([x
,y
], [x
+shift
,y
], {c:color
,p:p
}));
141 if (y
>0 && this.canTake([x
,y
], [x
+shift
,y
-1]) && this.board
[x
+shift
][y
-1] != V
.EMPTY
)
142 moves
.push(this.getBasicMove([x
,y
], [x
+shift
,y
-1], {c:'c',p:p
}));
143 if (y
<sizeY
-1 && this.canTake([x
,y
], [x
+shift
,y
+1]) && this.board
[x
+shift
][y
+1] != V
.EMPTY
)
144 moves
.push(this.getBasicMove([x
,y
], [x
+shift
,y
+1], {c:'c',p:p
}));
149 const Lep
= this.epSquares
.length
;
150 const epSquare
= Lep
>0 ? this.epSquares
[Lep
-1] : undefined;
151 if (!!epSquare
&& epSquare
.x
== x
+shift
&& Math
.abs(epSquare
.y
- y
) == 1)
153 let epStep
= epSquare
.y
- y
;
154 var enpassantMove
= this.getBasicMove([x
,y
], [x
+shift
,y
+epStep
]);
155 enpassantMove
.vanish
.push({
159 c: this.getColor(x
,y
+epStep
)
161 enpassantMove
.appear
[0].c
= 'c';
162 moves
.push(enpassantMove
);
168 getCastleMoves([x
,y
])
170 const c
= this.getColor(x
,y
);
171 if (x
!= (c
=="w" ? 7 : 0) || y
!= this.INIT_COL_KING
[c
])
172 return []; //x isn't first rank, or king has moved (shortcut)
174 const V
= VariantRules
;
177 const oppCol
= this.getOppCol(c
);
180 const finalSquares
= [ [2,3], [6,5] ]; //king, then rook
182 for (let castleSide
=0; castleSide
< 2; castleSide
++) //large, then small
184 if (!this.flags
[0][c
][castleSide
])
186 // If this code is reached, rooks and king are on initial position
188 // Nothing on the path of the king (and no checks; OK also if y==finalSquare)?
189 let step
= finalSquares
[castleSide
][0] < y
? -1 : 1;
190 for (i
=y
; i
!=finalSquares
[castleSide
][0]; i
+=step
)
192 if (this.isAttacked([x
,i
], oppCol
) || (this.board
[x
][i
] != V
.EMPTY
&&
193 // NOTE: next check is enough, because of chessboard constraints
194 (this.getColor(x
,i
) != c
|| ![V
.KING
,V
.ROOK
].includes(this.getPiece(x
,i
)))))
196 continue castlingCheck
;
200 // Nothing on the path to the rook?
201 step
= castleSide
== 0 ? -1 : 1;
202 for (i
= y
+ step
; i
!= this.INIT_COL_ROOK
[c
][castleSide
]; i
+= step
)
204 if (this.board
[x
][i
] != V
.EMPTY
)
205 continue castlingCheck
;
207 const rookPos
= this.INIT_COL_ROOK
[c
][castleSide
];
209 // Nothing on final squares, except maybe king and castling rook?
212 if (this.board
[x
][finalSquares
[castleSide
][i
]] != V
.EMPTY
&&
213 this.getPiece(x
,finalSquares
[castleSide
][i
]) != V
.KING
&&
214 finalSquares
[castleSide
][i
] != rookPos
)
216 continue castlingCheck
;
220 // If this code is reached, castle is valid
221 moves
.push( new Move({
223 new PiPo({x:x
,y:finalSquares
[castleSide
][0],p:V
.KING
,c:c
}),
224 new PiPo({x:x
,y:finalSquares
[castleSide
][1],p:V
.ROOK
,c:c
})],
226 new PiPo({x:x
,y:y
,p:V
.KING
,c:c
}),
227 new PiPo({x:x
,y:rookPos
,p:V
.ROOK
,c:c
})],
228 end: Math
.abs(y
- rookPos
) <= 2
230 : {x:x
, y:y
+ 2 * (castleSide
==0 ? -1 : 1)}
237 canIplay(side
, [x
,y
])
239 return ((side
=='w' && this.moves
.length
%2==0) || (side
=='b' && this.moves
.length
%2==1))
240 && [side
,'c'].includes(this.getColor(x
,y
));
243 // Does m2 un-do m1 ? (to disallow undoing checkered moves)
244 oppositeMoves(m1
, m2
)
246 return m1
.appear
.length
== 1 && m2
.appear
.length
== 1
247 && m1
.vanish
.length
== 1 && m2
.vanish
.length
== 1
248 && m1
.start
.x
== m2
.end
.x
&& m1
.end
.x
== m2
.start
.x
249 && m1
.start
.y
== m2
.end
.y
&& m1
.end
.y
== m2
.start
.y
250 && m1
.appear
[0].c
== m2
.vanish
[0].c
&& m1
.appear
[0].p
== m2
.vanish
[0].p
251 && m1
.vanish
[0].c
== m2
.appear
[0].c
&& m1
.vanish
[0].p
== m2
.appear
[0].p
;
256 if (moves
.length
== 0)
258 const color
= this.turn
;
259 return moves
.filter(m
=> {
260 const L
= this.moves
.length
;
261 if (L
> 0 && this.oppositeMoves(this.moves
[L
-1], m
))
263 return !this.underCheck(m
);
267 isAttackedByPawn([x
,y
], colors
)
269 for (let c
of colors
)
271 const color
= (c
=="c" ? this.turn : c
);
272 let pawnShift
= (color
=="w" ? 1 : -1);
273 if (x
+pawnShift
>=0 && x
+pawnShift
<8)
275 for (let i
of [-1,1])
277 if (y
+i
>=0 && y
+i
<8 && this.getPiece(x
+pawnShift
,y
+i
)==VariantRules
.PAWN
278 && this.getColor(x
+pawnShift
,y
+i
)==c
)
290 const color
= this.turn
;
292 let res
= this.isAttacked(this.kingPos
[color
], [this.getOppCol(color
),'c']);
297 getCheckSquares(move)
300 const color
= this.turn
;
301 this.moves
.push(move); //artifically change turn, for checkered pawns (TODO)
302 const kingAttacked
= this.isAttacked(this.kingPos
[color
], [this.getOppCol(color
),'c']);
303 let res
= kingAttacked
304 ? [ JSON
.parse(JSON
.stringify(this.kingPos
[color
])) ] //need to duplicate!
311 updateVariables(move)
313 const piece
= this.getPiece(move.start
.x
,move.start
.y
);
314 const c
= this.getColor(move.start
.x
,move.start
.y
);
316 if (c
!= 'c') //checkered not concerned by castle flags
318 const firstRank
= (c
== "w" ? 7 : 0);
319 // Update king position + flags
320 if (piece
== VariantRules
.KING
&& move.appear
.length
> 0)
322 this.kingPos
[c
][0] = move.appear
[0].x
;
323 this.kingPos
[c
][1] = move.appear
[0].y
;
324 this.flags
[0][c
] = [false,false];
327 const oppCol
= this.getOppCol(c
);
328 const oppFirstRank
= 7 - firstRank
;
329 if (move.start
.x
== firstRank
//our rook moves?
330 && this.INIT_COL_ROOK
[c
].includes(move.start
.y
))
332 const flagIdx
= move.start
.y
== this.INIT_COL_ROOK
[c
][0] ? 0 : 1;
333 this.flags
[0][c
][flagIdx
] = false;
335 else if (move.end
.x
== oppFirstRank
//we took opponent rook?
336 && this.INIT_COL_ROOK
[c
].includes(move.end
.y
))
338 const flagIdx
= move.end
.y
== this.INIT_COL_ROOK
[oppCol
][0] ? 0 : 1;
339 this.flags
[0][oppCol
][flagIdx
] = false;
343 // Does it turn off a 2-squares pawn flag?
344 const secondRank
= [1,6];
345 if (secondRank
.includes(move.start
.x
) && move.vanish
[0].p
== VariantRules
.PAWN
)
346 this.flags
[1][move.start
.x
==6 ? "w" : "b"][move.start
.y
] = false;
351 const color
= this.turn
;
352 if (!this.isAttacked(this.kingPos
[color
], this.getOppCol(color
))
353 && !this.isAttacked(this.kingPos
[color
], 'c'))
358 return color
== "w" ? "0-1" : "1-0";
363 const [sizeX
,sizeY
] = VariantRules
.size
;
365 //Just count material for now, considering checkered neutral (...)
366 for (let i
=0; i
<sizeX
; i
++)
368 for (let j
=0; j
<sizeY
; j
++)
370 if (this.board
[i
][j
] != VariantRules
.EMPTY
)
372 const sqColor
= this.getColor(i
,j
);
373 const sign
= sqColor
== "w" ? 1 : (sqColor
=="b" ? -1 : 0);
374 evaluation
+= sign
* VariantRules
.VALUES
[this.getPiece(i
,j
)];
381 static GenRandInitFen()
383 return ChessRules
.GenRandInitFen() + "1111111111111111"; //add 16 pawns flags
389 // Add castling flags
390 for (let c
of ['w','b'])
392 for (let i
=0; i
<2; i
++)
393 fen
+= this.flags
[0][c
][i
] ? '1' : '0';
396 for (let c
of ['w','b'])
398 for (let i
=0; i
<8; i
++)
399 fen
+= this.flags
[1][c
][i
] ? '1' : '0';
406 if (move.appear
.length
== 2)
409 if (move.end
.y
< move.start
.y
)
415 // Translate final square
417 String
.fromCharCode(97 + move.end
.y
) + (VariantRules
.size
[0]-move.end
.x
);
419 let piece
= this.getPiece(move.start
.x
, move.start
.y
);
420 if (piece
== VariantRules
.PAWN
)
424 if (move.vanish
.length
> 1)
427 let startColumn
= String
.fromCharCode(97 + move.start
.y
);
428 notation
= startColumn
+ "x" + finalSquare
+ "=" + move.appear
[0].p
.toUpperCase();
431 notation
= finalSquare
;
432 if (move.appear
.length
> 0 && piece
!= move.appear
[0].p
) //promotion
433 notation
+= "=" + move.appear
[0].p
.toUpperCase();
440 return piece
.toUpperCase() + (move.vanish
.length
> 1 ? "x" : "") + finalSquare
441 + (move.vanish
.length
> 1 ? "=" + move.appear
[0].p
.toUpperCase() : "");