Commit | Line | Data |
---|---|---|
0f7762c1 | 1 | import { ChessRules } from "@/base_rules"; |
f8c080e8 BA |
2 | import { ArrayFun } from "@/utils/array"; |
3 | import { randInt } from "@/utils/alea"; | |
0f7762c1 BA |
4 | |
5 | export class AlapoRules extends ChessRules { | |
6 | ||
7 | static get HasFlags() { | |
8 | return false; | |
9 | } | |
10 | ||
11 | static get HasEnpassant() { | |
12 | return false; | |
13 | } | |
14 | ||
15 | static get Lines() { | |
16 | return [ | |
17 | [[1, 0], [1, 6]], | |
18 | [[5, 0], [5, 6]] | |
19 | ]; | |
20 | } | |
21 | ||
22 | static get PIECES() { | |
23 | return [V.ROOK, V.BISHOP, V.QUEEN, V.ROOK_S, V.BISHOP_S, V.QUEEN_S]; | |
24 | } | |
25 | ||
26 | static get ROOK_S() { | |
27 | return "t"; | |
28 | } | |
29 | static get BISHOP_S() { | |
30 | return "c"; | |
31 | } | |
32 | static get QUEEN_S() { | |
33 | return "s"; | |
34 | } | |
35 | ||
36 | getPotentialMinirookMoves(sq) { | |
37 | return super.getSlideNJumpMoves(sq, V.steps[V.ROOK], "oneStep"); | |
38 | } | |
39 | getPotentialMinibishopMoves(sq) { | |
40 | return super.getSlideNJumpMoves(sq, V.steps[V.BISHOP], "oneStep"); | |
41 | } | |
42 | getPotentialMiniqueenMoves(sq) { | |
43 | return ( | |
44 | super.getSlideNJumpMoves( | |
45 | sq, V.steps[V.ROOK].concat(V.steps[V.BISHOP]), "oneStep") | |
46 | ); | |
47 | } | |
48 | ||
49 | getPotentialMovesFrom(sq) { | |
50 | switch (this.getPiece(sq[0], sq[1])) { | |
51 | case V.ROOK: return super.getPotentialRookMoves(sq); | |
52 | case V.BISHOP: return super.getPotentialBishopMoves(sq); | |
53 | case V.QUEEN: return super.getPotentialQueenMoves(sq); | |
54 | case V.ROOK_S: return this.getPotentialMinirookMoves(sq); | |
55 | case V.BISHOP_S: return this.getPotentialMinibishopMoves(sq); | |
56 | case V.QUEEN_S: return this.getPotentialMiniqueenMoves(sq); | |
57 | } | |
58 | return []; | |
59 | } | |
60 | ||
61 | static get size() { | |
62 | return { x: 6, y: 6 }; | |
63 | } | |
64 | ||
65 | getPpath(b, color, score, orientation) { | |
66 | // 'i' for "inversed": | |
67 | const suffix = (b[0] == orientation ? "" : "i"); | |
68 | return "Alapo/" + b + suffix; | |
69 | } | |
70 | ||
71 | static GenRandInitFen(randomness) { | |
72 | if (randomness == 0) | |
73 | return "rbqqbr/tcssct/6/6/TCSSCT/RBQQBR w 0"; | |
74 | ||
75 | const piece2pawn = { | |
76 | r: 't', | |
77 | q: 's', | |
78 | b: 'c' | |
79 | }; | |
80 | ||
81 | let pieces = { w: new Array(6), b: new Array(6) }; | |
82 | // Shuffle pieces on first (and last rank if randomness == 2) | |
83 | for (let c of ["w", "b"]) { | |
84 | if (c == 'b' && randomness == 1) { | |
85 | pieces['b'] = pieces['w']; | |
86 | break; | |
87 | } | |
88 | ||
89 | let positions = ArrayFun.range(6); | |
90 | ||
91 | // Get random squares for bishops | |
92 | let randIndex = 2 * randInt(3); | |
93 | const bishop1Pos = positions[randIndex]; | |
94 | let randIndex_tmp = 2 * randInt(3) + 1; | |
95 | const bishop2Pos = positions[randIndex_tmp]; | |
96 | positions.splice(Math.max(randIndex, randIndex_tmp), 1); | |
97 | positions.splice(Math.min(randIndex, randIndex_tmp), 1); | |
98 | ||
99 | // Get random square for queens | |
100 | randIndex = randInt(4); | |
101 | const queen1Pos = positions[randIndex]; | |
102 | positions.splice(randIndex, 1); | |
103 | randIndex = randInt(3); | |
104 | const queen2Pos = positions[randIndex]; | |
105 | positions.splice(randIndex, 1); | |
106 | ||
107 | // Rooks positions are now fixed, | |
108 | const rook1Pos = positions[0]; | |
109 | const rook2Pos = positions[1]; | |
110 | ||
111 | pieces[c][rook1Pos] = "r"; | |
112 | pieces[c][bishop1Pos] = "b"; | |
113 | pieces[c][queen1Pos] = "q"; | |
114 | pieces[c][queen2Pos] = "q"; | |
115 | pieces[c][bishop2Pos] = "b"; | |
116 | pieces[c][rook2Pos] = "r"; | |
117 | } | |
7194d19f | 118 | |
0f7762c1 BA |
119 | return ( |
120 | pieces["b"].join("") + "/" + | |
7194d19f BA |
121 | pieces["b"].map(p => piece2pawn[p]).join("") + |
122 | "/6/6/" + | |
123 | pieces["w"].map(p => piece2pawn[p].toUpperCase()).join("") + "/" + | |
0f7762c1 BA |
124 | pieces["w"].join("").toUpperCase() + |
125 | " w 0" | |
126 | ); | |
127 | } | |
128 | ||
129 | static IsGoodPosition(position) { | |
130 | if (position.length == 0) return false; | |
131 | const rows = position.split("/"); | |
132 | if (rows.length != V.size.x) return false; | |
133 | // Just check that at least one piece of each color is there: | |
134 | let pieces = { "w": 0, "b": 0 }; | |
135 | for (let row of rows) { | |
136 | let sumElts = 0; | |
137 | for (let i = 0; i < row.length; i++) { | |
138 | const lowerRi = row[i].toLowerCase(); | |
139 | if (V.PIECES.includes(lowerRi)) { | |
140 | pieces[row[i] == lowerRi ? "b" : "w"]++; | |
141 | sumElts++; | |
142 | } | |
143 | else { | |
144 | const num = parseInt(row[i], 10); | |
145 | if (isNaN(num)) return false; | |
146 | sumElts += num; | |
147 | } | |
148 | } | |
149 | if (sumElts != V.size.y) return false; | |
150 | } | |
151 | if (Object.values(pieces).some(v => v == 0)) return false; | |
152 | return true; | |
153 | } | |
154 | ||
155 | // Find possible captures by opponent on [x, y] | |
156 | findCaptures([x, y]) { | |
157 | const color = this.getColor(x, y); | |
158 | let moves = []; | |
159 | const steps = V.steps[V.ROOK].concat(V.steps[V.BISHOP]); | |
160 | const oppCol = V.GetOppCol(color); | |
161 | for (let loop = 0; loop < steps.length; loop++) { | |
162 | const step = steps[loop]; | |
163 | let i = x + step[0]; | |
164 | let j = y + step[1]; | |
165 | let stepsAfter = 1; | |
166 | while (V.OnBoard(i, j) && this.board[i][j] == V.EMPTY) { | |
167 | i += step[0]; | |
168 | j += step[1]; | |
169 | stepsAfter++; | |
170 | } | |
171 | if ( | |
172 | V.OnBoard(i, j) && | |
173 | this.board[i][j] != V.EMPTY && | |
174 | this.getColor(i, j) == oppCol | |
175 | ) { | |
176 | const oppPiece = this.getPiece(i, j); | |
177 | if ( | |
178 | ( | |
179 | stepsAfter >= 2 && | |
180 | [V.ROOK_S, V.BISHOP_S, V.QUEEN_S].includes(oppPiece) | |
181 | ) | |
182 | || | |
183 | ( | |
184 | [V.BISHOP, V.BISHOP_S].includes(oppPiece) && | |
185 | step.some(e => e == 0) | |
186 | ) | |
187 | || | |
188 | ( | |
189 | [V.ROOK, V.ROOK_S].includes(oppPiece) && | |
190 | step.every(e => e != 0) | |
191 | ) | |
192 | ) { | |
193 | continue; | |
194 | } | |
195 | return true; | |
196 | } | |
197 | } | |
198 | return false; | |
199 | } | |
200 | ||
201 | postPlay() {} | |
202 | postUndo() {} | |
203 | ||
204 | getCheckSquares() { | |
205 | return []; | |
206 | } | |
207 | filterValid(moves) { | |
208 | return moves; | |
209 | } | |
210 | ||
211 | getCurrentScore() { | |
212 | // Try both colors (to detect potential suicides) | |
213 | for (let c of ['w', 'b']) { | |
214 | const oppCol = V.GetOppCol(c); | |
215 | const goal = (c == 'w' ? 0 : 5); | |
216 | if ( | |
217 | this.board[goal].some( | |
218 | (b,j) => b[0] == c && !this.findCaptures([goal, j]) | |
219 | ) | |
220 | ) { | |
221 | return c == 'w' ? "1-0" : "0-1"; | |
222 | } | |
223 | } | |
224 | return super.getCurrentScore(); | |
225 | } | |
226 | ||
ded43c88 BA |
227 | static get VALUES() { |
228 | return { | |
229 | r: 5, | |
230 | b: 3, | |
231 | q: 9, | |
232 | t: 3, | |
233 | c: 2, | |
234 | s: 5 | |
235 | }; | |
236 | } | |
237 | ||
0f7762c1 | 238 | }; |