Early draft of Wildebeest + Grand
[vchess.git] / public / javascripts / variants / Wildebeest.js
CommitLineData
a37076f1
BA
1//https://www.chessvariants.com/large.dir/wildebeest.html
2class GrandRules extends ChessRules
3{
4 static getPpath(b)
5 {
6 const V = VariantRules;
7 return ([V.CAMEL,V.WILDEBEEST].includes(b[1]) ? "Wildebeest/" : "") + b;
8 }
9
10 static get CAMEL() { return 'c'; }
11 static get WILDEBEEST() { return 'w'; }
12
13 static get steps() {
14 return Object.assign(
15 ChessRules.steps, //add camel moves:
16 {'c': [ [-3,-1],[-3,1],[-1,-3],[-1,3],[1,-3],[1,3],[3,-1],[3,1] ]}
17 );
18 }
19
20// TODO: IN epSquares (return array), not return singleton. Easy. Adapt
21// just here for now...
22 getEpSquare(move)
23 {
24 const [sx,sy,ex] = [move.start.x,move.start.y,move.end.x];
25 if (this.getPiece(sx,sy) == VariantRules.PAWN && Math.abs(sx - ex) == 2)
26 {
27 return {
28 x: (sx + ex)/2,
29 y: sy
30 };
31 }
32 return undefined; //default
33 }
34
35 getPotentialMovesFrom([x,y])
36 {
37 switch (this.getPiece(x,y))
38 {
39 case VariantRules.CAMEL:
40 return this.getPotentialCamelMoves([x,y]);
41 case VariantRules.WILDEBEEST:
42 return this.getPotentialWildebeestMoves([x,y]);
43 default:
44 return super.getPotentialMovesFrom([x,y])
45 }
46 }
47
48 // TODO: several changes (promote to queen or wildebeest)
49 getPotentialPawnMoves([x,y])
50 {
51 const color = this.turn;
52 let moves = [];
53 const V = VariantRules;
54 const [sizeX,sizeY] = VariantRules.size;
55 const shift = (color == "w" ? -1 : 1);
56 const firstRank = (color == 'w' ? sizeY-1 : 0);
57 const startRank = (color == "w" ? sizeY-2 : 1);
58 const lastRank = (color == "w" ? 0 : sizeY-1);
59
60 if (x+shift >= 0 && x+shift < sizeX && x+shift != lastRank)
61 {
62 // Normal moves
63 if (this.board[x+shift][y] == V.EMPTY)
64 {
65 moves.push(this.getBasicMove([x,y], [x+shift,y]));
66 // Next condition because variants with pawns on 1st rank generally allow them to jump
67 if ([startRank,firstRank].includes(x) && this.board[x+2*shift][y] == V.EMPTY)
68 {
69 // Two squares jump
70 moves.push(this.getBasicMove([x,y], [x+2*shift,y]));
71 }
72 }
73 // Captures
74 if (y>0 && this.canTake([x,y], [x+shift,y-1]) && this.board[x+shift][y-1] != V.EMPTY)
75 moves.push(this.getBasicMove([x,y], [x+shift,y-1]));
76 if (y<sizeY-1 && this.canTake([x,y], [x+shift,y+1]) && this.board[x+shift][y+1] != V.EMPTY)
77 moves.push(this.getBasicMove([x,y], [x+shift,y+1]));
78 }
79
80 if (x+shift == lastRank)
81 {
82 // Promotion
83 let promotionPieces = [V.ROOK,V.KNIGHT,V.BISHOP,V.QUEEN];
84 promotionPieces.forEach(p => {
85 // Normal move
86 if (this.board[x+shift][y] == V.EMPTY)
87 moves.push(this.getBasicMove([x,y], [x+shift,y], {c:color,p:p}));
88 // Captures
89 if (y>0 && this.canTake([x,y], [x+shift,y-1]) && this.board[x+shift][y-1] != V.EMPTY)
90 moves.push(this.getBasicMove([x,y], [x+shift,y-1], {c:color,p:p}));
91 if (y<sizeY-1 && this.canTake([x,y], [x+shift,y+1]) && this.board[x+shift][y+1] != V.EMPTY)
92 moves.push(this.getBasicMove([x,y], [x+shift,y+1], {c:color,p:p}));
93 });
94 }
95
96 // En passant
97 const Lep = this.epSquares.length;
98 const epSquare = Lep>0 ? this.epSquares[Lep-1] : undefined;
99 if (!!epSquare && epSquare.x == x+shift && Math.abs(epSquare.y - y) == 1)
100 {
101 let epStep = epSquare.y - y;
102 var enpassantMove = this.getBasicMove([x,y], [x+shift,y+epStep]);
103 enpassantMove.vanish.push({
104 x: x,
105 y: y+epStep,
106 p: 'p',
107 c: this.getColor(x,y+epStep)
108 });
109 moves.push(enpassantMove);
110 }
111
112 return moves;
113 }
114
115 getPotentialCamelMoves(sq)
116 {
117 return this.getSlideNJumpMoves(sq, VariantRules.steps[VariantRules.CAMEL], "oneStep");
118 }
119
120 getPotentialWildebeestMoves(sq)
121 {
122 const V = VariantRules;
123 return this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT].concat(V.steps[V.CAMEL]));
124 }
125
126 // TODO: getCastleMoves, generalize a bit to include castleSquares as static variables
127 // ==> but this won't be exactly Wildebeest... think about it.
128
129 // TODO: also generalize lastRank ==> DO NOT HARDCODE 7 !!!
130
131 isAttacked(sq, colors)
132 {
133 return (super.isAttacked(sq, colors)
134 || this.isAttackedByCamel(sq, colors)
135 || this.isAttackedByWildebeest(sq, colors);
136 }
137
138 isAttackedByCamel(sq, colors)
139 {
140 return this.isAttackedBySlideNJump(sq, colors,
141 VariantRules.CAMEL, VariantRules.steps[VariantRules.CAMEL]);
142 }
143
144 isAttackedByWildebeest(sq, colors)
145 {
146 const V = VariantRules;
147 return this.isAttackedBySlideNJump(sq, colors, V.WILDEBEEST,
148 V.steps[V.KNIGHT].concat(V.steps[V.CAMEL]));
149 }
150
151 static get VALUES() {
152 return Object.assign(
153 ChessRules.VALUES,
154 {'c': 3, 'w': 7} //experimental
155 );
156 }
157
158 // TODO:
159 static GenRandInitFen()
160 {
161 let pieces = [new Array(8), new Array(8)];
162 // Shuffle pieces on first and last rank
163 for (let c = 0; c <= 1; c++)
164 {
165 let positions = _.range(8);
166
167 // Get random squares for bishops
168 let randIndex = 2 * _.random(3);
169 let bishop1Pos = positions[randIndex];
170 // The second bishop must be on a square of different color
171 let randIndex_tmp = 2 * _.random(3) + 1;
172 let bishop2Pos = positions[randIndex_tmp];
173 // Remove chosen squares
174 positions.splice(Math.max(randIndex,randIndex_tmp), 1);
175 positions.splice(Math.min(randIndex,randIndex_tmp), 1);
176
177 // Get random squares for knights
178 randIndex = _.random(5);
179 let knight1Pos = positions[randIndex];
180 positions.splice(randIndex, 1);
181 randIndex = _.random(4);
182 let knight2Pos = positions[randIndex];
183 positions.splice(randIndex, 1);
184
185 // Get random square for queen
186 randIndex = _.random(3);
187 let queenPos = positions[randIndex];
188 positions.splice(randIndex, 1);
189
190 // Rooks and king positions are now fixed, because of the ordering rook-king-rook
191 let rook1Pos = positions[0];
192 let kingPos = positions[1];
193 let rook2Pos = positions[2];
194
195 // Finally put the shuffled pieces in the board array
196 pieces[c][rook1Pos] = 'r';
197 pieces[c][knight1Pos] = 'n';
198 pieces[c][bishop1Pos] = 'b';
199 pieces[c][queenPos] = 'q';
200 pieces[c][kingPos] = 'k';
201 pieces[c][bishop2Pos] = 'b';
202 pieces[c][knight2Pos] = 'n';
203 pieces[c][rook2Pos] = 'r';
204 }
205 let fen = pieces[0].join("") +
206 "/pppppppp/8/8/8/8/PPPPPPPP/" +
207 pieces[1].join("").toUpperCase() +
208 " 1111"; //add flags
209 return fen;
210 }
211}