Remove some redundant code [Checkered/Magnetic still buggish]
[vchess.git] / public / javascripts / variants / Checkered.js
CommitLineData
1d184b4c
BA
1class CheckeredRules extends ChessRules
2{
3 // Path to pieces
4 static getPpath(b)
5 {
6 return b[0]=='c' ? "Checkered/"+b : b;
7 }
8 static board2fen(b)
9 {
10 const checkered_codes = {
11 'p': 's',
12 'q': 't',
13 'r': 'u',
14 'b': 'c',
15 'n': 'o',
16 };
17 if (b[0]=="c")
18 return checkered_codes[b[1]];
19 return ChessRules.board2fen(b);
20 }
21 static fen2board(f)
22 {
23 const checkered_pieces = {
24 's': 'p',
25 't': 'q',
26 'u': 'r',
27 'c': 'b',
28 'o': 'n',
29 };
30 if (Object.keys(checkered_pieces).includes(f))
31 return 'c'+checkered_pieces[f];
32 return ChessRules.fen2board(f);
33 }
34
2526c041 35 setFlags(fen)
1d184b4c 36 {
2526c041
BA
37 super.setFlags(fen); //castleFlags
38 this.pawnFlags =
39 {
40 "w": new Array(8), //pawns can move 2 squares?
41 "b": new Array(8)
42 };
43 const flags = fen.split(" ")[1].substr(4); //skip first 4 digits, for castle
1d184b4c
BA
44 for (let c of ['w','b'])
45 {
46 for (let i=0; i<8; i++)
2526c041 47 this.pawnFlags[c][i] = (flags.charAt((c=='w'?0:8)+i) == '1');
1d184b4c 48 }
1d184b4c
BA
49 }
50
2526c041
BA
51 // Aggregates flags into one object
52 get flags() {
53 return [this.castleFlags, this.pawnFlags];
1d184b4c
BA
54 }
55
2526c041
BA
56 // Reverse operation
57 parseFlags(flags)
1d184b4c 58 {
2526c041
BA
59 this.castleFlags = flags[0];
60 this.pawnFlags = flags[1];
1d184b4c
BA
61 }
62
2526c041 63 canTake([x1,y1], [x2,y2])
1d184b4c 64 {
2526c041
BA
65 const color1 = this.getColor(x1,y1);
66 const color2 = this.getColor(x2,y2);
67 // Checkered aren't captured
68 return color1 != color2 && color2 != 'c' && (color1 != 'c' || color2 != this.turn);
1d184b4c
BA
69 }
70
2526c041
BA
71 // Post-processing: apply "checkerization" of standard moves
72 getPotentialMovesFrom([x,y])
1d184b4c 73 {
2526c041
BA
74 let standardMoves = super.getPotentialMovesFrom([x,y]);
75 if (this.getPiece(x,y) == VariantRules.KING)
76 return standardMoves; //king has to be treated differently (for castles)
1d184b4c 77 let moves = [];
2526c041
BA
78 standardMoves.forEach(m => {
79 if (m.vanish[0].p == VariantRules.PAWN && Math.abs(m.end.x-m.start.x)==2
80 && !this.pawnFlags[this.turn][m.start.y])
1d184b4c 81 {
2526c041 82 return; //skip forbidden 2-squares jumps
1d184b4c 83 }
2526c041
BA
84 if (m.vanish.length == 1)
85 moves.push(m); //no capture
86 else
1d184b4c 87 {
2526c041
BA
88 // A capture occured (m.vanish.length == 2)
89 m.appear[0].c = "c";
90 moves.push(JSON.parse(JSON.stringify(m)));
91 if (m.appear[0].p != m.vanish[1].p)
1d184b4c 92 {
2526c041
BA
93 // Add transformation into captured piece
94 let m2 = JSON.parse(JSON.stringify(m));
95 m2.vanish[1].p = m.appear[0].p;
96 moves.push(m2);
1d184b4c
BA
97 }
98 }
2526c041 99 });
1d184b4c
BA
100 return moves;
101 }
102
46302e64 103 canIplay(side, [x,y])
1d184b4c 104 {
46302e64
BA
105 return ((side=='w' && this.moves.length%2==0) || (side=='b' && this.moves.length%2==1))
106 && [side,'c'].includes(this.getColor(x,y));
1d184b4c
BA
107 }
108
109 // Does m2 un-do m1 ? (to disallow undoing checkered moves)
110 oppositeMoves(m1, m2)
111 {
112 return m1.appear.length == 1 && m2.appear.length == 1
113 && m1.vanish.length == 1 && m2.vanish.length == 1
1d184b4c
BA
114 && m1.start.x == m2.end.x && m1.end.x == m2.start.x
115 && m1.start.y == m2.end.y && m1.end.y == m2.start.y
116 && m1.appear[0].c == m2.vanish[0].c && m1.appear[0].p == m2.vanish[0].p
117 && m1.vanish[0].c == m2.appear[0].c && m1.vanish[0].p == m2.appear[0].p;
118 }
119
120 filterValid(moves)
121 {
122 if (moves.length == 0)
123 return [];
46302e64 124 const color = this.turn;
1d184b4c
BA
125 return moves.filter(m => {
126 const L = this.moves.length;
127 if (L > 0 && this.oppositeMoves(this.moves[L-1], m))
128 return false;
46302e64 129 return !this.underCheck(m);
1d184b4c
BA
130 });
131 }
132
46302e64
BA
133 isAttackedByPawn([x,y], colors)
134 {
135 for (let c of colors)
136 {
137 const color = (c=="c" ? this.turn : c);
138 let pawnShift = (color=="w" ? 1 : -1);
139 if (x+pawnShift>=0 && x+pawnShift<8)
140 {
141 for (let i of [-1,1])
142 {
143 if (y+i>=0 && y+i<8 && this.getPiece(x+pawnShift,y+i)==VariantRules.PAWN
144 && this.getColor(x+pawnShift,y+i)==c)
145 {
146 return true;
147 }
148 }
149 }
150 }
151 return false;
152 }
1d184b4c 153
46302e64 154 underCheck(move)
1d184b4c 155 {
46302e64 156 const color = this.turn;
1d184b4c 157 this.play(move);
46302e64 158 let res = this.isAttacked(this.kingPos[color], [this.getOppCol(color),'c']);
1d184b4c
BA
159 this.undo(move);
160 return res;
161 }
162
46302e64 163 getCheckSquares(move)
bd6ff57c
BA
164 {
165 this.play(move);
46302e64 166 const color = this.turn;
cd4cad04 167 this.moves.push(move); //artifically change turn, for checkered pawns (TODO)
46302e64 168 const kingAttacked = this.isAttacked(this.kingPos[color], [this.getOppCol(color),'c']);
bd6ff57c 169 let res = kingAttacked
46302e64 170 ? [ JSON.parse(JSON.stringify(this.kingPos[color])) ] //need to duplicate!
bd6ff57c 171 : [ ];
cd4cad04 172 this.moves.pop();
bd6ff57c
BA
173 this.undo(move);
174 return res;
175 }
176
1d184b4c
BA
177 updateVariables(move)
178 {
1d184b4c 179 const c = this.getColor(move.start.x,move.start.y);
1d184b4c 180 if (c != 'c') //checkered not concerned by castle flags
2526c041 181 super.updateVariables(move);
1d184b4c
BA
182
183 // Does it turn off a 2-squares pawn flag?
184 const secondRank = [1,6];
185 if (secondRank.includes(move.start.x) && move.vanish[0].p == VariantRules.PAWN)
2526c041 186 this.pawnFlags[move.start.x==6 ? "w" : "b"][move.start.y] = false;
1d184b4c
BA
187 }
188
46302e64 189 checkGameEnd()
1d184b4c 190 {
46302e64 191 const color = this.turn;
1d184b4c
BA
192 if (!this.isAttacked(this.kingPos[color], this.getOppCol(color))
193 && !this.isAttacked(this.kingPos[color], 'c'))
194 {
195 return "1/2";
196 }
197 // OK, checkmate
198 return color == "w" ? "0-1" : "1-0";
199 }
200
201 evalPosition()
202 {
203 const [sizeX,sizeY] = VariantRules.size;
204 let evaluation = 0;
205 //Just count material for now, considering checkered neutral (...)
206 for (let i=0; i<sizeX; i++)
207 {
208 for (let j=0; j<sizeY; j++)
209 {
210 if (this.board[i][j] != VariantRules.EMPTY)
211 {
212 const sqColor = this.getColor(i,j);
213 const sign = sqColor == "w" ? 1 : (sqColor=="b" ? -1 : 0);
214 evaluation += sign * VariantRules.VALUES[this.getPiece(i,j)];
215 }
216 }
217 }
218 return evaluation;
219 }
220
221 static GenRandInitFen()
222 {
f3802fcd 223 return ChessRules.GenRandInitFen() + "1111111111111111"; //add 16 pawns flags
1d184b4c
BA
224 }
225
226 getFlagsFen()
227 {
2526c041 228 let fen = super.getFlagsFen();
1d184b4c
BA
229 // Add pawns flags
230 for (let c of ['w','b'])
231 {
232 for (let i=0; i<8; i++)
2526c041 233 fen += this.pawnFlags[c][i] ? '1' : '0';
1d184b4c
BA
234 }
235 return fen;
236 }
237
238 getNotation(move)
239 {
240 if (move.appear.length == 2)
241 {
242 // Castle
243 if (move.end.y < move.start.y)
244 return "0-0-0";
245 else
246 return "0-0";
247 }
248
249 // Translate final square
250 let finalSquare =
251 String.fromCharCode(97 + move.end.y) + (VariantRules.size[0]-move.end.x);
252
253 let piece = this.getPiece(move.start.x, move.start.y);
254 if (piece == VariantRules.PAWN)
255 {
256 // Pawn move
257 let notation = "";
258 if (move.vanish.length > 1)
259 {
260 // Capture
261 let startColumn = String.fromCharCode(97 + move.start.y);
262 notation = startColumn + "x" + finalSquare + "=" + move.appear[0].p.toUpperCase();
263 }
264 else //no capture
265 notation = finalSquare;
266 if (move.appear.length > 0 && piece != move.appear[0].p) //promotion
267 notation += "=" + move.appear[0].p.toUpperCase();
268 return notation;
269 }
270
271 else
272 {
273 // Piece movement
274 return piece.toUpperCase() + (move.vanish.length > 1 ? "x" : "") + finalSquare
275 + (move.vanish.length > 1 ? "=" + move.appear[0].p.toUpperCase() : "");
276 }
277 }
278}