Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
99 | pmbaty | 1 | /* |
2 | Texel - A UCI chess engine. |
||
3 | Copyright (C) 2012-2014 Peter Ă–sterlund, peterosterlund2@gmail.com |
||
4 | |||
5 | This program is free software: you can redistribute it and/or modify |
||
6 | it under the terms of the GNU General Public License as published by |
||
7 | the Free Software Foundation, either version 3 of the License, or |
||
8 | (at your option) any later version. |
||
9 | |||
10 | This program is distributed in the hope that it will be useful, |
||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
13 | GNU General Public License for more details. |
||
14 | |||
15 | You should have received a copy of the GNU General Public License |
||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
||
17 | */ |
||
18 | |||
19 | /* |
||
20 | * textio.cpp |
||
21 | * |
||
22 | * Created on: Feb 25, 2012 |
||
23 | * Author: petero |
||
24 | */ |
||
25 | |||
26 | #include "textio.hpp" |
||
27 | #include "moveGen.hpp" |
||
28 | #include <cassert> |
||
29 | |||
30 | const std::string TextIO::startPosFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; |
||
31 | |||
32 | |||
33 | Position |
||
34 | TextIO::readFEN(const std::string& fen) { |
||
35 | Position pos; |
||
36 | |||
37 | // Piece placement |
||
38 | int row = 7; |
||
39 | int col = 0; |
||
40 | size_t i; |
||
41 | for (i = 0; i < fen.length(); i++) { |
||
42 | char c = fen[i]; |
||
43 | if (c == ' ') |
||
44 | break; |
||
45 | switch (c) { |
||
46 | case '1': col += 1; break; |
||
47 | case '2': col += 2; break; |
||
48 | case '3': col += 3; break; |
||
49 | case '4': col += 4; break; |
||
50 | case '5': col += 5; break; |
||
51 | case '6': col += 6; break; |
||
52 | case '7': col += 7; break; |
||
53 | case '8': col += 8; break; |
||
54 | case '/': |
||
55 | row--; col = 0; |
||
56 | if (row < 0) throw ChessParseError("Too many rows"); |
||
57 | break; |
||
58 | case 'P': safeSetPiece(pos, col, row, Piece::WPAWN); col++; break; |
||
59 | case 'N': safeSetPiece(pos, col, row, Piece::WKNIGHT); col++; break; |
||
60 | case 'B': safeSetPiece(pos, col, row, Piece::WBISHOP); col++; break; |
||
61 | case 'R': safeSetPiece(pos, col, row, Piece::WROOK); col++; break; |
||
62 | case 'Q': safeSetPiece(pos, col, row, Piece::WQUEEN); col++; break; |
||
63 | case 'K': safeSetPiece(pos, col, row, Piece::WKING); col++; break; |
||
64 | case 'p': safeSetPiece(pos, col, row, Piece::BPAWN); col++; break; |
||
65 | case 'n': safeSetPiece(pos, col, row, Piece::BKNIGHT); col++; break; |
||
66 | case 'b': safeSetPiece(pos, col, row, Piece::BBISHOP); col++; break; |
||
67 | case 'r': safeSetPiece(pos, col, row, Piece::BROOK); col++; break; |
||
68 | case 'q': safeSetPiece(pos, col, row, Piece::BQUEEN); col++; break; |
||
69 | case 'k': safeSetPiece(pos, col, row, Piece::BKING); col++; break; |
||
70 | default: throw ChessParseError("Invalid piece"); |
||
71 | } |
||
72 | } |
||
73 | while (i < fen.length() && fen[i] == ' ') |
||
74 | i++; |
||
75 | if (i >= fen.length()) |
||
76 | throw ChessParseError("Invalid side"); |
||
77 | pos.setWhiteMove(fen[i++] == 'w'); |
||
78 | |||
79 | // Castling rights |
||
80 | int castleMask = 0; |
||
81 | while (i < fen.length() && fen[i] == ' ') |
||
82 | i++; |
||
83 | for ( ; i < fen.length(); i++) { |
||
84 | char c = fen[i]; |
||
85 | if (c == ' ') |
||
86 | break; |
||
87 | switch (c) { |
||
88 | case 'K': castleMask |= (1 << Position::H1_CASTLE); break; |
||
89 | case 'Q': castleMask |= (1 << Position::A1_CASTLE); break; |
||
90 | case 'k': castleMask |= (1 << Position::H8_CASTLE); break; |
||
91 | case 'q': castleMask |= (1 << Position::A8_CASTLE); break; |
||
92 | case '-': break; |
||
93 | default: throw ChessParseError("Invalid castling flags"); |
||
94 | } |
||
95 | } |
||
96 | pos.setCastleMask(castleMask); |
||
97 | |||
98 | while (i < fen.length() && fen[i] == ' ') |
||
99 | i++; |
||
100 | |||
101 | if (i < fen.length()) { |
||
102 | // En passant target square |
||
103 | if (fen[i] != '-') { |
||
104 | if (i >= fen.length() - 1) |
||
105 | throw ChessParseError("Invalid en passant square"); |
||
106 | pos.setEpSquare(getSquare(fen.substr(i, 2))); |
||
107 | } |
||
108 | while (i < fen.length() && fen[i] != ' ') |
||
109 | i++; |
||
110 | } |
||
111 | |||
112 | while (i < fen.length() && fen[i] == ' ') |
||
113 | i++; |
||
114 | if (i < fen.length()) { |
||
115 | int i0 = i; |
||
116 | while (i < fen.length() && fen[i] != ' ') |
||
117 | i++; |
||
118 | int halfMoveClock; |
||
119 | if (str2Num(fen.substr(i0, i - i0), halfMoveClock)) |
||
120 | pos.setHalfMoveClock(halfMoveClock); |
||
121 | } |
||
122 | while (i < fen.length() && fen[i] == ' ') |
||
123 | i++; |
||
124 | if (i < fen.length()) { |
||
125 | int i0 = i; |
||
126 | while (i < fen.length() && fen[i] != ' ') |
||
127 | i++; |
||
128 | int fullMoveCounter; |
||
129 | if (str2Num(fen.substr(i0, i - i0), fullMoveCounter)) |
||
130 | pos.setFullMoveCounter(fullMoveCounter); |
||
131 | } |
||
132 | |||
133 | // Each side must have exactly one king |
||
134 | int wKings = 0; |
||
135 | int bKings = 0; |
||
136 | for (int x = 0; x < 8; x++) { |
||
137 | for (int y = 0; y < 8; y++) { |
||
138 | int p = pos.getPiece(Position::getSquare(x, y)); |
||
139 | if (p == Piece::WKING) |
||
140 | wKings++; |
||
141 | else if (p == Piece::BKING) |
||
142 | bKings++; |
||
143 | } |
||
144 | } |
||
145 | if (wKings != 1) |
||
146 | throw ChessParseError("White must have exactly one king"); |
||
147 | if (bKings != 1) |
||
148 | throw ChessParseError("Black must have exactly one king"); |
||
149 | |||
150 | // Make sure king can not be captured |
||
151 | Position pos2(pos); |
||
152 | pos2.setWhiteMove(!pos.isWhiteMove()); |
||
153 | if (MoveGen::inCheck(pos2)) |
||
154 | throw ChessParseError("King capture possible"); |
||
155 | |||
156 | fixupEPSquare(pos); |
||
157 | return pos; |
||
158 | } |
||
159 | |||
160 | |||
161 | void |
||
162 | TextIO::fixupEPSquare(Position& pos) { |
||
163 | int epSquare = pos.getEpSquare(); |
||
164 | if (epSquare >= 0) { |
||
165 | MoveList moves; |
||
166 | MoveGen::pseudoLegalMoves(pos, moves); |
||
167 | MoveGen::removeIllegal(pos, moves); |
||
168 | bool epValid = false; |
||
169 | for (int mi = 0; mi < moves.size; mi++) { |
||
170 | const Move& m = moves[mi]; |
||
171 | if (m.to() == epSquare) { |
||
172 | if (pos.getPiece(m.from()) == (pos.isWhiteMove() ? Piece::WPAWN : Piece::BPAWN)) { |
||
173 | epValid = true; |
||
174 | break; |
||
175 | } |
||
176 | } |
||
177 | } |
||
178 | if (!epValid) |
||
179 | pos.setEpSquare(-1); |
||
180 | } |
||
181 | } |
||
182 | |||
183 | |||
184 | std::string |
||
185 | TextIO::toFEN(const Position& pos) { |
||
186 | std::string ret; |
||
187 | // Piece placement |
||
188 | for (int r = 7; r >=0; r--) { |
||
189 | int numEmpty = 0; |
||
190 | for (int c = 0; c < 8; c++) { |
||
191 | int p = pos.getPiece(Position::getSquare(c, r)); |
||
192 | if (p == Piece::EMPTY) { |
||
193 | numEmpty++; |
||
194 | } else { |
||
195 | if (numEmpty > 0) { |
||
196 | ret += (char)('0' + numEmpty); |
||
197 | numEmpty = 0; |
||
198 | } |
||
199 | switch (p) { |
||
200 | case Piece::WKING: ret += 'K'; break; |
||
201 | case Piece::WQUEEN: ret += 'Q'; break; |
||
202 | case Piece::WROOK: ret += 'R'; break; |
||
203 | case Piece::WBISHOP: ret += 'B'; break; |
||
204 | case Piece::WKNIGHT: ret += 'N'; break; |
||
205 | case Piece::WPAWN: ret += 'P'; break; |
||
206 | case Piece::BKING: ret += 'k'; break; |
||
207 | case Piece::BQUEEN: ret += 'q'; break; |
||
208 | case Piece::BROOK: ret += 'r'; break; |
||
209 | case Piece::BBISHOP: ret += 'b'; break; |
||
210 | case Piece::BKNIGHT: ret += 'n'; break; |
||
211 | case Piece::BPAWN: ret += 'p'; break; |
||
212 | default: assert(false); break; |
||
213 | } |
||
214 | } |
||
215 | } |
||
216 | if (numEmpty > 0) |
||
217 | ret += (char)('0' + numEmpty); |
||
218 | if (r > 0) |
||
219 | ret += '/'; |
||
220 | } |
||
221 | ret += (pos.isWhiteMove() ? " w " : " b "); |
||
222 | |||
223 | // Castling rights |
||
224 | bool anyCastle = false; |
||
225 | if (pos.h1Castle()) { |
||
226 | ret += 'K'; |
||
227 | anyCastle = true; |
||
228 | } |
||
229 | if (pos.a1Castle()) { |
||
230 | ret += 'Q'; |
||
231 | anyCastle = true; |
||
232 | } |
||
233 | if (pos.h8Castle()) { |
||
234 | ret += 'k'; |
||
235 | anyCastle = true; |
||
236 | } |
||
237 | if (pos.a8Castle()) { |
||
238 | ret += 'q'; |
||
239 | anyCastle = true; |
||
240 | } |
||
241 | if (!anyCastle) { |
||
242 | ret += '-'; |
||
243 | } |
||
244 | |||
245 | // En passant target square |
||
246 | { |
||
247 | ret += ' '; |
||
248 | if (pos.getEpSquare() >= 0) { |
||
249 | int x = Position::getX(pos.getEpSquare()); |
||
250 | int y = Position::getY(pos.getEpSquare()); |
||
251 | ret += ((char)(x + 'a')); |
||
252 | ret += ((char)(y + '1')); |
||
253 | } else { |
||
254 | ret += '-'; |
||
255 | } |
||
256 | } |
||
257 | |||
258 | // Move counters |
||
259 | ret += ' '; |
||
260 | ret += num2Str(pos.getHalfMoveClock()); |
||
261 | ret += ' '; |
||
262 | ret += num2Str(pos.getFullMoveCounter()); |
||
263 | |||
264 | return ret; |
||
265 | } |
||
266 | |||
267 | std::string |
||
268 | TextIO::moveToUCIString(const Move& m) { |
||
269 | std::string ret = squareToString(m.from()); |
||
270 | ret += squareToString(m.to()); |
||
271 | switch (m.promoteTo()) { |
||
272 | case Piece::WQUEEN: |
||
273 | case Piece::BQUEEN: |
||
274 | ret += "q"; |
||
275 | break; |
||
276 | case Piece::WROOK: |
||
277 | case Piece::BROOK: |
||
278 | ret += "r"; |
||
279 | break; |
||
280 | case Piece::WBISHOP: |
||
281 | case Piece::BBISHOP: |
||
282 | ret += "b"; |
||
283 | break; |
||
284 | case Piece::WKNIGHT: |
||
285 | case Piece::BKNIGHT: |
||
286 | ret += "n"; |
||
287 | break; |
||
288 | default: |
||
289 | break; |
||
290 | } |
||
291 | return ret; |
||
292 | } |
||
293 | |||
294 | Move |
||
295 | TextIO::uciStringToMove(const std::string& move) { |
||
296 | Move m; |
||
297 | if ((move.length() < 4) || (move.length() > 5)) |
||
298 | return m; |
||
299 | int fromSq = TextIO::getSquare(move.substr(0, 2)); |
||
300 | int toSq = TextIO::getSquare(move.substr(2, 2)); |
||
301 | if ((fromSq < 0) || (toSq < 0)) { |
||
302 | return m; |
||
303 | } |
||
304 | char prom = ' '; |
||
305 | bool white = true; |
||
306 | if (move.length() == 5) { |
||
307 | prom = move[4]; |
||
308 | if (Position::getY(toSq) == 7) { |
||
309 | white = true; |
||
310 | } else if (Position::getY(toSq) == 0) { |
||
311 | white = false; |
||
312 | } else { |
||
313 | return m; |
||
314 | } |
||
315 | } |
||
316 | int promoteTo; |
||
317 | switch (prom) { |
||
318 | case ' ': |
||
319 | promoteTo = Piece::EMPTY; |
||
320 | break; |
||
321 | case 'q': |
||
322 | promoteTo = white ? Piece::WQUEEN : Piece::BQUEEN; |
||
323 | break; |
||
324 | case 'r': |
||
325 | promoteTo = white ? Piece::WROOK : Piece::BROOK; |
||
326 | break; |
||
327 | case 'b': |
||
328 | promoteTo = white ? Piece::WBISHOP : Piece::BBISHOP; |
||
329 | break; |
||
330 | case 'n': |
||
331 | promoteTo = white ? Piece::WKNIGHT : Piece::BKNIGHT; |
||
332 | break; |
||
333 | default: |
||
334 | return m; |
||
335 | } |
||
336 | return Move(fromSq, toSq, promoteTo); |
||
337 | } |
||
338 | |||
339 | static bool |
||
340 | isCapture(const Position& pos, const Move& move) { |
||
341 | if (pos.getPiece(move.to()) != Piece::EMPTY) |
||
342 | return true; |
||
343 | int p = pos.getPiece(move.from()); |
||
344 | return (p == (pos.isWhiteMove() ? Piece::WPAWN : Piece::BPAWN)) && |
||
345 | (move.to() == pos.getEpSquare()); |
||
346 | } |
||
347 | |||
348 | static std::string |
||
349 | pieceToChar(int p) { |
||
350 | switch (p) { |
||
351 | case Piece::WQUEEN: case Piece::BQUEEN: return "Q"; |
||
352 | case Piece::WROOK: case Piece::BROOK: return "R"; |
||
353 | case Piece::WBISHOP: case Piece::BBISHOP: return "B"; |
||
354 | case Piece::WKNIGHT: case Piece::BKNIGHT: return "N"; |
||
355 | case Piece::WKING: case Piece::BKING: return "K"; |
||
356 | } |
||
357 | return ""; |
||
358 | } |
||
359 | |||
360 | static std::string |
||
361 | moveToString(Position& pos, const Move& move, bool longForm, const MoveList& moves) { |
||
362 | std::string ret; |
||
363 | int wKingOrigPos = Position::getSquare(4, 0); |
||
364 | int bKingOrigPos = Position::getSquare(4, 7); |
||
365 | if (move.from() == wKingOrigPos && pos.getPiece(wKingOrigPos) == Piece::WKING) { |
||
366 | // Check white castle |
||
367 | if (move.to() == Position::getSquare(6, 0)) |
||
368 | ret += "O-O"; |
||
369 | else if (move.to() == Position::getSquare(2, 0)) |
||
370 | ret += "O-O-O"; |
||
371 | } else if (move.from() == bKingOrigPos && pos.getPiece(bKingOrigPos) == Piece::BKING) { |
||
372 | // Check black castle |
||
373 | if (move.to() == Position::getSquare(6, 7)) |
||
374 | ret += "O-O"; |
||
375 | else if (move.to() == Position::getSquare(2, 7)) |
||
376 | ret += "O-O-O"; |
||
377 | } |
||
378 | if (ret.length() == 0) { |
||
379 | int p = pos.getPiece(move.from()); |
||
380 | ret += pieceToChar(p); |
||
381 | int x1 = Position::getX(move.from()); |
||
382 | int y1 = Position::getY(move.from()); |
||
383 | int x2 = Position::getX(move.to()); |
||
384 | int y2 = Position::getY(move.to()); |
||
385 | if (longForm) { |
||
386 | ret += (char)(x1 + 'a'); |
||
387 | ret += (char)(y1 + '1'); |
||
388 | ret += isCapture(pos, move) ? 'x' : '-'; |
||
389 | } else { |
||
390 | if (p == (pos.isWhiteMove() ? Piece::WPAWN : Piece::BPAWN)) { |
||
391 | if (isCapture(pos, move)) |
||
392 | ret += (char)(x1 + 'a'); |
||
393 | } else { |
||
394 | int numSameTarget = 0; |
||
395 | int numSameFile = 0; |
||
396 | int numSameRow = 0; |
||
397 | for (int mi = 0; mi < moves.size; mi++) { |
||
398 | const Move& m = moves[mi]; |
||
399 | if (m.isEmpty()) |
||
400 | break; |
||
401 | if ((pos.getPiece(m.from()) == p) && (m.to() == move.to())) { |
||
402 | numSameTarget++; |
||
403 | if (Position::getX(m.from()) == x1) |
||
404 | numSameFile++; |
||
405 | if (Position::getY(m.from()) == y1) |
||
406 | numSameRow++; |
||
407 | } |
||
408 | } |
||
409 | if (numSameTarget < 2) { |
||
410 | // No file/row info needed |
||
411 | } else if (numSameFile < 2) { |
||
412 | ret += (char)(x1 + 'a'); // Only file info needed |
||
413 | } else if (numSameRow < 2) { |
||
414 | ret += (char)(y1 + '1'); // Only row info needed |
||
415 | } else { |
||
416 | ret += (char) (x1 + 'a'); // File and row info needed |
||
417 | ret += (char) (y1 + '1'); |
||
418 | } |
||
419 | } |
||
420 | if (isCapture(pos, move)) |
||
421 | ret += 'x'; |
||
422 | } |
||
423 | ret += (char)(x2 + 'a'); |
||
424 | ret += (char)(y2 + '1'); |
||
425 | if (move.promoteTo() != Piece::EMPTY) |
||
426 | ret += pieceToChar(move.promoteTo()); |
||
427 | } |
||
428 | UndoInfo ui; |
||
429 | if (MoveGen::givesCheck(pos, move)) { |
||
430 | pos.makeMove(move, ui); |
||
431 | MoveList nextMoves; |
||
432 | MoveGen::pseudoLegalMoves(pos, nextMoves); |
||
433 | MoveGen::removeIllegal(pos, nextMoves); |
||
434 | if (nextMoves.size == 0) |
||
435 | ret += '#'; |
||
436 | else |
||
437 | ret += '+'; |
||
438 | pos.unMakeMove(move, ui); |
||
439 | } |
||
440 | |||
441 | return ret; |
||
442 | } |
||
443 | |||
444 | std::string |
||
445 | TextIO::moveToString(const Position& pos, const Move& move, bool longForm) { |
||
446 | MoveList moves; |
||
447 | MoveGen::pseudoLegalMoves(pos, moves); |
||
448 | Position tmpPos(pos); |
||
449 | MoveGen::removeIllegal(tmpPos, moves); |
||
450 | return ::moveToString(tmpPos, move, longForm, moves); |
||
451 | } |
||
452 | |||
453 | namespace { |
||
454 | struct MoveInfo { |
||
455 | int piece = -1; // -1 for unspecified |
||
456 | int fromX = -1, fromY = -1; // -1 for unspecified |
||
457 | int toX = -1, toY = -1; // -1 for unspecified |
||
458 | int promPiece = -1; // -1 for unspecified |
||
459 | }; |
||
460 | } |
||
461 | |||
462 | Move |
||
463 | TextIO::stringToMove(Position& pos, const std::string& strMoveIn) { |
||
464 | std::string strMove; |
||
465 | for (size_t i = 0; i < strMoveIn.length(); i++) { |
||
466 | switch (strMoveIn[i]) { |
||
467 | case '=': |
||
468 | case '+': |
||
469 | case '#': |
||
470 | break; |
||
471 | default: |
||
472 | strMove += strMoveIn[i]; |
||
473 | break; |
||
474 | } |
||
475 | } |
||
476 | |||
477 | Move move; |
||
478 | if (strMove == "--") |
||
479 | return move; |
||
480 | |||
481 | const bool wtm = pos.isWhiteMove(); |
||
482 | |||
483 | MoveInfo info; |
||
484 | bool capture = false; |
||
485 | if ((strMove == "O-O") || (strMove =="0-0") || (strMove == "o-o")) { |
||
486 | info.piece = wtm ? Piece::WKING : Piece::BKING; |
||
487 | info.fromX = 4; |
||
488 | info.toX = 6; |
||
489 | info.fromY = info.toY = wtm ? 0 : 7; |
||
490 | info.promPiece = Piece::EMPTY; |
||
491 | } else if ((strMove == "O-O-O") || (strMove == "0-0-0") || (strMove == "o-o-o")) { |
||
492 | info.piece = wtm ? Piece::WKING : Piece::BKING; |
||
493 | info.fromX = 4; |
||
494 | info.toX = 2; |
||
495 | info.fromY = info.toY = wtm ? 0 : 7; |
||
496 | info.promPiece = Piece::EMPTY; |
||
497 | } else { |
||
498 | bool atToSq = false; |
||
499 | for (size_t i = 0; i < strMove.length(); i++) { |
||
500 | char c = strMove[i]; |
||
501 | if (i == 0) { |
||
502 | int piece = charToPiece(wtm, c); |
||
503 | if (piece >= 0) { |
||
504 | info.piece = piece; |
||
505 | continue; |
||
506 | } |
||
507 | } |
||
508 | int tmpX = c - 'a'; |
||
509 | if ((tmpX >= 0) && (tmpX < 8)) { |
||
510 | if (atToSq || (info.fromX >= 0)) |
||
511 | info.toX = tmpX; |
||
512 | else |
||
513 | info.fromX = tmpX; |
||
514 | } |
||
515 | int tmpY = c - '1'; |
||
516 | if ((tmpY >= 0) && (tmpY < 8)) { |
||
517 | if (atToSq || (info.fromY >= 0)) |
||
518 | info.toY = tmpY; |
||
519 | else |
||
520 | info.fromY = tmpY; |
||
521 | } |
||
522 | if ((c == 'x') || (c == '-')) { |
||
523 | atToSq = true; |
||
524 | if (c == 'x') |
||
525 | capture = true; |
||
526 | } |
||
527 | if (i == strMove.length() - 1) { |
||
528 | int promPiece = charToPiece(wtm, c); |
||
529 | if (promPiece >= 0) { |
||
530 | info.promPiece = promPiece; |
||
531 | } |
||
532 | } |
||
533 | } |
||
534 | if ((info.fromX >= 0) && (info.toX < 0)) { |
||
535 | info.toX = info.fromX; |
||
536 | info.fromX = -1; |
||
537 | } |
||
538 | if ((info.fromY >= 0) && (info.toY < 0)) { |
||
539 | info.toY = info.fromY; |
||
540 | info.fromY = -1; |
||
541 | } |
||
542 | if (info.piece < 0) { |
||
543 | bool haveAll = (info.fromX >= 0) && (info.fromY >= 0) && |
||
544 | (info.toX >= 0) && (info.toY >= 0); |
||
545 | if (!haveAll) |
||
546 | info.piece = wtm ? Piece::WPAWN : Piece::BPAWN; |
||
547 | } |
||
548 | if (info.promPiece < 0) |
||
549 | info.promPiece = Piece::EMPTY; |
||
550 | } |
||
551 | |||
552 | MoveList moves; |
||
553 | MoveGen::pseudoLegalMoves(pos, moves); |
||
554 | MoveGen::removeIllegal(pos, moves); |
||
555 | |||
556 | std::vector<Move> matches; |
||
557 | for (int i = 0; i < moves.size; i++) { |
||
558 | const Move& m = moves[i]; |
||
559 | int p = pos.getPiece(m.from()); |
||
560 | bool match = true; |
||
561 | if ((info.piece >= 0) && (info.piece != p)) |
||
562 | match = false; |
||
563 | if ((info.fromX >= 0) && (info.fromX != Position::getX(m.from()))) |
||
564 | match = false; |
||
565 | if ((info.fromY >= 0) && (info.fromY != Position::getY(m.from()))) |
||
566 | match = false; |
||
567 | if ((info.toX >= 0) && (info.toX != Position::getX(m.to()))) |
||
568 | match = false; |
||
569 | if ((info.toY >= 0) && (info.toY != Position::getY(m.to()))) |
||
570 | match = false; |
||
571 | if ((info.promPiece >= 0) && (info.promPiece != m.promoteTo())) |
||
572 | match = false; |
||
573 | if (match) |
||
574 | matches.push_back(m); |
||
575 | } |
||
576 | int nMatches = matches.size(); |
||
577 | if (nMatches == 0) |
||
578 | return move; |
||
579 | else if (nMatches == 1) |
||
580 | return matches[0]; |
||
581 | if (!capture) |
||
582 | return move; |
||
583 | for (size_t i = 0; i < matches.size(); i++) { |
||
584 | const Move& m = matches[i]; |
||
585 | int capt = pos.getPiece(m.to()); |
||
586 | if (capt != Piece::EMPTY) { |
||
587 | if (move.isEmpty()) { |
||
588 | move = m; |
||
589 | } else { |
||
590 | move = Move(); |
||
591 | return move; |
||
592 | } |
||
593 | } |
||
594 | } |
||
595 | return move; |
||
596 | } |
||
597 | |||
598 | std::string |
||
599 | TextIO::asciiBoard(const Position& pos) { |
||
600 | std::string ret; |
||
601 | ret += " +----+----+----+----+----+----+----+----+\n"; |
||
602 | for (int y = 7; y >= 0; y--) { |
||
603 | ret += " |"; |
||
604 | for (int x = 0; x < 8; x++) { |
||
605 | ret += ' '; |
||
606 | int p = pos.getPiece(Position::getSquare(x, y)); |
||
607 | if (p == Piece::EMPTY) { |
||
608 | bool dark = Position::darkSquare(x, y); |
||
609 | ret.append(dark ? ".. |" : " |"); |
||
610 | } else { |
||
611 | ret += Piece::isWhite(p) ? ' ' : '*'; |
||
612 | std::string pieceName = pieceToChar(p); |
||
613 | if (pieceName.length() == 0) |
||
614 | pieceName = "P"; |
||
615 | |||
616 | ret += pieceName; |
||
617 | ret += " |"; |
||
618 | } |
||
619 | } |
||
620 | |||
621 | ret += ("\n +----+----+----+----+----+----+----+----+\n"); |
||
622 | } |
||
623 | |||
624 | return ret; |
||
625 | } |
||
626 | |||
627 | std::string |
||
628 | TextIO::asciiBoard(U64 mask) { |
||
629 | std::string ret; |
||
630 | for (int y = 7; y >= 0; y--) { |
||
631 | for (int x = 0; x < 8; x++) { |
||
632 | int sq = Position::getSquare(x, y); |
||
633 | ret += (mask & (1ULL << sq)) ? '1' : '0'; |
||
634 | } |
||
635 | ret += '\n'; |
||
636 | } |
||
637 | return ret; |
||
638 | } |