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