Commit | Line | Data |
---|---|---|
e3e2cc44 BA |
1 | import { ChessRules, PiPo, Move } from "@/base_rules"; |
2 | import { ArrayFun } from "@/utils/array"; | |
3 | import { randInt, shuffle } from "@/utils/alea"; | |
4 | ||
5 | export const VariantRules = class CircularRules extends ChessRules { | |
6 | static get HasFlags() { | |
7 | return false; | |
8 | } | |
9 | ||
10 | static get HasEnpassant() { | |
11 | return false; | |
12 | } | |
13 | ||
14 | // TODO: CanFlip --> also for racing kings (answer is false) | |
15 | ||
16 | // TODO: shuffle on 1st and 5th ranks | |
17 | static GenRandInitFen() { | |
18 | let pieces = { w: new Array(8), b: new Array(8) }; | |
19 | // Shuffle pieces on first and last rank | |
20 | for (let c of ["w", "b"]) { | |
21 | let positions = ArrayFun.range(8); | |
22 | ||
23 | // Get random squares for bishops | |
24 | let randIndex = 2 * randInt(4); | |
25 | const bishop1Pos = positions[randIndex]; | |
26 | // The second bishop must be on a square of different color | |
27 | let randIndex_tmp = 2 * randInt(4) + 1; | |
28 | const bishop2Pos = positions[randIndex_tmp]; | |
29 | // Remove chosen squares | |
30 | positions.splice(Math.max(randIndex, randIndex_tmp), 1); | |
31 | positions.splice(Math.min(randIndex, randIndex_tmp), 1); | |
32 | ||
33 | // Get random squares for knights | |
34 | randIndex = randInt(6); | |
35 | const knight1Pos = positions[randIndex]; | |
36 | positions.splice(randIndex, 1); | |
37 | randIndex = randInt(5); | |
38 | const knight2Pos = positions[randIndex]; | |
39 | positions.splice(randIndex, 1); | |
40 | ||
41 | // Get random square for queen | |
42 | randIndex = randInt(4); | |
43 | const queenPos = positions[randIndex]; | |
44 | positions.splice(randIndex, 1); | |
45 | ||
46 | // Rooks and king positions are now fixed, | |
47 | // because of the ordering rook-king-rook | |
48 | const rook1Pos = positions[0]; | |
49 | const kingPos = positions[1]; | |
50 | const rook2Pos = positions[2]; | |
51 | ||
52 | // Finally put the shuffled pieces in the board array | |
53 | pieces[c][rook1Pos] = "r"; | |
54 | pieces[c][knight1Pos] = "n"; | |
55 | pieces[c][bishop1Pos] = "b"; | |
56 | pieces[c][queenPos] = "q"; | |
57 | pieces[c][kingPos] = "k"; | |
58 | pieces[c][bishop2Pos] = "b"; | |
59 | pieces[c][knight2Pos] = "n"; | |
60 | pieces[c][rook2Pos] = "r"; | |
61 | } | |
62 | return ( | |
63 | pieces["b"].join("") + | |
64 | "/pppppppp/8/8/8/8/PPPPPPPP/" + | |
65 | pieces["w"].join("").toUpperCase() + | |
66 | " w 0" | |
67 | ); | |
68 | } | |
69 | ||
70 | // TODO: adapt this for a circular board | |
71 | getSlideNJumpMoves([x, y], steps, oneStep) { | |
72 | let moves = []; | |
73 | outerLoop: for (let step of steps) { | |
74 | let i = x + step[0]; | |
75 | let j = y + step[1]; | |
76 | while (V.OnBoard(i, j) && this.board[i][j] == V.EMPTY) { | |
77 | moves.push(this.getBasicMove([x, y], [i, j])); | |
78 | if (oneStep !== undefined) continue outerLoop; | |
79 | i += step[0]; | |
80 | j += step[1]; | |
81 | } | |
82 | if (V.OnBoard(i, j) && this.canTake([x, y], [i, j])) | |
83 | moves.push(this.getBasicMove([x, y], [i, j])); | |
84 | } | |
85 | return moves; | |
86 | } | |
87 | ||
88 | // TODO: adapt: all pawns go in thz same direction! | |
89 | getPotentialPawnMoves([x, y]) { | |
90 | const color = this.turn; | |
91 | let moves = []; | |
92 | const [sizeX, sizeY] = [V.size.x, V.size.y]; | |
93 | const shiftX = color == "w" ? -1 : 1; | |
94 | const firstRank = color == "w" ? sizeX - 1 : 0; | |
95 | const startRank = color == "w" ? sizeX - 2 : 1; | |
96 | const lastRank = color == "w" ? 0 : sizeX - 1; | |
97 | const pawnColor = this.getColor(x, y); //can be different for checkered | |
98 | ||
99 | // NOTE: next condition is generally true (no pawn on last rank) | |
100 | if (x + shiftX >= 0 && x + shiftX < sizeX) { | |
101 | const finalPieces = | |
102 | x + shiftX == lastRank | |
103 | ? [V.ROOK, V.KNIGHT, V.BISHOP, V.QUEEN] | |
104 | : [V.PAWN]; | |
105 | // One square forward | |
106 | if (this.board[x + shiftX][y] == V.EMPTY) { | |
107 | for (let piece of finalPieces) { | |
108 | moves.push( | |
109 | this.getBasicMove([x, y], [x + shiftX, y], { | |
110 | c: pawnColor, | |
111 | p: piece | |
112 | }) | |
113 | ); | |
114 | } | |
115 | // Next condition because pawns on 1st rank can generally jump | |
116 | if ( | |
117 | [startRank, firstRank].includes(x) && | |
118 | this.board[x + 2 * shiftX][y] == V.EMPTY | |
119 | ) { | |
120 | // Two squares jump | |
121 | moves.push(this.getBasicMove([x, y], [x + 2 * shiftX, y])); | |
122 | } | |
123 | } | |
124 | // Captures | |
125 | for (let shiftY of [-1, 1]) { | |
126 | if ( | |
127 | y + shiftY >= 0 && | |
128 | y + shiftY < sizeY && | |
129 | this.board[x + shiftX][y + shiftY] != V.EMPTY && | |
130 | this.canTake([x, y], [x + shiftX, y + shiftY]) | |
131 | ) { | |
132 | for (let piece of finalPieces) { | |
133 | moves.push( | |
134 | this.getBasicMove([x, y], [x + shiftX, y + shiftY], { | |
135 | c: pawnColor, | |
136 | p: piece | |
137 | }) | |
138 | ); | |
139 | } | |
140 | } | |
141 | } | |
142 | } | |
143 | ||
144 | return moves; | |
145 | } | |
146 | ||
147 | // What are the king moves from square x,y ? | |
148 | getPotentialKingMoves(sq) { | |
149 | return this.getSlideNJumpMoves( | |
150 | sq, | |
151 | V.steps[V.ROOK].concat(V.steps[V.BISHOP]), | |
152 | "oneStep" | |
153 | ); | |
154 | } | |
155 | ||
156 | // TODO: check boundaries here as well | |
157 | isAttackedByPawn([x, y], colors) { | |
158 | for (let c of colors) { | |
159 | let pawnShift = c == "w" ? 1 : -1; | |
160 | if (x + pawnShift >= 0 && x + pawnShift < V.size.x) { | |
161 | for (let i of [-1, 1]) { | |
162 | if ( | |
163 | y + i >= 0 && | |
164 | y + i < V.size.y && | |
165 | this.getPiece(x + pawnShift, y + i) == V.PAWN && | |
166 | this.getColor(x + pawnShift, y + i) == c | |
167 | ) { | |
168 | return true; | |
169 | } | |
170 | } | |
171 | } | |
172 | } | |
173 | return false; | |
174 | } | |
175 | ||
176 | // TODO: adapt this function | |
177 | isAttackedBySlideNJump([x, y], colors, piece, steps, oneStep) { | |
178 | for (let step of steps) { | |
179 | let rx = x + step[0], | |
180 | ry = y + step[1]; | |
181 | while (V.OnBoard(rx, ry) && this.board[rx][ry] == V.EMPTY && !oneStep) { | |
182 | rx += step[0]; | |
183 | ry += step[1]; | |
184 | } | |
185 | if ( | |
186 | V.OnBoard(rx, ry) && | |
187 | this.getPiece(rx, ry) === piece && | |
188 | colors.includes(this.getColor(rx, ry)) | |
189 | ) { | |
190 | return true; | |
191 | } | |
192 | } | |
193 | return false; | |
194 | } | |
195 | }; |