1 import { ChessRules
, PiPo
} from "@/base_rules";
3 export const VariantRules
= class MagneticRules
extends ChessRules
{
4 static get HasEnpassant() {
8 getPotentialMovesFrom([x
, y
]) {
9 let standardMoves
= super.getPotentialMovesFrom([x
, y
]);
11 standardMoves
.forEach(m
=> {
12 let newMove_s
= this.applyMagneticLaws(m
);
13 if (newMove_s
.length
== 1) moves
.push(newMove_s
[0]);
15 else moves
= moves
.concat(newMove_s
);
20 // Complete a move with magnetic actions
21 // TODO: job is done multiple times for (normal) promotions.
22 applyMagneticLaws(move) {
23 if (move.appear
[0].p
== V
.KING
&& move.appear
.length
== 1) return [move]; //kings are not charged
24 const aIdx
= move.appear
[0].p
!= V
.KING
? 0 : 1; //if castling, rook is charged
25 const [x
, y
] = [move.appear
[aIdx
].x
, move.appear
[aIdx
].y
];
26 const color
= this.turn
;
27 const lastRank
= color
== "w" ? 0 : 7;
28 const standardMove
= JSON
.parse(JSON
.stringify(move));
29 this.play(standardMove
);
36 let [i
, j
] = [x
+ step
[0], y
+ step
[1]];
37 while (V
.OnBoard(i
, j
)) {
38 if (this.board
[i
][j
] != V
.EMPTY
) {
39 // Found something. Same color or not?
40 if (this.getColor(i
, j
) != color
) {
43 (Math
.abs(i
- x
) >= 2 || Math
.abs(j
- y
) >= 2) &&
44 this.getPiece(i
, j
) != V
.KING
48 p: this.getPiece(i
, j
),
49 c: this.getColor(i
, j
),
56 p: this.getPiece(i
, j
),
57 c: this.getColor(i
, j
),
65 if (this.getPiece(i
, j
) != V
.KING
) {
66 // Push it until we meet an obstacle or edge of the board
67 let [ii
, jj
] = [i
+ step
[0], j
+ step
[1]];
68 while (V
.OnBoard(ii
, jj
)) {
69 if (this.board
[ii
][jj
] != V
.EMPTY
) break;
75 if (Math
.abs(ii
- i
) >= 1 || Math
.abs(jj
- j
) >= 1) {
78 p: this.getPiece(i
, j
),
79 c: this.getColor(i
, j
),
86 p: this.getPiece(i
, j
),
87 c: this.getColor(i
, j
),
101 this.undo(standardMove
);
103 // Scan move for pawn (max 1) on 8th rank
104 for (let i
= 1; i
< move.appear
.length
; i
++) {
106 move.appear
[i
].p
== V
.PAWN
&&
107 move.appear
[i
].c
== color
&&
108 move.appear
[i
].x
== lastRank
110 move.appear
[i
].p
= V
.ROOK
;
112 for (let piece
of [V
.KNIGHT
, V
.BISHOP
, V
.QUEEN
]) {
113 let cmove
= JSON
.parse(JSON
.stringify(move));
114 cmove
.appear
[i
].p
= piece
;
117 // Swap appear[i] and appear[0] for moves presentation (TODO: this is awkward)
119 let tmp
= m
.appear
[0];
120 m
.appear
[0] = m
.appear
[i
];
126 if (moves
.length
== 0)
127 //no pawn on 8th rank
133 if (this.kingPos
[this.turn
][0] < 0) return false;
134 return true; //TODO: is it right?
138 return false; //there is no check
145 updateVariables(move) {
146 super.updateVariables(move);
147 const c
= move.vanish
[0].c
;
148 if (move.vanish
.length
>= 2 && move.vanish
[1].p
== V
.KING
) {
149 // We took opponent king !
150 const oppCol
= V
.GetOppCol(c
);
151 this.kingPos
[oppCol
] = [-1, -1];
152 this.castleFlags
[oppCol
] = [false, false];
154 // Did we magnetically move our (init) rooks or opponents' ones ?
155 const firstRank
= c
== "w" ? 7 : 0;
156 const oppFirstRank
= 7 - firstRank
;
157 const oppCol
= V
.GetOppCol(c
);
158 move.vanish
.forEach(psq
=> {
159 if (psq
.x
== firstRank
&& this.INIT_COL_ROOK
[c
].includes(psq
.y
))
160 this.castleFlags
[c
][psq
.y
== this.INIT_COL_ROOK
[c
][0] ? 0 : 1] = false;
162 psq
.x
== oppFirstRank
&&
163 this.INIT_COL_ROOK
[oppCol
].includes(psq
.y
)
165 this.castleFlags
[oppCol
][
166 psq
.y
== this.INIT_COL_ROOK
[oppCol
][0] ? 0 : 1
171 unupdateVariables(move) {
172 super.unupdateVariables(move);
173 const c
= move.vanish
[0].c
;
174 const oppCol
= V
.GetOppCol(c
);
175 if (this.kingPos
[oppCol
][0] < 0) {
176 // Last move took opponent's king
177 for (let psq
of move.vanish
) {
179 this.kingPos
[oppCol
] = [psq
.x
, psq
.y
];
187 const color
= this.turn
;
188 const kp
= this.kingPos
[color
];
191 return color
== "w" ? "0-1" : "1-0";
192 if (this.atLeastOneMove())
195 return "1/2"; //no moves but kings still there
198 static get THRESHOLD_MATE() {
199 return 500; //checkmates evals may be slightly below 1000