Add unambiguous section in the PGN + some fixes + code formatting and fix typos
[vchess.git] / client / src / variants / Magnetic.js
CommitLineData
0c3fe8a6
BA
1import { ChessRules, PiPo } from "@/base_rules";
2
32f6285e 3export class MagneticRules extends ChessRules {
6808d7a1
BA
4 static get HasEnpassant() {
5 return false;
6 }
2d7194bd 7
6808d7a1
BA
8 getPotentialMovesFrom([x, y]) {
9 let standardMoves = super.getPotentialMovesFrom([x, y]);
dac39588
BA
10 let moves = [];
11 standardMoves.forEach(m => {
12 let newMove_s = this.applyMagneticLaws(m);
6808d7a1
BA
13 if (newMove_s.length == 1) moves.push(newMove_s[0]);
14 //promotion
15 else moves = moves.concat(newMove_s);
dac39588
BA
16 });
17 return moves;
18 }
2526c041 19
dac39588
BA
20 // Complete a move with magnetic actions
21 // TODO: job is done multiple times for (normal) promotions.
6808d7a1 22 applyMagneticLaws(move) {
910d631b
BA
23 // Exception: kings are not charged
24 if (move.appear[0].p == V.KING && move.appear.length == 1) return [move];
25 // If castling, rook is charged:
26 const aIdx = move.appear[0].p != V.KING ? 0 : 1;
6808d7a1 27 const [x, y] = [move.appear[aIdx].x, move.appear[aIdx].y];
dac39588 28 const color = this.turn;
6808d7a1 29 const lastRank = color == "w" ? 0 : 7;
dac39588
BA
30 const standardMove = JSON.parse(JSON.stringify(move));
31 this.play(standardMove);
6808d7a1
BA
32 for (let step of [
33 [-1, 0],
34 [1, 0],
35 [0, -1],
36 [0, 1]
37 ]) {
38 let [i, j] = [x + step[0], y + step[1]];
39 while (V.OnBoard(i, j)) {
40 if (this.board[i][j] != V.EMPTY) {
dac39588 41 // Found something. Same color or not?
6808d7a1 42 if (this.getColor(i, j) != color) {
dac39588 43 // Attraction
6808d7a1
BA
44 if (
45 (Math.abs(i - x) >= 2 || Math.abs(j - y) >= 2) &&
46 this.getPiece(i, j) != V.KING
47 ) {
dac39588
BA
48 move.vanish.push(
49 new PiPo({
6808d7a1
BA
50 p: this.getPiece(i, j),
51 c: this.getColor(i, j),
52 x: i,
53 y: j
dac39588
BA
54 })
55 );
56 move.appear.push(
57 new PiPo({
6808d7a1
BA
58 p: this.getPiece(i, j),
59 c: this.getColor(i, j),
60 x: x + step[0],
61 y: y + step[1]
dac39588
BA
62 })
63 );
64 }
6808d7a1 65 } else {
dac39588 66 // Repulsion
6808d7a1 67 if (this.getPiece(i, j) != V.KING) {
dac39588 68 // Push it until we meet an obstacle or edge of the board
6808d7a1
BA
69 let [ii, jj] = [i + step[0], j + step[1]];
70 while (V.OnBoard(ii, jj)) {
71 if (this.board[ii][jj] != V.EMPTY) break;
dac39588
BA
72 ii += step[0];
73 jj += step[1];
74 }
75 ii -= step[0];
76 jj -= step[1];
6808d7a1 77 if (Math.abs(ii - i) >= 1 || Math.abs(jj - j) >= 1) {
dac39588
BA
78 move.vanish.push(
79 new PiPo({
6808d7a1
BA
80 p: this.getPiece(i, j),
81 c: this.getColor(i, j),
82 x: i,
83 y: j
dac39588
BA
84 })
85 );
86 move.appear.push(
87 new PiPo({
6808d7a1
BA
88 p: this.getPiece(i, j),
89 c: this.getColor(i, j),
90 x: ii,
91 y: jj
dac39588
BA
92 })
93 );
94 }
95 }
96 }
97 break;
98 }
99 i += step[0];
100 j += step[1];
101 }
102 }
103 this.undo(standardMove);
104 let moves = [];
105 // Scan move for pawn (max 1) on 8th rank
6808d7a1
BA
106 for (let i = 1; i < move.appear.length; i++) {
107 if (
108 move.appear[i].p == V.PAWN &&
109 move.appear[i].c == color &&
110 move.appear[i].x == lastRank
111 ) {
dac39588
BA
112 move.appear[i].p = V.ROOK;
113 moves.push(move);
6808d7a1 114 for (let piece of [V.KNIGHT, V.BISHOP, V.QUEEN]) {
dac39588
BA
115 let cmove = JSON.parse(JSON.stringify(move));
116 cmove.appear[i].p = piece;
117 moves.push(cmove);
118 }
2c5d7b20
BA
119 // Swap appear[i] and appear[0] for moves presentation
120 // (TODO: this is awkward)
dac39588
BA
121 moves.forEach(m => {
122 let tmp = m.appear[0];
123 m.appear[0] = m.appear[i];
124 m.appear[i] = tmp;
125 });
126 break;
127 }
128 }
6808d7a1
BA
129 if (moves.length == 0)
130 //no pawn on 8th rank
dac39588
BA
131 moves.push(move);
132 return moves;
133 }
1af36beb 134
6808d7a1
BA
135 atLeastOneMove() {
136 if (this.kingPos[this.turn][0] < 0) return false;
dac39588
BA
137 return true; //TODO: is it right?
138 }
1af36beb 139
31e9e40a
BA
140 filterValid(moves) {
141 // There are no checks
142 return moves;
dac39588 143 }
1af36beb 144
6808d7a1 145 getCheckSquares() {
dac39588
BA
146 return [];
147 }
1af36beb 148
3a2a7b5f
BA
149 postPlay(move) {
150 super.postPlay(move);
dac39588 151 const c = move.vanish[0].c;
6808d7a1 152 if (move.vanish.length >= 2 && move.vanish[1].p == V.KING) {
dac39588
BA
153 // We took opponent king !
154 const oppCol = V.GetOppCol(c);
6808d7a1 155 this.kingPos[oppCol] = [-1, -1];
3a2a7b5f 156 this.castleFlags[oppCol] = [8, 8];
dac39588
BA
157 }
158 // Did we magnetically move our (init) rooks or opponents' ones ?
6808d7a1 159 const firstRank = c == "w" ? 7 : 0;
dac39588
BA
160 const oppFirstRank = 7 - firstRank;
161 const oppCol = V.GetOppCol(c);
162 move.vanish.forEach(psq => {
3a2a7b5f
BA
163 if (
164 psq.x == firstRank &&
165 this.castleFlags[c].includes(psq.y)
166 ) {
167 this.castleFlags[c][psq.y == this.castleFlags[c][0] ? 0 : 1] = 8;
168 }
6808d7a1
BA
169 else if (
170 psq.x == oppFirstRank &&
3a2a7b5f
BA
171 this.castleFlags[oppCol].includes(psq.y)
172 ) {
2c5d7b20
BA
173 const flagIdx = (psq.y == this.castleFlags[oppCol][0] ? 0 : 1);
174 this.castleFlags[oppCol][flagIdx] = 8;
3a2a7b5f 175 }
dac39588
BA
176 });
177 }
1af36beb 178
3a2a7b5f
BA
179 postUndo(move) {
180 super.postUndo(move);
dac39588
BA
181 const c = move.vanish[0].c;
182 const oppCol = V.GetOppCol(c);
6808d7a1 183 if (this.kingPos[oppCol][0] < 0) {
dac39588 184 // Last move took opponent's king
6808d7a1
BA
185 for (let psq of move.vanish) {
186 if (psq.p == "k") {
dac39588
BA
187 this.kingPos[oppCol] = [psq.x, psq.y];
188 break;
189 }
190 }
191 }
192 }
1af36beb 193
6808d7a1 194 getCurrentScore() {
dac39588
BA
195 const color = this.turn;
196 const kp = this.kingPos[color];
6808d7a1 197 if (kp[0] < 0)
31e9e40a 198 // King disappeared
6808d7a1
BA
199 return color == "w" ? "0-1" : "1-0";
200 if (this.atLeastOneMove())
bb688df5 201 // Game not over
0c3fe8a6
BA
202 return "*";
203 return "1/2"; //no moves but kings still there
dac39588 204 }
9e42b4dd 205
6808d7a1 206 static get THRESHOLD_MATE() {
dac39588
BA
207 return 500; //checkmates evals may be slightly below 1000
208 }
b83a675a
BA
209
210 static get SEARCH_DEPTH() {
211 return 2;
212 }
6808d7a1 213};