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