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