Commit | Line | Data |
---|---|---|
0c3fe8a6 BA |
1 | import { ChessRules } from "@/base_rules"; |
2 | import { ArrayFun } from "@/utils/array"; | |
3 | import { randInt } from "@/utils/alea"; | |
4 | ||
6808d7a1 BA |
5 | export const VariantRules = class LosersRules extends ChessRules { |
6 | static get HasFlags() { | |
7 | return false; | |
8 | } | |
dac39588 | 9 | |
6808d7a1 BA |
10 | getPotentialPawnMoves([x, y]) { |
11 | let moves = super.getPotentialPawnMoves([x, y]); | |
dac39588 BA |
12 | |
13 | // Complete with promotion(s) into king, if possible | |
14 | const color = this.turn; | |
6808d7a1 BA |
15 | const shift = color == "w" ? -1 : 1; |
16 | const lastRank = color == "w" ? 0 : V.size.x - 1; | |
17 | if (x + shift == lastRank) { | |
dac39588 | 18 | // Normal move |
6808d7a1 BA |
19 | if (this.board[x + shift][y] == V.EMPTY) |
20 | moves.push( | |
21 | this.getBasicMove([x, y], [x + shift, y], { c: color, p: V.KING }) | |
22 | ); | |
dac39588 | 23 | // Captures |
6808d7a1 BA |
24 | if ( |
25 | y > 0 && | |
26 | this.canTake([x, y], [x + shift, y - 1]) && | |
27 | this.board[x + shift][y - 1] != V.EMPTY | |
28 | ) { | |
29 | moves.push( | |
30 | this.getBasicMove([x, y], [x + shift, y - 1], { c: color, p: V.KING }) | |
31 | ); | |
dac39588 | 32 | } |
6808d7a1 BA |
33 | if ( |
34 | y < V.size.y - 1 && | |
35 | this.canTake([x, y], [x + shift, y + 1]) && | |
36 | this.board[x + shift][y + 1] != V.EMPTY | |
37 | ) { | |
38 | moves.push( | |
39 | this.getBasicMove([x, y], [x + shift, y + 1], { c: color, p: V.KING }) | |
40 | ); | |
dac39588 BA |
41 | } |
42 | } | |
43 | ||
44 | return moves; | |
45 | } | |
46 | ||
6808d7a1 | 47 | getPotentialKingMoves(sq) { |
dac39588 | 48 | // No castle: |
6808d7a1 BA |
49 | return this.getSlideNJumpMoves( |
50 | sq, | |
51 | V.steps[V.ROOK].concat(V.steps[V.BISHOP]), | |
52 | "oneStep" | |
53 | ); | |
dac39588 BA |
54 | } |
55 | ||
56 | // Stop at the first capture found (if any) | |
6808d7a1 | 57 | atLeastOneCapture() { |
dac39588 BA |
58 | const color = this.turn; |
59 | const oppCol = V.GetOppCol(color); | |
6808d7a1 BA |
60 | for (let i = 0; i < V.size.x; i++) { |
61 | for (let j = 0; j < V.size.y; j++) { | |
62 | if (this.board[i][j] != V.EMPTY && this.getColor(i, j) != oppCol) { | |
63 | const moves = this.getPotentialMovesFrom([i, j]); | |
64 | if (moves.length > 0) { | |
65 | for (let k = 0; k < moves.length; k++) { | |
66 | if ( | |
67 | moves[k].vanish.length == 2 && | |
68 | this.filterValid([moves[k]]).length > 0 | |
69 | ) | |
dac39588 BA |
70 | return true; |
71 | } | |
72 | } | |
73 | } | |
74 | } | |
75 | } | |
76 | return false; | |
77 | } | |
78 | ||
79 | // Trim all non-capturing moves | |
6808d7a1 BA |
80 | static KeepCaptures(moves) { |
81 | return moves.filter(m => { | |
82 | return m.vanish.length == 2; | |
83 | }); | |
dac39588 BA |
84 | } |
85 | ||
6808d7a1 BA |
86 | getPossibleMovesFrom(sq) { |
87 | let moves = this.filterValid(this.getPotentialMovesFrom(sq)); | |
dac39588 | 88 | // This is called from interface: we need to know if a capture is possible |
6808d7a1 | 89 | if (this.atLeastOneCapture()) moves = V.KeepCaptures(moves); |
dac39588 BA |
90 | return moves; |
91 | } | |
92 | ||
6808d7a1 | 93 | getAllValidMoves() { |
dac39588 | 94 | let moves = super.getAllValidMoves(); |
6808d7a1 BA |
95 | if ( |
96 | moves.some(m => { | |
97 | return m.vanish.length == 2; | |
98 | }) | |
99 | ) | |
dac39588 BA |
100 | moves = V.KeepCaptures(moves); |
101 | return moves; | |
102 | } | |
103 | ||
6808d7a1 | 104 | underCheck() { |
dac39588 BA |
105 | return false; //No notion of check |
106 | } | |
107 | ||
6808d7a1 | 108 | getCheckSquares() { |
dac39588 BA |
109 | return []; |
110 | } | |
111 | ||
112 | // No variables update because no royal king + no castling | |
6808d7a1 BA |
113 | updateVariables() {} |
114 | unupdateVariables() {} | |
a6abf094 | 115 | |
6808d7a1 BA |
116 | getCurrentScore() { |
117 | if (this.atLeastOneMove()) | |
118 | // game not over | |
0c3fe8a6 BA |
119 | return "*"; |
120 | ||
121 | // No valid move: the side who cannot move wins | |
6808d7a1 | 122 | return this.turn == "w" ? "1-0" : "0-1"; |
dac39588 BA |
123 | } |
124 | ||
6808d7a1 | 125 | static get VALUES() { |
dac39588 BA |
126 | // Experimental... |
127 | return { | |
6808d7a1 BA |
128 | p: 1, |
129 | r: 7, | |
130 | n: 3, | |
131 | b: 3, | |
132 | q: 5, | |
133 | k: 5 | |
dac39588 BA |
134 | }; |
135 | } | |
136 | ||
6808d7a1 BA |
137 | static get SEARCH_DEPTH() { |
138 | return 4; | |
139 | } | |
dac39588 | 140 | |
6808d7a1 BA |
141 | evalPosition() { |
142 | return -super.evalPosition(); //better with less material | |
dac39588 BA |
143 | } |
144 | ||
6808d7a1 BA |
145 | static GenRandInitFen() { |
146 | let pieces = { w: new Array(8), b: new Array(8) }; | |
dac39588 | 147 | // Shuffle pieces on first and last rank |
6808d7a1 | 148 | for (let c of ["w", "b"]) { |
dac39588 BA |
149 | let positions = ArrayFun.range(8); |
150 | ||
151 | // Get random squares for bishops | |
152 | let randIndex = 2 * randInt(4); | |
153 | let bishop1Pos = positions[randIndex]; | |
154 | // The second bishop must be on a square of different color | |
155 | let randIndex_tmp = 2 * randInt(4) + 1; | |
156 | let bishop2Pos = positions[randIndex_tmp]; | |
157 | // Remove chosen squares | |
6808d7a1 BA |
158 | positions.splice(Math.max(randIndex, randIndex_tmp), 1); |
159 | positions.splice(Math.min(randIndex, randIndex_tmp), 1); | |
dac39588 BA |
160 | |
161 | // Get random squares for knights | |
162 | randIndex = randInt(6); | |
163 | let knight1Pos = positions[randIndex]; | |
164 | positions.splice(randIndex, 1); | |
165 | randIndex = randInt(5); | |
166 | let knight2Pos = positions[randIndex]; | |
167 | positions.splice(randIndex, 1); | |
168 | ||
169 | // Get random square for queen | |
170 | randIndex = randInt(4); | |
171 | let queenPos = positions[randIndex]; | |
172 | positions.splice(randIndex, 1); | |
173 | ||
174 | // Random square for king (no castle) | |
175 | randIndex = randInt(3); | |
176 | let kingPos = positions[randIndex]; | |
177 | positions.splice(randIndex, 1); | |
178 | ||
179 | // Rooks positions are now fixed | |
180 | let rook1Pos = positions[0]; | |
181 | let rook2Pos = positions[1]; | |
182 | ||
183 | // Finally put the shuffled pieces in the board array | |
6808d7a1 BA |
184 | pieces[c][rook1Pos] = "r"; |
185 | pieces[c][knight1Pos] = "n"; | |
186 | pieces[c][bishop1Pos] = "b"; | |
187 | pieces[c][queenPos] = "q"; | |
188 | pieces[c][kingPos] = "k"; | |
189 | pieces[c][bishop2Pos] = "b"; | |
190 | pieces[c][knight2Pos] = "n"; | |
191 | pieces[c][rook2Pos] = "r"; | |
dac39588 | 192 | } |
6808d7a1 BA |
193 | return ( |
194 | pieces["b"].join("") + | |
dac39588 BA |
195 | "/pppppppp/8/8/8/8/PPPPPPPP/" + |
196 | pieces["w"].join("").toUpperCase() + | |
6808d7a1 BA |
197 | " w 0 -" |
198 | ); //en-passant allowed, but no flags | |
dac39588 | 199 | } |
6808d7a1 | 200 | }; |