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( |
6808d7a1 BA |
124 | this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], "oneStep") |
125 | ); | |
dac39588 BA |
126 | } |
127 | ||
6808d7a1 | 128 | getPotentialCardinalMoves(sq) { |
dac39588 | 129 | return this.getSlideNJumpMoves(sq, V.steps[V.BISHOP]).concat( |
6808d7a1 BA |
130 | this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], "oneStep") |
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]) || |
6808d7a1 BA |
145 | this.isAttackedBySlideNJump( |
146 | sq, | |
68e19a44 | 147 | color, |
6808d7a1 BA |
148 | V.MARSHALL, |
149 | V.steps[V.KNIGHT], | |
150 | "oneStep" | |
151 | ) | |
152 | ); | |
dac39588 BA |
153 | } |
154 | ||
68e19a44 | 155 | isAttackedByCardinal(sq, color) { |
6808d7a1 | 156 | return ( |
68e19a44 | 157 | this.isAttackedBySlideNJump(sq, color, V.CARDINAL, V.steps[V.BISHOP]) || |
6808d7a1 BA |
158 | this.isAttackedBySlideNJump( |
159 | sq, | |
68e19a44 | 160 | color, |
6808d7a1 BA |
161 | V.CARDINAL, |
162 | V.steps[V.KNIGHT], | |
163 | "oneStep" | |
164 | ) | |
165 | ); | |
dac39588 BA |
166 | } |
167 | ||
6808d7a1 | 168 | static get VALUES() { |
dac39588 | 169 | return Object.assign( |
a97bdbda BA |
170 | { c: 5, m: 7 }, //experimental |
171 | ChessRules.VALUES | |
dac39588 BA |
172 | ); |
173 | } | |
174 | ||
6808d7a1 BA |
175 | static get SEARCH_DEPTH() { |
176 | return 2; | |
177 | } | |
dac39588 | 178 | |
7ba4a5bc | 179 | static GenRandInitFen(randomness) { |
7ba4a5bc | 180 | if (randomness == 0) { |
2c5d7b20 BA |
181 | return ( |
182 | "r8r/1nbqkmcbn1/pppppppppp/91/91/91/91/PPPPPPPPPP/1NBQKMCBN1/R8R " + | |
63543a13 | 183 | "w 0 -" |
2c5d7b20 | 184 | ); |
7ba4a5bc BA |
185 | } |
186 | ||
0fb43db7 BA |
187 | let pieces = { w: new Array(8), b: new Array(8) }; |
188 | // Shuffle pieces on second and before-last rank | |
6808d7a1 | 189 | for (let c of ["w", "b"]) { |
7ba4a5bc BA |
190 | if (c == 'b' && randomness == 1) { |
191 | pieces['b'] = pieces['w']; | |
192 | break; | |
193 | } | |
194 | ||
0fb43db7 | 195 | let positions = ArrayFun.range(8); |
dac39588 BA |
196 | |
197 | // Get random squares for bishops | |
0fb43db7 | 198 | let randIndex = 2 * randInt(4); |
3208c667 | 199 | const bishop1Pos = positions[randIndex]; |
dac39588 | 200 | // The second bishop must be on a square of different color |
0fb43db7 | 201 | let randIndex_tmp = 2 * randInt(4) + 1; |
3208c667 | 202 | const bishop2Pos = positions[randIndex_tmp]; |
dac39588 | 203 | // Remove chosen squares |
6808d7a1 BA |
204 | positions.splice(Math.max(randIndex, randIndex_tmp), 1); |
205 | positions.splice(Math.min(randIndex, randIndex_tmp), 1); | |
dac39588 BA |
206 | |
207 | // Get random squares for knights | |
0fb43db7 | 208 | randIndex = randInt(6); |
3208c667 | 209 | const knight1Pos = positions[randIndex]; |
dac39588 | 210 | positions.splice(randIndex, 1); |
0fb43db7 | 211 | randIndex = randInt(5); |
3208c667 | 212 | const knight2Pos = positions[randIndex]; |
dac39588 BA |
213 | positions.splice(randIndex, 1); |
214 | ||
215 | // Get random square for queen | |
0fb43db7 | 216 | randIndex = randInt(4); |
3208c667 | 217 | const queenPos = positions[randIndex]; |
dac39588 BA |
218 | positions.splice(randIndex, 1); |
219 | ||
220 | // ...random square for marshall | |
0fb43db7 | 221 | randIndex = randInt(3); |
3208c667 | 222 | const marshallPos = positions[randIndex]; |
dac39588 BA |
223 | positions.splice(randIndex, 1); |
224 | ||
225 | // ...random square for cardinal | |
0fb43db7 | 226 | randIndex = randInt(2); |
3208c667 | 227 | const cardinalPos = positions[randIndex]; |
dac39588 BA |
228 | positions.splice(randIndex, 1); |
229 | ||
0fb43db7 | 230 | // King position is now fixed, |
3208c667 | 231 | const kingPos = positions[0]; |
dac39588 BA |
232 | |
233 | // Finally put the shuffled pieces in the board array | |
6808d7a1 BA |
234 | pieces[c][knight1Pos] = "n"; |
235 | pieces[c][bishop1Pos] = "b"; | |
236 | pieces[c][queenPos] = "q"; | |
237 | pieces[c][marshallPos] = "m"; | |
238 | pieces[c][cardinalPos] = "c"; | |
239 | pieces[c][kingPos] = "k"; | |
240 | pieces[c][bishop2Pos] = "b"; | |
241 | pieces[c][knight2Pos] = "n"; | |
dac39588 | 242 | } |
6808d7a1 | 243 | return ( |
0fb43db7 BA |
244 | "r8r/1" + pieces["b"].join("") + "1/" + |
245 | "pppppppppp/91/91/91/91/PPPPPPPPPP/" + | |
246 | "1" + pieces["w"].join("").toUpperCase() + "1/R8R" + | |
63543a13 | 247 | " w 0 -" |
6808d7a1 | 248 | ); |
dac39588 | 249 | } |
7e8a7ea1 | 250 | |
6808d7a1 | 251 | }; |