Commit | Line | Data |
---|---|---|
32cfcea4 BA |
1 | class UltimaRules extends ChessRules |
2 | { | |
2eef6db6 BA |
3 | static getPpath(b) |
4 | { | |
5 | if (b[1] == "m") //'m' for Immobilizer (I is too similar to 1) | |
6 | return "Ultima/" + b; | |
7 | return b; //usual piece | |
8 | } | |
32cfcea4 | 9 | |
2eef6db6 BA |
10 | initVariables(fen) |
11 | { | |
12 | this.kingPos = {'w':[-1,-1], 'b':[-1,-1]}; | |
13 | const fenParts = fen.split(" "); | |
14 | const position = fenParts[0].split("/"); | |
15 | for (let i=0; i<position.length; i++) | |
16 | { | |
17 | let k = 0; | |
18 | for (let j=0; j<position[i].length; j++) | |
19 | { | |
20 | switch (position[i].charAt(j)) | |
21 | { | |
22 | case 'k': | |
23 | this.kingPos['b'] = [i,k]; | |
24 | break; | |
25 | case 'K': | |
26 | this.kingPos['w'] = [i,k]; | |
27 | break; | |
28 | default: | |
29 | let num = parseInt(position[i].charAt(j)); | |
30 | if (!isNaN(num)) | |
31 | k += (num-1); | |
32 | } | |
33 | k++; | |
34 | } | |
35 | } | |
36 | this.epSquares = []; //no en-passant here | |
37 | } | |
38 | ||
39 | setFlags(fen) | |
40 | { | |
41 | // TODO: for compatibility? | |
42 | this.castleFlags = {"w":[false,false], "b":[false,false]}; | |
43 | } | |
44 | ||
45 | static get IMMOBILIZER() { return 'm'; } | |
46 | // Although other pieces keep their names here for coding simplicity, | |
47 | // keep in mind that: | |
48 | // - a "rook" is a coordinator, capturing by coordinating with the king | |
49 | // - a "knight" is a long-leaper, capturing as in draughts | |
50 | // - a "bishop" is a chameleon, capturing as its prey | |
51 | // - a "queen" is a withdrawer, capturing by moving away from pieces | |
52 | ||
53 | getPotentialMovesFrom([x,y]) | |
54 | { | |
45338cdd | 55 | // TODO: pre-check: is thing on this square immobilized? If yes, return [] |
2eef6db6 BA |
56 | switch (this.getPiece(x,y)) |
57 | { | |
58 | case VariantRules.IMMOBILIZER: | |
59 | return this.getPotentialImmobilizerMoves([x,y]); | |
60 | default: | |
61 | return super.getPotentialMovesFrom([x,y]); | |
62 | } | |
63 | // TODO: add potential suicides as a move "taking the immobilizer" | |
64 | // TODO: add long-leaper captures | |
65 | // TODO: mark matching coordinator/withdrawer/chameleon moves as captures | |
66 | // (will be a bit tedious for chameleons) | |
67 | // --> filter directly in functions below | |
68 | } | |
69 | ||
70 | getSlideNJumpMoves([x,y], steps, oneStep) | |
71 | { | |
72 | const color = this.getColor(x,y); | |
73 | const piece = this.getPiece(x,y); | |
74 | let moves = []; | |
75 | const [sizeX,sizeY] = VariantRules.size; | |
76 | outerLoop: | |
77 | for (let step of steps) | |
78 | { | |
79 | let i = x + step[0]; | |
80 | let j = y + step[1]; | |
81 | while (i>=0 && i<sizeX && j>=0 && j<sizeY | |
82 | && this.board[i][j] == VariantRules.EMPTY) | |
83 | { | |
84 | moves.push(this.getBasicMove([x,y], [i,j])); | |
85 | if (oneStep !== undefined) | |
86 | continue outerLoop; | |
87 | i += step[0]; | |
88 | j += step[1]; | |
89 | } | |
90 | // Only king can take on occupied square: | |
91 | if (piece==VariantRules.KING && i>=0 && i<sizeX && j>=0 | |
92 | && j<sizeY && this.canTake([x,y], [i,j])) | |
93 | { | |
94 | moves.push(this.getBasicMove([x,y], [i,j])); | |
95 | } | |
96 | } | |
97 | return moves; | |
98 | } | |
99 | ||
100 | getPotentialPawnMoves([x,y]) | |
101 | { | |
102 | return super.getPotentialRookMoves([x,y]); | |
103 | } | |
104 | ||
105 | getPotentialRookMoves(sq) | |
106 | { | |
107 | return super.getPotentialQueenMoves(sq); | |
108 | } | |
109 | ||
110 | getPotentialKnightMoves(sq) | |
111 | { | |
112 | return super.getPotentialQueenMoves(sq); | |
113 | } | |
114 | ||
115 | getPotentialBishopMoves(sq) | |
116 | { | |
117 | return super.getPotentialQueenMoves(sq); | |
118 | } | |
119 | ||
120 | getPotentialQueenMoves(sq) | |
121 | { | |
122 | return super.getPotentialQueenMoves(sq); | |
123 | } | |
124 | ||
45338cdd BA |
125 | getPotentialImmobilizerMoves(sq) |
126 | { | |
127 | return super.getPotentialQueenMoves(sq); | |
128 | } | |
129 | ||
2eef6db6 BA |
130 | getPotentialKingMoves(sq) |
131 | { | |
132 | const V = VariantRules; | |
133 | return this.getSlideNJumpMoves(sq, | |
134 | V.steps[V.ROOK].concat(V.steps[V.BISHOP]), "oneStep"); | |
135 | } | |
136 | ||
137 | // isAttacked() is OK because the immobilizer doesn't take | |
138 | ||
139 | isAttackedByPawn([x,y], colors) | |
140 | { | |
141 | // Square (x,y) must be surrounded by two enemy pieces, | |
142 | // and one of them at least should be a pawn | |
143 | return false; | |
144 | } | |
145 | ||
146 | isAttackedByRook(sq, colors) | |
147 | { | |
148 | // Enemy king must be on same file and a rook on same row (or reverse) | |
149 | } | |
150 | ||
151 | isAttackedByKnight(sq, colors) | |
152 | { | |
153 | // Square (x,y) must be on same line as a knight, | |
154 | // and there must be empty square(s) behind. | |
155 | } | |
156 | ||
157 | isAttackedByBishop(sq, colors) | |
158 | { | |
159 | // switch on piece nature on square sq: a chameleon attack as this piece | |
160 | // ==> call the appropriate isAttackedBy... (exception of immobilizers) | |
161 | // Other exception: a chameleon cannot attack a chameleon (seemingly...) | |
162 | } | |
163 | ||
164 | isAttackedByQueen(sq, colors) | |
165 | { | |
166 | // Square (x,y) must be adjacent to a queen, and the queen must have | |
167 | // some free space in the opposite direction from (x,y) | |
168 | } | |
169 | ||
170 | updateVariables(move) | |
171 | { | |
172 | // Just update king position | |
173 | const piece = this.getPiece(move.start.x,move.start.y); | |
174 | const c = this.getColor(move.start.x,move.start.y); | |
175 | if (piece == VariantRules.KING && move.appear.length > 0) | |
176 | { | |
177 | this.kingPos[c][0] = move.appear[0].x; | |
178 | this.kingPos[c][1] = move.appear[0].y; | |
179 | } | |
180 | } | |
181 | ||
182 | static get VALUES() { //TODO: totally experimental! | |
183 | return { | |
184 | 'p': 1, | |
185 | 'r': 2, | |
186 | 'n': 5, | |
187 | 'b': 3, | |
188 | 'q': 3, | |
189 | 'm': 5, | |
190 | 'k': 1000 | |
191 | }; | |
192 | } | |
193 | ||
194 | static get SEARCH_DEPTH() { return 2; } //TODO? | |
195 | ||
196 | static GenRandInitFen() | |
197 | { | |
198 | let pieces = { "w": new Array(8), "b": new Array(8) }; | |
199 | // Shuffle pieces on first and last rank | |
200 | for (let c of ["w","b"]) | |
201 | { | |
202 | let positions = _.range(8); | |
203 | // Get random squares for every piece, totally freely | |
204 | ||
205 | let randIndex = _.random(7); | |
206 | const bishop1Pos = positions[randIndex]; | |
207 | positions.splice(randIndex, 1); | |
208 | ||
209 | randIndex = _.random(6); | |
210 | const bishop2Pos = positions[randIndex]; | |
211 | positions.splice(randIndex, 1); | |
212 | ||
213 | randIndex = _.random(5); | |
214 | const knight1Pos = positions[randIndex]; | |
215 | positions.splice(randIndex, 1); | |
216 | ||
217 | randIndex = _.random(4); | |
218 | const knight2Pos = positions[randIndex]; | |
219 | positions.splice(randIndex, 1); | |
220 | ||
221 | randIndex = _.random(3); | |
222 | const queenPos = positions[randIndex]; | |
223 | positions.splice(randIndex, 1); | |
224 | ||
225 | randIndex = _.random(2); | |
226 | const kingPos = positions[randIndex]; | |
227 | positions.splice(randIndex, 1); | |
228 | ||
229 | randIndex = _.random(1); | |
230 | const rookPos = positions[randIndex]; | |
231 | positions.splice(randIndex, 1); | |
45338cdd | 232 | const immobilizerPos = positions[0]; |
2eef6db6 BA |
233 | |
234 | pieces[c][bishop1Pos] = 'b'; | |
235 | pieces[c][bishop2Pos] = 'b'; | |
236 | pieces[c][knight1Pos] = 'n'; | |
237 | pieces[c][knight2Pos] = 'n'; | |
238 | pieces[c][queenPos] = 'q'; | |
239 | pieces[c][kingPos] = 'k'; | |
240 | pieces[c][rookPos] = 'r'; | |
241 | pieces[c][immobilizerPos] = 'm'; | |
242 | } | |
243 | return pieces["b"].join("") + | |
244 | "/pppppppp/8/8/8/8/PPPPPPPP/" + | |
245 | pieces["w"].join("").toUpperCase() + | |
246 | " 0000"; //TODO: flags?! | |
247 | } | |
248 | ||
249 | getFlagsFen() | |
250 | { | |
251 | return "0000"; //TODO: or "-" ? | |
252 | } | |
32cfcea4 | 253 | } |