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