Commit | Line | Data |
---|---|---|
0c3fe8a6 BA |
1 | import { ChessRules } from "@/base_rules"; |
2 | import { ArrayFun } from "@/utils/array"; | |
3 | import { randInt } from "@/utils/alea"; | |
4 | ||
32f6285e | 5 | export class GrandRules extends ChessRules { |
7e8a7ea1 | 6 | |
63543a13 | 7 | static get HasFlags() { |
0fb43db7 BA |
8 | return false; |
9 | } | |
10 | ||
6808d7a1 | 11 | static IsGoodEnpassant(enpassant) { |
472c0c4f | 12 | if (enpassant != "-") return !!enpassant.match(/^([a-j][0-9]{1,2},?)+$/); |
dac39588 BA |
13 | return true; |
14 | } | |
15 | ||
241bf8f2 BA |
16 | getPpath(b) { |
17 | return ([V.MARSHALL, V.CARDINAL].includes(b[1]) ? "Grand/" : "") + b; | |
18 | } | |
19 | ||
6808d7a1 BA |
20 | static get size() { |
21 | return { x: 10, y: 10 }; | |
22 | } | |
dac39588 | 23 | |
a6836242 | 24 | // Rook + knight: |
6808d7a1 BA |
25 | static get MARSHALL() { |
26 | return "m"; | |
a6836242 BA |
27 | } |
28 | ||
29 | // Bishop + knight | |
6808d7a1 BA |
30 | static get CARDINAL() { |
31 | return "c"; | |
a6836242 | 32 | } |
dac39588 | 33 | |
6808d7a1 BA |
34 | static get PIECES() { |
35 | return ChessRules.PIECES.concat([V.MARSHALL, V.CARDINAL]); | |
dac39588 BA |
36 | } |
37 | ||
6808d7a1 BA |
38 | getPotentialMovesFrom([x, y]) { |
39 | switch (this.getPiece(x, y)) { | |
dac39588 | 40 | case V.MARSHALL: |
6808d7a1 | 41 | return this.getPotentialMarshallMoves([x, y]); |
dac39588 | 42 | case V.CARDINAL: |
6808d7a1 | 43 | return this.getPotentialCardinalMoves([x, y]); |
dac39588 | 44 | default: |
6808d7a1 | 45 | return super.getPotentialMovesFrom([x, y]); |
dac39588 BA |
46 | } |
47 | } | |
48 | ||
49 | // Special pawn rules: promotions to captured friendly pieces, | |
50 | // optional on ranks 8-9 and mandatory on rank 10. | |
6808d7a1 | 51 | getPotentialPawnMoves([x, y]) { |
dac39588 BA |
52 | const color = this.turn; |
53 | let moves = []; | |
6808d7a1 BA |
54 | const [sizeX, sizeY] = [V.size.x, V.size.y]; |
55 | const shiftX = color == "w" ? -1 : 1; | |
0fb43db7 | 56 | const startRank = (color == "w" ? sizeX - 3 : 2); |
6808d7a1 BA |
57 | const lastRanks = |
58 | color == "w" ? [0, 1, 2] : [sizeX - 1, sizeX - 2, sizeX - 3]; | |
dac39588 | 59 | // Always x+shiftX >= 0 && x+shiftX < sizeX, because no pawns on last rank |
63543a13 | 60 | let finalPieces = [V.PAWN]; |
6808d7a1 | 61 | if (lastRanks.includes(x + shiftX)) { |
63543a13 BA |
62 | // Determine which promotion pieces are available: |
63 | let promotionPieces = { | |
64 | [V.ROOK]: 2, | |
65 | [V.KNIGHT]: 2, | |
66 | [V.BISHOP]: 2, | |
67 | [V.QUEEN]: 1, | |
68 | [V.MARSHALL]: 1, | |
69 | [V.CARDINAL]: 1 | |
70 | }; | |
71 | for (let i=0; i<10; i++) { | |
72 | for (let j=0; j<10; j++) { | |
73 | if (this.board[i][j] != V.EMPTY && this.getColor(i, j) == color) { | |
74 | const p = this.getPiece(i, j); | |
75 | if (![V.PAWN, V.KING].includes(p)) promotionPieces[p]--; | |
76 | } | |
77 | } | |
78 | } | |
79 | const availablePieces = | |
80 | Object.keys(promotionPieces).filter(k => promotionPieces[k] > 0); | |
81 | if (x + shiftX == lastRanks[0]) finalPieces = availablePieces; | |
82 | else Array.prototype.push.apply(finalPieces, availablePieces); | |
0fb43db7 | 83 | } |
6808d7a1 | 84 | if (this.board[x + shiftX][y] == V.EMPTY) { |
dac39588 BA |
85 | // One square forward |
86 | for (let piece of finalPieces) | |
6808d7a1 BA |
87 | moves.push( |
88 | this.getBasicMove([x, y], [x + shiftX, y], { c: color, p: piece }) | |
89 | ); | |
0fb43db7 BA |
90 | if (x == startRank && this.board[x + 2 * shiftX][y] == V.EMPTY) |
91 | // Two squares jump | |
92 | moves.push(this.getBasicMove([x, y], [x + 2 * shiftX, y])); | |
dac39588 BA |
93 | } |
94 | // Captures | |
6808d7a1 BA |
95 | for (let shiftY of [-1, 1]) { |
96 | if ( | |
97 | y + shiftY >= 0 && | |
98 | y + shiftY < sizeY && | |
99 | this.board[x + shiftX][y + shiftY] != V.EMPTY && | |
100 | this.canTake([x, y], [x + shiftX, y + shiftY]) | |
101 | ) { | |
102 | for (let piece of finalPieces) { | |
103 | moves.push( | |
104 | this.getBasicMove([x, y], [x + shiftX, y + shiftY], { | |
105 | c: color, | |
106 | p: piece | |
107 | }) | |
108 | ); | |
dac39588 BA |
109 | } |
110 | } | |
111 | } | |
112 | ||
113 | // En passant | |
0fb43db7 BA |
114 | Array.prototype.push.apply( |
115 | moves, | |
116 | this.getEnpassantCaptures([x, y], shiftX) | |
117 | ); | |
dac39588 BA |
118 | |
119 | return moves; | |
120 | } | |
121 | ||
6808d7a1 | 122 | getPotentialMarshallMoves(sq) { |
dac39588 | 123 | return this.getSlideNJumpMoves(sq, V.steps[V.ROOK]).concat( |
4313762d | 124 | this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], 1) |
6808d7a1 | 125 | ); |
dac39588 BA |
126 | } |
127 | ||
6808d7a1 | 128 | getPotentialCardinalMoves(sq) { |
dac39588 | 129 | return this.getSlideNJumpMoves(sq, V.steps[V.BISHOP]).concat( |
4313762d | 130 | this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], 1) |
6808d7a1 | 131 | ); |
dac39588 BA |
132 | } |
133 | ||
68e19a44 | 134 | isAttacked(sq, color) { |
6808d7a1 | 135 | return ( |
68e19a44 BA |
136 | super.isAttacked(sq, color) || |
137 | this.isAttackedByMarshall(sq, color) || | |
138 | this.isAttackedByCardinal(sq, color) | |
6808d7a1 | 139 | ); |
dac39588 BA |
140 | } |
141 | ||
68e19a44 | 142 | isAttackedByMarshall(sq, color) { |
6808d7a1 | 143 | return ( |
68e19a44 | 144 | this.isAttackedBySlideNJump(sq, color, V.MARSHALL, V.steps[V.ROOK]) || |
4313762d | 145 | this.isAttackedBySlideNJump(sq, color, V.MARSHALL, V.steps[V.KNIGHT], 1) |
6808d7a1 | 146 | ); |
dac39588 BA |
147 | } |
148 | ||
68e19a44 | 149 | isAttackedByCardinal(sq, color) { |
6808d7a1 | 150 | return ( |
68e19a44 | 151 | this.isAttackedBySlideNJump(sq, color, V.CARDINAL, V.steps[V.BISHOP]) || |
4313762d | 152 | this.isAttackedBySlideNJump(sq, color, V.CARDINAL, V.steps[V.KNIGHT], 1) |
6808d7a1 | 153 | ); |
dac39588 BA |
154 | } |
155 | ||
6808d7a1 | 156 | static get VALUES() { |
dac39588 | 157 | return Object.assign( |
a97bdbda BA |
158 | { c: 5, m: 7 }, //experimental |
159 | ChessRules.VALUES | |
dac39588 BA |
160 | ); |
161 | } | |
162 | ||
6808d7a1 BA |
163 | static get SEARCH_DEPTH() { |
164 | return 2; | |
165 | } | |
dac39588 | 166 | |
4313762d BA |
167 | static GenRandInitFen(options) { |
168 | if (options.randomness == 0) { | |
2c5d7b20 BA |
169 | return ( |
170 | "r8r/1nbqkmcbn1/pppppppppp/91/91/91/91/PPPPPPPPPP/1NBQKMCBN1/R8R " + | |
63543a13 | 171 | "w 0 -" |
2c5d7b20 | 172 | ); |
7ba4a5bc BA |
173 | } |
174 | ||
0fb43db7 BA |
175 | let pieces = { w: new Array(8), b: new Array(8) }; |
176 | // Shuffle pieces on second and before-last rank | |
6808d7a1 | 177 | for (let c of ["w", "b"]) { |
4313762d | 178 | if (c == 'b' && options.randomness == 1) { |
7ba4a5bc BA |
179 | pieces['b'] = pieces['w']; |
180 | break; | |
181 | } | |
182 | ||
0fb43db7 | 183 | let positions = ArrayFun.range(8); |
dac39588 BA |
184 | |
185 | // Get random squares for bishops | |
0fb43db7 | 186 | let randIndex = 2 * randInt(4); |
3208c667 | 187 | const bishop1Pos = positions[randIndex]; |
dac39588 | 188 | // The second bishop must be on a square of different color |
0fb43db7 | 189 | let randIndex_tmp = 2 * randInt(4) + 1; |
3208c667 | 190 | const bishop2Pos = positions[randIndex_tmp]; |
dac39588 | 191 | // Remove chosen squares |
6808d7a1 BA |
192 | positions.splice(Math.max(randIndex, randIndex_tmp), 1); |
193 | positions.splice(Math.min(randIndex, randIndex_tmp), 1); | |
dac39588 BA |
194 | |
195 | // Get random squares for knights | |
0fb43db7 | 196 | randIndex = randInt(6); |
3208c667 | 197 | const knight1Pos = positions[randIndex]; |
dac39588 | 198 | positions.splice(randIndex, 1); |
0fb43db7 | 199 | randIndex = randInt(5); |
3208c667 | 200 | const knight2Pos = positions[randIndex]; |
dac39588 BA |
201 | positions.splice(randIndex, 1); |
202 | ||
203 | // Get random square for queen | |
0fb43db7 | 204 | randIndex = randInt(4); |
3208c667 | 205 | const queenPos = positions[randIndex]; |
dac39588 BA |
206 | positions.splice(randIndex, 1); |
207 | ||
208 | // ...random square for marshall | |
0fb43db7 | 209 | randIndex = randInt(3); |
3208c667 | 210 | const marshallPos = positions[randIndex]; |
dac39588 BA |
211 | positions.splice(randIndex, 1); |
212 | ||
213 | // ...random square for cardinal | |
0fb43db7 | 214 | randIndex = randInt(2); |
3208c667 | 215 | const cardinalPos = positions[randIndex]; |
dac39588 BA |
216 | positions.splice(randIndex, 1); |
217 | ||
0fb43db7 | 218 | // King position is now fixed, |
3208c667 | 219 | const kingPos = positions[0]; |
dac39588 BA |
220 | |
221 | // Finally put the shuffled pieces in the board array | |
6808d7a1 BA |
222 | pieces[c][knight1Pos] = "n"; |
223 | pieces[c][bishop1Pos] = "b"; | |
224 | pieces[c][queenPos] = "q"; | |
225 | pieces[c][marshallPos] = "m"; | |
226 | pieces[c][cardinalPos] = "c"; | |
227 | pieces[c][kingPos] = "k"; | |
228 | pieces[c][bishop2Pos] = "b"; | |
229 | pieces[c][knight2Pos] = "n"; | |
dac39588 | 230 | } |
6808d7a1 | 231 | return ( |
0fb43db7 BA |
232 | "r8r/1" + pieces["b"].join("") + "1/" + |
233 | "pppppppppp/91/91/91/91/PPPPPPPPPP/" + | |
234 | "1" + pieces["w"].join("").toUpperCase() + "1/R8R" + | |
63543a13 | 235 | " w 0 -" |
6808d7a1 | 236 | ); |
dac39588 | 237 | } |
7e8a7ea1 | 238 | |
6808d7a1 | 239 | }; |