22fd2b403f940694cc3d5501a56c1d113a1b4586
[vchess.git] / client / src / variants / Antiking.js
1 class AntikingRules extends ChessRules
2 {
3 static getPpath(b)
4 {
5 return b[1]=='a' ? "Antiking/"+b : b;
6 }
7
8 static get ANTIKING() { return 'a'; }
9
10 static get PIECES()
11 {
12 return ChessRules.PIECES.concat([V.ANTIKING]);
13 }
14
15 setOtherVariables(fen)
16 {
17 super.setOtherVariables(fen);
18 this.antikingPos = {'w':[-1,-1], 'b':[-1,-1]};
19 const rows = V.ParseFen(fen).position.split("/");
20 for (let i=0; i<rows.length; i++)
21 {
22 let k = 0;
23 for (let j=0; j<rows[i].length; j++)
24 {
25 switch (rows[i].charAt(j))
26 {
27 case 'a':
28 this.antikingPos['b'] = [i,k];
29 break;
30 case 'A':
31 this.antikingPos['w'] = [i,k];
32 break;
33 default:
34 const num = parseInt(rows[i].charAt(j));
35 if (!isNaN(num))
36 k += (num-1);
37 }
38 k++;
39 }
40 }
41 }
42
43 canTake([x1,y1], [x2,y2])
44 {
45 const piece1 = this.getPiece(x1,y1);
46 const piece2 = this.getPiece(x2,y2);
47 const color1 = this.getColor(x1,y1);
48 const color2 = this.getColor(x2,y2);
49 return piece2 != "a" &&
50 ((piece1 != "a" && color1 != color2) || (piece1 == "a" && color1 == color2));
51 }
52
53 getPotentialMovesFrom([x,y])
54 {
55 switch (this.getPiece(x,y))
56 {
57 case V.ANTIKING:
58 return this.getPotentialAntikingMoves([x,y]);
59 default:
60 return super.getPotentialMovesFrom([x,y]);
61 }
62 }
63
64 getPotentialAntikingMoves(sq)
65 {
66 return this.getSlideNJumpMoves(sq,
67 V.steps[V.ROOK].concat(V.steps[V.BISHOP]), "oneStep");
68 }
69
70 isAttacked(sq, colors)
71 {
72 return (super.isAttacked(sq, colors) || this.isAttackedByAntiking(sq, colors));
73 }
74
75 isAttackedByKing([x,y], colors)
76 {
77 if (this.getPiece(x,y) == V.ANTIKING)
78 return false; //antiking is not attacked by king
79 return this.isAttackedBySlideNJump([x,y], colors, V.KING,
80 V.steps[V.ROOK].concat(V.steps[V.BISHOP]), "oneStep");
81 }
82
83 isAttackedByAntiking([x,y], colors)
84 {
85 if ([V.KING,V.ANTIKING].includes(this.getPiece(x,y)))
86 return false; //(anti)king is not attacked by antiking
87 return this.isAttackedBySlideNJump([x,y], colors, V.ANTIKING,
88 V.steps[V.ROOK].concat(V.steps[V.BISHOP]), "oneStep");
89 }
90
91 underCheck(color)
92 {
93 const oppCol = V.GetOppCol(color);
94 let res = this.isAttacked(this.kingPos[color], [oppCol])
95 || !this.isAttacked(this.antikingPos[color], [oppCol]);
96 return res;
97 }
98
99 getCheckSquares(color)
100 {
101 let res = super.getCheckSquares(color);
102 if (!this.isAttacked(this.antikingPos[color], [V.GetOppCol(color)]))
103 res.push(JSON.parse(JSON.stringify(this.antikingPos[color])));
104 return res;
105 }
106
107 updateVariables(move)
108 {
109 super.updateVariables(move);
110 const piece = move.vanish[0].p;
111 const c = move.vanish[0].c;
112 // Update antiking position
113 if (piece == V.ANTIKING)
114 {
115 this.antikingPos[c][0] = move.appear[0].x;
116 this.antikingPos[c][1] = move.appear[0].y;
117 }
118 }
119
120 unupdateVariables(move)
121 {
122 super.unupdateVariables(move);
123 const c = move.vanish[0].c;
124 if (move.vanish[0].p == V.ANTIKING)
125 this.antikingPos[c] = [move.start.x, move.start.y];
126 }
127
128 checkGameEnd()
129 {
130 const color = this.turn;
131 const oppCol = V.GetOppCol(color);
132 if (!this.isAttacked(this.kingPos[color], [oppCol])
133 && this.isAttacked(this.antikingPos[color], [oppCol]))
134 {
135 return "1/2";
136 }
137 return color == "w" ? "0-1" : "1-0";
138 }
139
140 static get VALUES() {
141 return Object.assign(
142 ChessRules.VALUES,
143 { 'a': 1000 }
144 );
145 }
146
147 static GenRandInitFen()
148 {
149 let pieces = { "w": new Array(8), "b": new Array(8) };
150 let antikingPos = { "w": -1, "b": -1 };
151 for (let c of ["w","b"])
152 {
153 let positions = range(8);
154
155 // Get random squares for bishops, but avoid corners; because,
156 // if an antiking blocks a cornered bishop, it can never be checkmated
157 let randIndex = 2 * randInt(1,4);
158 const bishop1Pos = positions[randIndex];
159 let randIndex_tmp = 2 * randInt(3) + 1;
160 const bishop2Pos = positions[randIndex_tmp];
161 positions.splice(Math.max(randIndex,randIndex_tmp), 1);
162 positions.splice(Math.min(randIndex,randIndex_tmp), 1);
163
164 randIndex = randInt(6);
165 const knight1Pos = positions[randIndex];
166 positions.splice(randIndex, 1);
167 randIndex = randInt(5);
168 const knight2Pos = positions[randIndex];
169 positions.splice(randIndex, 1);
170
171 randIndex = randInt(4);
172 const queenPos = positions[randIndex];
173 positions.splice(randIndex, 1);
174
175 const rook1Pos = positions[0];
176 const kingPos = positions[1];
177 const rook2Pos = positions[2];
178
179 // Random squares for antikings
180 antikingPos[c] = randInt(8);
181
182 pieces[c][rook1Pos] = 'r';
183 pieces[c][knight1Pos] = 'n';
184 pieces[c][bishop1Pos] = 'b';
185 pieces[c][queenPos] = 'q';
186 pieces[c][kingPos] = 'k';
187 pieces[c][bishop2Pos] = 'b';
188 pieces[c][knight2Pos] = 'n';
189 pieces[c][rook2Pos] = 'r';
190 }
191 const ranks23_black = "pppppppp/" + (antikingPos["w"]>0?antikingPos["w"]:"")
192 + "A" + (antikingPos["w"]<7?7-antikingPos["w"]:"");
193 const ranks23_white = (antikingPos["b"]>0?antikingPos["b"]:"") + "a"
194 + (antikingPos["b"]<7?7-antikingPos["b"]:"") + "/PPPPPPPP";
195 return pieces["b"].join("") + "/" + ranks23_black +
196 "/8/8/" +
197 ranks23_white + "/" + pieces["w"].join("").toUpperCase() +
198 " w 1111 -";
199 }
200 }