Started code review + some fixes (unfinished)
[vchess.git] / client / src / variants / Magnetic.js
CommitLineData
0c3fe8a6
BA
1import { ChessRules, PiPo } from "@/base_rules";
2
6808d7a1
BA
3export const VariantRules = class MagneticRules extends ChessRules {
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
BA
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];
dac39588 26 const color = this.turn;
6808d7a1 27 const lastRank = color == "w" ? 0 : 7;
dac39588
BA
28 const standardMove = JSON.parse(JSON.stringify(move));
29 this.play(standardMove);
6808d7a1
BA
30 for (let step of [
31 [-1, 0],
32 [1, 0],
33 [0, -1],
34 [0, 1]
35 ]) {
36 let [i, j] = [x + step[0], y + step[1]];
37 while (V.OnBoard(i, j)) {
38 if (this.board[i][j] != V.EMPTY) {
dac39588 39 // Found something. Same color or not?
6808d7a1 40 if (this.getColor(i, j) != color) {
dac39588 41 // Attraction
6808d7a1
BA
42 if (
43 (Math.abs(i - x) >= 2 || Math.abs(j - y) >= 2) &&
44 this.getPiece(i, j) != V.KING
45 ) {
dac39588
BA
46 move.vanish.push(
47 new PiPo({
6808d7a1
BA
48 p: this.getPiece(i, j),
49 c: this.getColor(i, j),
50 x: i,
51 y: j
dac39588
BA
52 })
53 );
54 move.appear.push(
55 new PiPo({
6808d7a1
BA
56 p: this.getPiece(i, j),
57 c: this.getColor(i, j),
58 x: x + step[0],
59 y: y + step[1]
dac39588
BA
60 })
61 );
62 }
6808d7a1 63 } else {
dac39588 64 // Repulsion
6808d7a1 65 if (this.getPiece(i, j) != V.KING) {
dac39588 66 // Push it until we meet an obstacle or edge of the board
6808d7a1
BA
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;
dac39588
BA
70 ii += step[0];
71 jj += step[1];
72 }
73 ii -= step[0];
74 jj -= step[1];
6808d7a1 75 if (Math.abs(ii - i) >= 1 || Math.abs(jj - j) >= 1) {
dac39588
BA
76 move.vanish.push(
77 new PiPo({
6808d7a1
BA
78 p: this.getPiece(i, j),
79 c: this.getColor(i, j),
80 x: i,
81 y: j
dac39588
BA
82 })
83 );
84 move.appear.push(
85 new PiPo({
6808d7a1
BA
86 p: this.getPiece(i, j),
87 c: this.getColor(i, j),
88 x: ii,
89 y: jj
dac39588
BA
90 })
91 );
92 }
93 }
94 }
95 break;
96 }
97 i += step[0];
98 j += step[1];
99 }
100 }
101 this.undo(standardMove);
102 let moves = [];
103 // Scan move for pawn (max 1) on 8th rank
6808d7a1
BA
104 for (let i = 1; i < move.appear.length; i++) {
105 if (
106 move.appear[i].p == V.PAWN &&
107 move.appear[i].c == color &&
108 move.appear[i].x == lastRank
109 ) {
dac39588
BA
110 move.appear[i].p = V.ROOK;
111 moves.push(move);
6808d7a1 112 for (let piece of [V.KNIGHT, V.BISHOP, V.QUEEN]) {
dac39588
BA
113 let cmove = JSON.parse(JSON.stringify(move));
114 cmove.appear[i].p = piece;
115 moves.push(cmove);
116 }
117 // Swap appear[i] and appear[0] for moves presentation (TODO: this is awkward)
118 moves.forEach(m => {
119 let tmp = m.appear[0];
120 m.appear[0] = m.appear[i];
121 m.appear[i] = tmp;
122 });
123 break;
124 }
125 }
6808d7a1
BA
126 if (moves.length == 0)
127 //no pawn on 8th rank
dac39588
BA
128 moves.push(move);
129 return moves;
130 }
1af36beb 131
6808d7a1
BA
132 atLeastOneMove() {
133 if (this.kingPos[this.turn][0] < 0) return false;
dac39588
BA
134 return true; //TODO: is it right?
135 }
1af36beb 136
6808d7a1 137 underCheck() {
dac39588
BA
138 return false; //there is no check
139 }
1af36beb 140
6808d7a1 141 getCheckSquares() {
dac39588
BA
142 return [];
143 }
1af36beb 144
6808d7a1 145 updateVariables(move) {
dac39588
BA
146 super.updateVariables(move);
147 const c = move.vanish[0].c;
6808d7a1 148 if (move.vanish.length >= 2 && move.vanish[1].p == V.KING) {
dac39588
BA
149 // We took opponent king !
150 const oppCol = V.GetOppCol(c);
6808d7a1
BA
151 this.kingPos[oppCol] = [-1, -1];
152 this.castleFlags[oppCol] = [false, false];
dac39588
BA
153 }
154 // Did we magnetically move our (init) rooks or opponents' ones ?
6808d7a1 155 const firstRank = c == "w" ? 7 : 0;
dac39588
BA
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))
6808d7a1
BA
160 this.castleFlags[c][psq.y == this.INIT_COL_ROOK[c][0] ? 0 : 1] = false;
161 else if (
162 psq.x == oppFirstRank &&
163 this.INIT_COL_ROOK[oppCol].includes(psq.y)
164 )
165 this.castleFlags[oppCol][
166 psq.y == this.INIT_COL_ROOK[oppCol][0] ? 0 : 1
167 ] = false;
dac39588
BA
168 });
169 }
1af36beb 170
6808d7a1 171 unupdateVariables(move) {
dac39588
BA
172 super.unupdateVariables(move);
173 const c = move.vanish[0].c;
174 const oppCol = V.GetOppCol(c);
6808d7a1 175 if (this.kingPos[oppCol][0] < 0) {
dac39588 176 // Last move took opponent's king
6808d7a1
BA
177 for (let psq of move.vanish) {
178 if (psq.p == "k") {
dac39588
BA
179 this.kingPos[oppCol] = [psq.x, psq.y];
180 break;
181 }
182 }
183 }
184 }
1af36beb 185
6808d7a1 186 getCurrentScore() {
dac39588
BA
187 const color = this.turn;
188 const kp = this.kingPos[color];
6808d7a1
BA
189 if (kp[0] < 0)
190 //king disappeared
191 return color == "w" ? "0-1" : "1-0";
192 if (this.atLeastOneMove())
193 // game not over
0c3fe8a6
BA
194 return "*";
195 return "1/2"; //no moves but kings still there
dac39588 196 }
9e42b4dd 197
6808d7a1 198 static get THRESHOLD_MATE() {
dac39588
BA
199 return 500; //checkmates evals may be slightly below 1000
200 }
6808d7a1 201};