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