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