1 class MagneticRules
extends ChessRules
5 return undefined; //no en-passant
8 // Complete a move with magnetic actions
9 applyMagneticLaws([x
,y
], move)
11 const standardMove
= JSON
.parse(JSON
.stringify(move));
12 this.play(standardMove
);
13 const color
= this.getColor(x
,y
);
14 const [sizeX
,sizeY
] = VariantRules
.size
;
15 for (let step
of [[-1,0],[1,0],[0,-1],[0,1]])
17 let [i
,j
] = [x
+step
[0],y
+step
[1]];
18 while (i
>=0 && i
<sizeX
&& j
>=0 && j
<sizeY
)
20 if (this.board
[i
][j
] != VariantRules
.EMPTY
)
22 // Found something. Same color or not?
23 if (this.getColor(i
,j
) != color
)
26 if ((Math
.abs(i
-x
)>=2 || Math
.abs(j
-y
)>=2)
27 && this.getPiece(i
,j
) != VariantRules
.KING
)
50 if (this.getPiece(i
,j
) != VariantRules
.KING
)
52 // Push it until we meet an obstacle or edge of the board
53 let [ii
,jj
] = [i
+step
[0],j
+step
[1]];
54 while (ii
>=0 && ii
<sizeX
&& jj
>=0 && jj
<sizeY
)
56 if (this.board
[ii
][jj
] != VariantRules
.EMPTY
)
63 if (Math
.abs(ii
-i
)>=1 || Math
.abs(jj
-j
)>=1)
90 this.undo(standardMove
);
93 // TODO: when pawn is pushed to 8th rank, apply promotions (similar change as in Checkered)
94 getBasicMove([sx
,sy
], [ex
,ey
], tr
)
101 c: !!tr
? tr
.c : this.getColor(sx
,sy
),
102 p: !!tr
? tr
.p : this.getPiece(sx
,sy
)
109 c: this.getColor(sx
,sy
),
110 p: this.getPiece(sx
,sy
)
115 if (this.board
[ex
][ey
] != VariantRules
.EMPTY
)
121 c: this.getColor(ex
,ey
),
122 p: this.getPiece(ex
,ey
)
126 this.applyMagneticLaws([ex
,ey
], mv
);
130 getPotentialPawnMoves([x
,y
])
132 const color
= this.getColor(x
,y
);
134 var V
= VariantRules
;
135 const [sizeX
,sizeY
] = VariantRules
.size
;
136 let shift
= (color
== "w" ? -1 : 1);
137 let startRank
= (color
== "w" ? sizeY
-2 : 1);
138 let firstRank
= (color
== 'w' ? sizeY
-1 : 0);
139 let lastRank
= (color
== "w" ? 0 : sizeY
-1);
141 if (x
+shift
>= 0 && x
+shift
< sizeX
&& x
+shift
!= lastRank
)
144 if (this.board
[x
+shift
][y
] == V
.EMPTY
)
146 moves
.push(this.getBasicMove([x
,y
], [x
+shift
,y
]));
147 if ([startRank
,firstRank
].includes(x
) && this.board
[x
+2*shift
][y
] == V
.EMPTY
)
150 moves
.push(this.getBasicMove([x
,y
], [x
+2*shift
,y
]));
154 if (y
>0 && this.canTake([x
,y
], [x
+shift
,y
-1]) && this.board
[x
+shift
][y
-1] != V
.EMPTY
)
155 moves
.push(this.getBasicMove([x
,y
], [x
+shift
,y
-1]));
156 if (y
<sizeY
-1 && this.canTake([x
,y
], [x
+shift
,y
+1]) && this.board
[x
+shift
][y
+1] != V
.EMPTY
)
157 moves
.push(this.getBasicMove([x
,y
], [x
+shift
,y
+1]));
160 if (x
+shift
== lastRank
)
163 let promotionPieces
= [V
.ROOK
,V
.KNIGHT
,V
.BISHOP
,V
.QUEEN
];
164 promotionPieces
.forEach(p
=> {
166 if (this.board
[x
+shift
][y
] == V
.EMPTY
)
167 moves
.push(this.getBasicMove([x
,y
], [x
+shift
,y
], {c:color
,p:p
}));
169 if (y
>0 && this.canTake([x
,y
], [x
+shift
,y
-1]) && this.board
[x
+shift
][y
-1] != V
.EMPTY
)
170 moves
.push(this.getBasicMove([x
,y
], [x
+shift
,y
-1], {c:color
,p:p
}));
171 if (y
<sizeY
-1 && this.canTake([x
,y
], [x
+shift
,y
+1]) && this.board
[x
+shift
][y
+1] != V
.EMPTY
)
172 moves
.push(this.getBasicMove([x
,y
], [x
+shift
,y
+1], {c:color
,p:p
}));
181 getCastleMoves([x
,y
])
183 const c
= this.getColor(x
,y
);
184 if (x
!= (c
=="w" ? 7 : 0) || y
!= this.INIT_COL_KING
[c
])
185 return []; //x isn't first rank, or king has moved (shortcut)
187 const V
= VariantRules
;
190 const oppCol
= this.getOppCol(c
);
193 const finalSquares
= [ [2,3], [6,5] ]; //king, then rook
195 for (let castleSide
=0; castleSide
< 2; castleSide
++) //large, then small
197 if (!this.flags
[c
][castleSide
])
199 // If this code is reached, rooks and king are on initial position
201 // Nothing on the path of the king (and no checks; OK also if y==finalSquare)?
202 let step
= finalSquares
[castleSide
][0] < y
? -1 : 1;
203 for (i
=y
; i
!=finalSquares
[castleSide
][0]; i
+=step
)
205 if (this.isAttacked([x
,i
], oppCol
) || (this.board
[x
][i
] != V
.EMPTY
&&
206 // NOTE: next check is enough, because of chessboard constraints
207 (this.getColor(x
,i
) != c
|| ![V
.KING
,V
.ROOK
].includes(this.getPiece(x
,i
)))))
209 continue castlingCheck
;
213 // Nothing on the path to the rook?
214 step
= castleSide
== 0 ? -1 : 1;
215 for (i
= y
+ step
; i
!= this.INIT_COL_ROOK
[c
][castleSide
]; i
+= step
)
217 if (this.board
[x
][i
] != V
.EMPTY
)
218 continue castlingCheck
;
220 const rookPos
= this.INIT_COL_ROOK
[c
][castleSide
];
222 // Nothing on final squares, except maybe king and castling rook?
225 if (this.board
[x
][finalSquares
[castleSide
][i
]] != V
.EMPTY
&&
226 this.getPiece(x
,finalSquares
[castleSide
][i
]) != V
.KING
&&
227 finalSquares
[castleSide
][i
] != rookPos
)
229 continue castlingCheck
;
233 // If this code is reached, castle is valid
234 let cmove
= new Move({
236 new PiPo({x:x
,y:finalSquares
[castleSide
][0],p:V
.KING
,c:c
}),
237 new PiPo({x:x
,y:finalSquares
[castleSide
][1],p:V
.ROOK
,c:c
})],
239 new PiPo({x:x
,y:y
,p:V
.KING
,c:c
}),
240 new PiPo({x:x
,y:rookPos
,p:V
.ROOK
,c:c
})],
241 end: Math
.abs(y
- rookPos
) <= 2
243 : {x:x
, y:y
+ 2 * (castleSide
==0 ? -1 : 1)}
245 this.applyMagneticLaws([x
,finalSquares
[castleSide
][1]], cmove
);
252 // TODO: verify this assertion
255 // return true; //always at least one possible move
260 return false; //there is no check
263 getCheckSquares(move)
265 const c
= this.getOppCol(this.turn
); //opponent
266 const saveKingPos
= this.kingPos
[c
]; //king might be taken
268 // The only way to be "under check" is to have lost the king (thus game over)
269 let res
= this.kingPos
[c
][0] < 0
270 ? [ JSON
.parse(JSON
.stringify(saveKingPos
)) ]
276 updateVariables(move)
278 super.updateVariables(move);
279 const c
= this.getColor(move.start
.x
,move.start
.y
);
280 if (c
!= this.getColor(move.end
.x
,move.end
.y
)
281 && this.board
[move.end
.x
][move.end
.y
] != VariantRules
.EMPTY
282 && this.getPiece(move.end
.x
,move.end
.y
) == VariantRules
.KING
)
284 // We took opponent king !
285 const oppCol
= this.getOppCol(c
);
286 this.kingPos
[oppCol
] = [-1,-1];
287 this.flags
[oppCol
] = [false,false];
291 unupdateVariables(move)
293 super.unupdateVariables(move);
294 const c
= this.getColor(move.start
.x
,move.start
.y
);
295 const oppCol
= this.getOppCol(c
);
296 if (this.kingPos
[oppCol
][0] < 0)
298 // Last move took opponent's king
299 for (let psq
of move.vanish
)
303 this.kingPos
[oppCol
] = [psq
.x
, psq
.y
];
312 if (this.checkRepetition())
315 const color
= this.turn
;
316 // TODO: do we need "atLeastOneMove()"?
317 if (this.atLeastOneMove() && this.kingPos
[color
][0] >= 0)
320 return this.checkGameEnd();
325 // No valid move: our king disappeared
326 return this.turn
== "w" ? "0-1" : "1-0";