225489ec84e1d998944223c486e1f6d7a87d5846
1 class MagneticRules
extends ChessRules
3 static get HasEnpassant
{ return false; }
8 const parsedFen
= V
.ParseFen(fen
);
9 this.setFlags(fenParsed
.flags
);
10 this.scanKingsRooks(fen
);
13 getPotentialMovesFrom([x
,y
])
15 let standardMoves
= super.getPotentialMovesFrom([x
,y
]);
17 standardMoves
.forEach(m
=> {
18 let newMove_s
= this.applyMagneticLaws(m
);
19 if (newMove_s
.length
== 1)
20 moves
.push(newMove_s
[0]);
22 moves
= moves
.concat(newMove_s
);
27 getPotentialPawnMoves([x
,y
])
29 const color
= this.turn
;
31 const [sizeX
,sizeY
] = [V
.size
.x
,V
.size
.y
];
32 const shift
= (color
== "w" ? -1 : 1);
33 const firstRank
= (color
== 'w' ? sizeX
-1 : 0);
34 const startRank
= (color
== "w" ? sizeX
-2 : 1);
35 const lastRank
= (color
== "w" ? 0 : sizeX
-1);
37 if (x
+shift
>= 0 && x
+shift
< sizeX
&& x
+shift
!= lastRank
)
40 if (this.board
[x
+shift
][y
] == V
.EMPTY
)
42 moves
.push(this.getBasicMove([x
,y
], [x
+shift
,y
]));
43 // Next condition because variants with pawns on 1st rank allow them to jump
44 if ([startRank
,firstRank
].includes(x
) && this.board
[x
+2*shift
][y
] == V
.EMPTY
)
47 moves
.push(this.getBasicMove([x
,y
], [x
+2*shift
,y
]));
51 if (y
>0 && this.board
[x
+shift
][y
-1] != V
.EMPTY
52 && this.canTake([x
,y
], [x
+shift
,y
-1]))
54 moves
.push(this.getBasicMove([x
,y
], [x
+shift
,y
-1]));
56 if (y
<sizeY
-1 && this.board
[x
+shift
][y
+1] != V
.EMPTY
57 && this.canTake([x
,y
], [x
+shift
,y
+1]))
59 moves
.push(this.getBasicMove([x
,y
], [x
+shift
,y
+1]));
63 if (x
+shift
== lastRank
)
66 const pawnColor
= this.getColor(x
,y
); //can be different for checkered
67 let promotionPieces
= [V
.ROOK
,V
.KNIGHT
,V
.BISHOP
,V
.QUEEN
];
68 promotionPieces
.forEach(p
=> {
70 if (this.board
[x
+shift
][y
] == V
.EMPTY
)
71 moves
.push(this.getBasicMove([x
,y
], [x
+shift
,y
], {c:pawnColor
,p:p
}));
73 if (y
>0 && this.board
[x
+shift
][y
-1] != V
.EMPTY
74 && this.canTake([x
,y
], [x
+shift
,y
-1]))
76 moves
.push(this.getBasicMove([x
,y
], [x
+shift
,y
-1], {c:pawnColor
,p:p
}));
78 if (y
<sizeY
-1 && this.board
[x
+shift
][y
+1] != V
.EMPTY
79 && this.canTake([x
,y
], [x
+shift
,y
+1]))
81 moves
.push(this.getBasicMove([x
,y
], [x
+shift
,y
+1], {c:pawnColor
,p:p
}));
85 return moves
; //no en-passant
88 // Complete a move with magnetic actions
89 // TODO: job is done multiple times for (normal) promotions.
90 applyMagneticLaws(move)
92 if (move.appear
[0].p
== V
.KING
&& move.appear
.length
==1)
93 return [move]; //kings are not charged
94 const aIdx
= (move.appear
[0].p
!= V
.KING
? 0 : 1); //if castling, rook is charged
95 const [x
,y
] = [move.appear
[aIdx
].x
, move.appear
[aIdx
].y
];
96 const color
= this.turn
;
97 const lastRank
= (color
=="w" ? 0 : 7);
98 const standardMove
= JSON
.parse(JSON
.stringify(move));
99 this.play(standardMove
);
100 for (let step
of [[-1,0],[1,0],[0,-1],[0,1]])
102 let [i
,j
] = [x
+step
[0],y
+step
[1]];
103 while (V
.OnBoard(i
,j
))
105 if (this.board
[i
][j
] != V
.EMPTY
)
107 // Found something. Same color or not?
108 if (this.getColor(i
,j
) != color
)
111 if ((Math
.abs(i
-x
)>=2 || Math
.abs(j
-y
)>=2) && this.getPiece(i
,j
) != V
.KING
)
115 p:this.getPiece(i
,j
),
116 c:this.getColor(i
,j
),
123 p:this.getPiece(i
,j
),
124 c:this.getColor(i
,j
),
134 if (this.getPiece(i
,j
) != V
.KING
)
136 // Push it until we meet an obstacle or edge of the board
137 let [ii
,jj
] = [i
+step
[0],j
+step
[1]];
138 while (V
.OnBoard(ii
,jj
))
140 if (this.board
[ii
][jj
] != V
.EMPTY
)
147 if (Math
.abs(ii
-i
)>=1 || Math
.abs(jj
-j
)>=1)
151 p:this.getPiece(i
,j
),
152 c:this.getColor(i
,j
),
159 p:this.getPiece(i
,j
),
160 c:this.getColor(i
,j
),
174 this.undo(standardMove
);
176 // Scan move for pawn (max 1) on 8th rank
177 for (let i
=1; i
<move.appear
.length
; i
++)
179 if (move.appear
[i
].p
==V
.PAWN
&& move.appear
[i
].c
==color
180 && move.appear
[i
].x
==lastRank
)
182 move.appear
[i
].p
= V
.ROOK
;
184 for (let piece
of [V
.KNIGHT
, V
.BISHOP
, V
.QUEEN
])
186 let cmove
= JSON
.parse(JSON
.stringify(move));
187 cmove
.appear
[i
].p
= piece
;
190 // Swap appear[i] and appear[0] for moves presentation (TODO: this is awkward)
192 let tmp
= m
.appear
[0];
193 m
.appear
[0] = m
.appear
[i
];
199 if (moves
.length
== 0) //no pawn on 8th rank
206 if (this.kingPos
[this.turn
][0] < 0)
208 return true; //TODO: is it right?
213 return false; //there is no check
216 getCheckSquares(move)
218 const c
= this.getOppCol(this.turn
); //opponent
219 const saveKingPos
= this.kingPos
[c
]; //king might be taken
221 // The only way to be "under check" is to have lost the king (thus game over)
222 let res
= this.kingPos
[c
][0] < 0
223 ? [JSON
.parse(JSON
.stringify(saveKingPos
))]
229 updateVariables(move)
231 super.updateVariables(move);
232 const c
= this.getColor(move.start
.x
,move.start
.y
);
233 if (this.board
[move.end
.x
][move.end
.y
] != V
.EMPTY
234 && c
!= this.getColor(move.end
.x
,move.end
.y
)
235 && this.getPiece(move.end
.x
,move.end
.y
) == V
.KING
)
237 // We took opponent king !
238 const oppCol
= this.getOppCol(c
);
239 this.kingPos
[oppCol
] = [-1,-1];
240 this.castleFlags
[oppCol
] = [false,false];
242 // Did we magnetically move our (init) rooks or opponents' ones ?
243 const firstRank
= (c
== "w" ? 7 : 0);
244 const oppFirstRank
= 7 - firstRank
;
245 const oppCol
= this.getOppCol(c
);
246 move.vanish
.forEach(psq
=> {
247 if (psq
.x
== firstRank
&& this.INIT_COL_ROOK
[c
].includes(psq
.y
))
248 this.castleFlags
[c
][psq
.y
==this.INIT_COL_ROOK
[c
][0] ? 0 : 1] = false;
249 else if (psq
.x
== oppFirstRank
&& this.INIT_COL_ROOK
[oppCol
].includes(psq
.y
))
250 this.castleFlags
[oppCol
][psq
.y
==this.INIT_COL_ROOK
[oppCol
][0] ? 0 : 1] = false;
254 unupdateVariables(move)
256 super.unupdateVariables(move);
257 const c
= this.getColor(move.start
.x
,move.start
.y
);
258 const oppCol
= this.getOppCol(c
);
259 if (this.kingPos
[oppCol
][0] < 0)
261 // Last move took opponent's king
262 for (let psq
of move.vanish
)
266 this.kingPos
[oppCol
] = [psq
.x
, psq
.y
];
275 // No valid move: our king disappeared
276 return this.turn
== "w" ? "0-1" : "1-0";
279 static get THRESHOLD_MATE()
281 return 500; //checkmates evals may be slightly below 1000