Removed Q_ASSERT macros in Position, as in #26.
[tagua/yd.git] / src / variants / xchess / position.h
blobaabe3fd4d8be14d29af36ba1924e1e49421b5bdf
1 /*
2 Copyright (c) 2006 Paolo Capriotti <p.capriotti@sns.it>
3 (c) 2006 Maurizio Monge <maurizio.monge@kdemail.net>
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 2 of the License, or
8 (at your option) any later version.
9 */
11 #ifndef POSITION_H
12 #define POSITION_H
14 #include <vector>
15 #include <map>
16 #include <iostream>
17 #include <memory>
19 #include <QString>
20 #include <QStringList>
21 #include <boost/shared_ptr.hpp>
23 #include "common.h"
24 #include "pathinfo.h"
25 #include "option.h"
26 #include "interactiontype.h"
27 #include "turntest.h"
28 #include "variants/xchess/generator.h"
29 #include "variants/xchess/piecetype.h"
31 class AlgebraicNotation;
32 class VerboseNotation;
34 #define POLYMORPHIC_NEW(type, argsdecl, args) \
35 virtual type* _new argsdecl const { return new type args; }
37 template <typename M, typename P, typename B>
38 class Position;
40 template <typename M, typename P, typename B>
41 class Position {
42 public:
43 typedef typename P::Type Type;
44 typedef typename P::Color Color;
45 protected:
46 Color m_turn;
48 B m_board;
49 Point m_enPassantSquare;
51 bool m_castleWhiteKing : 1;
52 bool m_castleWhiteQueen : 1;
53 bool m_castleBlackKing : 1;
54 bool m_castleBlackQueen : 1;
56 public:
57 typedef M Move;
58 typedef P Piece;
59 typedef B Board;
61 Position(int = 8, int = 8);
62 Position(const OptList& l, int = 8, int = 8);
63 Position(Color turn,
64 bool castleWhiteKing, bool castleWhiteQueen,
65 bool castleBlackKing, bool castleBlackQueen,
66 const Point& enPassant);
67 Position(const Position<M, P, B>&);
68 template <typename M1, typename P1, typename B1>
69 Position(const Position<M1, P1, B1>&);
71 Point size() const { return m_board.getSize(); }
73 POLYMORPHIC_NEW(Position, (), ())
74 POLYMORPHIC_NEW(Position, (const Position* other), (*other))
75 virtual Position* clone() const { return new Position(*this); }
76 virtual ~Position();
78 virtual QString type() const { return "chess"; }
80 bool operator==(const Position<M, P, B>&) const;
81 bool operator!=(const Position<M, P, B>&) const;
83 virtual void setup();
85 void debugInfo() const;
87 virtual const Point first() const { return m_board.first(); }
88 virtual const Point last() const { return m_board.last(); }
89 virtual Point next(const Point& p) const { return m_board.next(p); }
90 inline bool valid(const Point& p) const { return m_board.valid(p); }
92 PathInfo path(const Point&, const Point&) const;
93 const Point& enPassantSquare() const { return m_enPassantSquare; }
95 virtual P get(const Point& p) const {
96 return valid(p) ? m_board[p] : P();
98 virtual P operator[](const Point& p) const { return get(p); }
99 inline void set(const Point& p, const P& piece) {
100 if(!valid(p))
101 return;
102 m_board[p] = piece;
104 inline void removePiece(const Point& p) { set(p, 0); }
105 inline void basicMovePiece(const M&);
107 inline InteractionType movable(const TurnTest& test, const Point& p) const {
108 if (!valid(p) || !m_board[p] || !test(m_turn))
109 return NoAction;
111 return m_board[p].color() == m_turn ? Moving : Premoving;
113 inline InteractionType droppable(const TurnTest& test, int p) const {
114 if (!test(m_turn))
115 return NoAction;
117 Color c = static_cast<Color>(p);
118 return c == m_turn ? Moving : Premoving;
120 inline Color turn() const { return m_turn; }
121 inline Color previousTurn() const { return Piece::oppositeColor(m_turn); }
122 inline const B& board() const { return m_board; }
123 inline bool castleKing(Color color) const { return color == WHITE? m_castleWhiteKing : m_castleBlackKing; }
124 inline bool castleQueen(Color color) const { return color == WHITE? m_castleWhiteQueen : m_castleBlackQueen; }
126 virtual bool attacks(Color, const Point& destination, Point& source) const;
127 virtual bool attacks(Color, const Point& destination) const;
128 virtual bool attacks(const Point& destination) const;
130 Point findPiece(Color, typename P::Type) const;
131 virtual void switchTurn();
132 virtual void setTurn(Color turn);
134 typename P::Type promotionType() const { return QUEEN; }
136 virtual void move(const M&);
137 virtual Position<M, P, B>* legallyMove(M&) const;
138 void stepBack(const Position<M, P, B>* oldPosition, const M& move);
139 virtual Color moveTurn(const M& move) const;
140 virtual bool checkPromotionType(const M&) const;
141 virtual bool pseudolegal(M&) const;
142 virtual bool testMove(M&) const;
143 virtual bool testPremove(M) const;
145 virtual M getMove(const AlgebraicNotation& san, bool& ok) const;
146 // virtual M getMove(const QString& san, bool& ok) const;
147 static M getVerboseMove(Color, const VerboseNotation& m);
149 //FIXME: Those are really very chess dependent, make them virtual at least
150 static Point kingStartingPosition(Color color) { return color == WHITE? Point(4,7) : Point(4,0); }
152 inline M kingCastleMove() const { return m_turn == WHITE?
153 M(Point(4, 7), Point(6, 7)) : M(Point(4,0), Point(6,0)); }
154 inline M queenCastleMove() const { return m_turn == WHITE?
155 M(Point(4, 7), Point(2, 7)) : M(Point(4,0), Point(2,0)); }
157 enum State {
158 InPlay,
159 WhiteWins,
160 BlackWins,
161 Draw
163 State state() const;
164 virtual boost::shared_ptr<AbstractGenerator<M> > createLegalGenerator() const;
165 virtual bool stalled() const;
166 // virtual bool pseudoStalled() const;
167 bool check() const;
168 bool check(Color) const;
170 virtual void basicDropPiece(P* piece, const Point& to);
171 virtual void executeCaptureOn(const Point& point);
173 boost::shared_ptr<P> moveHint(const M&) const;
175 void dump() const;
176 QString fen(int, int) const;
177 void fromFEN(const QString& fen, bool&);
178 QStringList borderCoords() const;
181 std::ostream& operator<<(std::ostream& os, const class GenericPosition&);
184 #include <iostream>
185 #include "algebraicnotation.h"
187 template <typename M, typename P, typename B>
188 Position<M, P, B>::Position(int width, int height)
189 : m_turn(WHITE)
190 , m_board(width, height)
191 , m_enPassantSquare(Point::invalid())
192 , m_castleWhiteKing(true)
193 , m_castleWhiteQueen(true)
194 , m_castleBlackKing(true)
195 , m_castleBlackQueen(true) { }
197 template <typename M, typename P, typename B>
198 Position<M, P, B>::Position(const OptList&, int width, int height)
199 : m_turn(WHITE)
200 , m_board(width, height)
201 , m_enPassantSquare(Point::invalid())
202 , m_castleWhiteKing(true)
203 , m_castleWhiteQueen(true)
204 , m_castleBlackKing(true)
205 , m_castleBlackQueen(true) { }
207 template <typename M, typename P, typename B>
208 Position<M, P, B>::Position(Color turn, bool castleWhiteKing,
209 bool castleWhiteQueen,
210 bool castleBlackKing,
211 bool castleBlackQueen,
212 const Point& enPassant)
213 : m_turn(turn)
214 , m_board(8, 8)
215 , m_enPassantSquare(enPassant)
216 , m_castleWhiteKing(castleWhiteKing)
217 , m_castleWhiteQueen(castleWhiteQueen)
218 , m_castleBlackKing(castleBlackKing)
219 , m_castleBlackQueen(castleBlackQueen) { }
221 template <typename M, typename P, typename B>
222 Position<M, P, B>::Position(const Position<M, P, B>& other)
223 : m_turn(other.m_turn)
224 , m_board(other.m_board)
225 , m_enPassantSquare(other.m_enPassantSquare)
226 , m_castleWhiteKing(other.m_castleWhiteKing)
227 , m_castleWhiteQueen(other.m_castleWhiteQueen)
228 , m_castleBlackKing(other.m_castleBlackKing)
229 , m_castleBlackQueen(other.m_castleBlackQueen) { }
231 template <typename M, typename P, typename B>
232 template <typename M1, typename P1, typename B1>
233 Position<M, P, B>::Position(const Position<M1, P1, B1>& other)
234 : m_turn(other.turn())
235 , m_board(other.board())
236 , m_enPassantSquare(other.enPassantSquare())
237 , m_castleWhiteKing(other.castleKing(WHITE))
238 , m_castleWhiteQueen(other.castleQueen(WHITE))
239 , m_castleBlackKing(other.castleKing(BLACK))
240 , m_castleBlackQueen(other.castleQueen(BLACK)) { }
243 template <typename M, typename P, typename B>
244 Position<M, P, B>::~Position() {
248 template <typename M, typename P, typename B>
249 QStringList Position<M, P, B>::borderCoords() const
251 QStringList retv;
252 Point p = m_board.getSize();
253 for(int i=0; i<p.x; i++)
254 retv << QChar('a'+i);
255 for(int i=1; i<=p.y; i++)
256 retv += QString::number(i);
257 return retv + retv;
260 template <typename M, typename P, typename B>
261 bool Position<M, P, B>::operator==(const Position<M, P, B>& other) const {
262 #if 0
263 std::cout << "turn: " << m_turn << " " << other.m_turn << std::endl;
264 std::cout << "ep: " << m_enPassantSquare << " " << other.m_enPassantSquare << std::endl;
265 std::cout << "wk: " << m_castleWhiteKing << " " << other.m_castleWhiteKing << std::endl;
266 std::cout << "wq: " << m_castleWhiteQueen << " " << other.m_castleWhiteQueen << std::endl;
267 std::cout << "bk: " << m_castleBlackKing << " " << other.m_castleBlackKing << std::endl;
268 std::cout << "bq: " << m_castleBlackQueen << " " << other.m_castleBlackQueen << std::endl;
269 if (m_turn != other.m_turn) {
270 std::cout << "turns differ" << std::endl;
271 return false;
273 if (!(m_board == other.m_board)) {
274 std::cout << "boards differ" << std::endl;
275 return false;
277 if (m_castleWhiteKing != other.m_castleWhiteKing) {
278 std::cout << "wk differ" << std::endl;
279 return false;
281 if (m_castleWhiteQueen != other.m_castleWhiteQueen) {
282 std::cout << "wq differ" << std::endl;
283 return false;
285 if (m_castleBlackKing != other.m_castleBlackKing) {
286 std::cout << "bk differ" << std::endl;
287 return false;
289 if (m_castleBlackQueen != other.m_castleBlackQueen) {
290 std::cout << "bq differ" << std::endl;
291 return false;
293 std::cout << "equal" << std::endl;
294 return true;
295 #else
296 return m_turn == other.m_turn &&
297 m_board == other.m_board &&
298 m_enPassantSquare == other.m_enPassantSquare &&
299 m_castleWhiteKing == other.m_castleWhiteKing &&
300 m_castleWhiteQueen == other.m_castleWhiteQueen &&
301 m_castleBlackKing == other.m_castleBlackKing &&
302 m_castleBlackQueen == other.m_castleBlackQueen;
303 #endif
306 template <typename M, typename P, typename B>
307 bool Position<M, P, B>::operator!=(const Position& other) const {
308 return !(*this == other);
311 template <typename M, typename P, typename B>
312 void Position<M, P, B>::debugInfo() const {
313 #if 0
314 std::cout << "board = " << &m_board << std::endl;
315 #endif
318 #define SET_PIECE(i,j, color, type) m_board[Point(i,j)] = P(color, type)
319 template <typename M, typename P, typename B>
320 void Position<M, P, B>::setup() {
321 for (int i = 0; i < 8; i++) {
322 SET_PIECE(i, 1, BLACK, PAWN);
323 SET_PIECE(i, 6, WHITE, PAWN);
326 SET_PIECE(0,0, BLACK, ROOK);
327 SET_PIECE(1,0, BLACK, KNIGHT);
328 SET_PIECE(2,0, BLACK, BISHOP);
329 SET_PIECE(3,0, BLACK, QUEEN);
330 SET_PIECE(4,0, BLACK, KING);
331 SET_PIECE(5,0, BLACK, BISHOP);
332 SET_PIECE(6,0, BLACK, KNIGHT);
333 SET_PIECE(7,0, BLACK, ROOK);
335 SET_PIECE(0,7, WHITE, ROOK);
336 SET_PIECE(1,7, WHITE, KNIGHT);
337 SET_PIECE(2,7, WHITE, BISHOP);
338 SET_PIECE(3,7, WHITE, QUEEN);
339 SET_PIECE(4,7, WHITE, KING);
340 SET_PIECE(5,7, WHITE, BISHOP);
341 SET_PIECE(6,7, WHITE, KNIGHT);
342 SET_PIECE(7,7, WHITE, ROOK);
344 m_turn = WHITE;
345 m_enPassantSquare = Point::invalid();
346 m_castleWhiteKing = true;
347 m_castleWhiteQueen = true;
348 m_castleBlackKing = true;
349 m_castleBlackQueen = true;
351 #undef SET_PIECE
353 template <typename M, typename P, typename B>
354 PathInfo Position<M, P, B>::path(const Point& from, const Point& to) const {
355 return m_board.path(from, to);
358 template <typename M, typename P, typename B>
359 void Position<M, P, B>::movePiece(const M& move) {
360 executeCaptureOn(move.to);
361 basicMovePiece(move);
362 switchTurn();
365 template <typename M, typename P, typename B>
366 void Position<M, P, B>::executeCaptureOn(const Point& point) {
367 m_board[point] = Piece();
370 template <typename M, typename P, typename B>
371 void Position<M, P, B>::basicMovePiece(const M& move) {
372 P p = m_board[move.from];
373 if (p) {
374 m_board[move.to] = p;
375 m_board[move.from] = Piece();
379 template <typename M, typename P, typename B>
380 void Position<M, P, B>::basicDropPiece(P* piece, const Point& to) {
381 if (piece) {
382 m_board[to] = *piece;
383 switchTurn();
387 template <typename M, typename P, typename B>
388 boost::shared_ptr<P> Position<M, P, B>::moveHint(const M& move) const {
389 if (move.type() == M::Promotion)
390 return boost::shared_ptr<P>(new Piece(m_turn, move.promotionType));
391 else
392 return boost::shared_ptr<P>();
396 template <typename M, typename P, typename B>
397 bool Position<M, P, B>::checkPromotionType(const M& m) const {
398 return (m.promotionType == KNIGHT ||
399 m.promotionType == BISHOP ||
400 m.promotionType == ROOK ||
401 m.promotionType == QUEEN);
404 template <typename M, typename P, typename B>
405 bool Position<M, P, B>::pseudolegal(M& move) const {
406 if (!move.valid()) return false;
408 if (!valid(move.from)) return false;
409 if (!valid(move.to)) return false;
410 P piece = m_board[move.from];
411 if (!piece) return false;
412 Color thisTurn = piece.color();
413 Color otherTurn = P::oppositeColor(thisTurn);
414 if (piece && (turn() == thisTurn)) {
415 move.setType(piece.canMove(*this, move.from, move.to));
417 if (move.type() == M::Invalid) return false;
419 if (move.type() == M::Promotion && !checkPromotionType(move))
420 return false;
422 if (move.type() == M::KingSideCastling) {
423 if (attacks(otherTurn, move.from) ||
424 attacks(otherTurn, move.from + Point(1,0))) return false;
426 else if (move.type() == M::QueenSideCastling) {
427 if (attacks(otherTurn, move.from) ||
428 attacks(otherTurn, move.from + Point(-1,0))) return false;
431 return true;
433 else return false;
436 template <typename M, typename P, typename B>
437 typename P::Color Position<M, P, B>::moveTurn(const M& move) const {
438 P piece = m_board[move.from];
439 if (piece) {
440 return piece.color();
444 template <typename M, typename P, typename B>
445 bool Position<M, P, B>::testMove(M& move) const {
447 if (move.status == M::Untested) {
448 if (pseudolegal(move)) {
449 Color turn = moveTurn(move);
451 // check king safety
452 std::auto_ptr<Position> tempPosition(clone());
453 tempPosition->move(move);
454 Point kingPos = tempPosition->findPiece(turn, KING);
456 if (kingPos == Point::invalid())
457 move.status = M::Illegal;
458 else if (tempPosition->attacks(P::oppositeColor(turn), kingPos))
459 move.status = M::Illegal;
460 else
461 move.status = M::Legal;
463 else
464 move.status = M::Illegal;
467 return move.status == M::Legal;
470 template <typename M, typename P, typename B>
471 M Position<M, P, B>::getMove(const AlgebraicNotation& san, bool& ok) const {
472 M candidate = M::invalid();
474 if (san.invalid()) {
475 ok = false;
476 return candidate;
479 if (san.castling != AlgebraicNotation::NoCastling) {
480 Point from = kingStartingPosition(turn());
481 Point to = from + (san.castling == AlgebraicNotation::KingSide? Point(2,0) : Point(-2,0));
482 P king = m_board[from];
483 if (!(king && king.type() == KING)) {
484 ok = false;
485 return candidate;
487 else {
488 ok = true;
489 return M(from, to);
493 if (san.from.valid()) {
494 candidate = M(san.from, san.to);
496 else {
497 for (Point i = first(); i <= last(); i = next(i)) {
498 P p = m_board[i];
499 M mv(i, san.to, static_cast<typename P::Type>(san.promotion));
500 if (i.resembles(san.from) && p && p.type() == san.type && p.color() == turn()
501 && testMove(mv)) {
503 if (candidate.valid()) {
504 ok = false;
505 return candidate; // return the first matching move
507 else candidate = mv;
512 ok = candidate.valid();
513 return candidate;
516 template <typename M, typename P, typename B>
517 M Position<M, P, B>::getMove(const QString& san, bool& ok) const {
518 return getMove(AlgebraicNotation(san), ok);
521 template <typename M, typename P, typename B>
522 M Position<M, P, B>::getVerboseMove(Color turn, const VerboseNotation& m) {
523 Point from, to;
524 if (m.castling == AlgebraicNotation::NoCastling) {
525 from = m.from;
526 to = m.to;
528 else {
529 from = kingStartingPosition(turn);
530 to = from + (m.castling == AlgebraicNotation::KingSide ? Point(2,0) : Point(-2, 0));
533 M res(from, to);
534 res.promotionType = static_cast<typename P::Type>(m.promotion);
536 return res;
539 template <typename M, typename P, typename B>
540 Position<M, P, B>* Position<M, P, B>::legallyMove(M& mv) const {
541 if (testMove(mv)) {
542 Position* res = clone();
543 res->move(mv);
544 return res;
546 else
547 return 0;
550 template <typename M, typename P, typename B>
551 void Position<M, P, B>::fromFEN(const QString& fen, bool& ok) {
552 ok = false;
554 QStringList data = fen.split(' ', QString::SkipEmptyParts);
555 const int boardIndex = 0;
556 const int turnIndex = 1;
557 const int castlingIndex = 2;
558 const int enPassantIndex = 3;
560 // read turn
561 QChar turn = data[turnIndex][0].toLower();
562 if (turn == 'w')
563 setTurn(WHITE);
564 else if (turn == 'b')
565 setTurn(BLACK);
567 // read castling
568 for (int i = 0; i < data[castlingIndex].length(); i++) {
569 QChar symbol = data[castlingIndex][i];
570 if (symbol == 'k')
571 m_castleBlackKing = true;
572 else if (symbol == 'q')
573 m_castleBlackQueen = true;
574 else if (symbol == 'K')
575 m_castleWhiteKing = true;
576 else if (symbol == 'Q')
577 m_castleWhiteQueen = true;
580 // read en-passant
581 m_enPassantSquare = Point(data[enPassantIndex], size().y);
583 // read board
584 Point cursor(0, 0);
585 for (int index = 0; index < data[boardIndex].length(); index++) {
586 QChar symbol = data[boardIndex][index];
587 if (symbol == '/') {
588 cursor = Point(0, cursor.y + 1);
590 else if (symbol.isDigit()) {
591 int k = symbol.toAscii() - '0';
592 cursor.x += k;
594 else {
595 if (!valid(cursor)) return;
596 typename P::Type type = P::getType(symbol);
597 if (type == INVALID_TYPE) return;
598 Color color = symbol.isUpper() ? WHITE : BLACK;
599 set(cursor, P(color, type));
600 cursor.x++;
604 ok = true;
607 // adapted from Maurizio Monge's rattatechess
608 template <typename M, typename P, typename B>
609 QString Position<M, P, B>::fen(int halfmove, int fullmove) const {
610 QString str;
612 // add board information
613 int cn = 0;
614 for (int i = 0; i < 8; i++) {
615 for (int j = 0; j < 8; j++) {
616 Point p = Point(j, i);
617 Piece pc = m_board[p];
618 if (!pc)
619 cn++;
620 else {
621 if (cn > 0) {
622 str += QString::number(cn);
623 cn = 0;
625 QString symbol = P::typeSymbol(pc.type());
626 if (pc.color() == BLACK)
627 symbol = symbol.toLower();
628 str += symbol;
631 if (cn > 0) {
632 str += QString::number(cn);
633 cn = 0;
635 if (i != 7)
636 str += "/";
639 // add turn information
640 str += turn() == WHITE ? " w " : " b ";
642 // add castling information
643 QString castleString;
644 if(m_castleWhiteKing)
645 castleString += "K";
646 if(m_castleWhiteQueen)
647 castleString += "Q";
648 if(m_castleBlackKing)
649 castleString += "k";
650 if(m_castleBlackQueen)
651 castleString += "k";
652 if (castleString == "") castleString = "-";
653 str += castleString + " ";
655 // add en passant information
656 if (m_enPassantSquare == Point::invalid())
657 str += "-";
658 else
659 str += m_enPassantSquare.toString(size().y);
660 str += " ";
662 // add move count information
663 str += QString::number(halfmove) + " " + QString::number(fullmove);
665 return str;
669 template <typename M, typename P, typename B>
670 void Position<M, P, B>::dump() const {
671 for (Point i = first(); i <= last(); i = next(i)) {
672 if (i.x == 0)
673 std::cout << "+---+---+---+---+---+---+---+---+" << std::endl;
675 Piece piece = m_board[i];
676 QString symbol;
677 if (piece) {
678 symbol = Piece::typeSymbol(piece.type());
679 if (piece.color() == BLACK) symbol = symbol.toLower();
681 else
682 symbol = ((i.x + i.y) % 2 == 0) ? " " : ".";
684 std::cout << "| " << symbol << " ";
685 if (i.x == 7)
686 std::cout << "|" << std::endl;
688 std::cout << "+---+---+---+---+---+---+---+---+" << std::endl;
691 template <typename M, typename P, typename B>
692 void Position<M, P, B>::move(const M& move) {
693 P piece = m_board[move.from];
694 if (!piece) return;
696 Color color = piece.color();
697 typename P::Type type = piece.type();
699 executeCaptureOn(move.to);
700 basicMovePiece(move);
702 if (move.type() == M::EnPassantTrigger)
703 m_enPassantSquare = (move.to + move.from) / 2;
704 else {
705 m_enPassantSquare = Point::invalid();
707 if (move.type() == M::EnPassantCapture) {
708 Point phantom(move.to.x, move.from.y);
709 m_board[phantom] = Piece();
712 else if (move.type() == M::Promotion) {
713 typename P::Type type = move.promotionType;
714 m_board[move.to] = P(piece.color(), type);
717 else if (move.type() == M::KingSideCastling) {
718 Point rookSquare = move.to + Point(1,0);
719 Point rookDestination = move.from + Point(1,0);
720 basicMovePiece(M(rookSquare, rookDestination));
723 else if (move.type() == M::QueenSideCastling) {
724 Point rookSquare = move.to - Point(2,0);
725 Point rookDestination = move.from - Point(1,0);
726 basicMovePiece(M(rookSquare, rookDestination));
730 if (type == KING) {
731 if (color == WHITE) {
732 m_castleWhiteKing = false;
733 m_castleWhiteQueen = false;
735 else {
736 m_castleBlackKing = false;
737 m_castleBlackQueen = false;
741 if (move.from == Point(0,0) || move.to == Point(0,0))
742 m_castleBlackQueen = false;
743 else if (move.from == Point(7,0) || move.to == Point(7,0))
744 m_castleBlackKing = false;
745 else if (move.from == Point(0,7) || move.to == Point(0,7))
746 m_castleWhiteQueen = false;
747 else if (move.from == Point(7,7) || move.to == Point(7,7))
748 m_castleWhiteKing = false;
750 switchTurn();
753 template <typename M, typename P, typename B>
754 void Position<M, P, B>::switchTurn() {
755 m_turn = P::oppositeColor(turn());
758 template <typename M, typename P, typename B>
759 void Position<M, P, B>::setTurn(Color turn) {
760 m_turn = turn;
763 template <typename M, typename P, typename B>
764 bool Position<M, P, B>::testPremove(M premove) const {
765 for (Point p = first(); p <= last(); p = next(p)) {
766 P piece = m_board[p];
767 if (!piece || piece.color() != turn()) continue;
768 for (Point q = first(); q <= last(); q = next(q)) {
769 M move(p,q);
770 if (testMove(move)) {
771 Position tempPosition(*this);
772 tempPosition.move(move);
774 if (tempPosition.testMove(premove)) return true;
779 return false;
782 template <typename M, typename P, typename B>
783 bool Position<M, P, B>::attacks(Color color, const Point& destination) const {
784 Point temp;
785 return attacks(color, destination, temp);
788 template <typename M, typename P, typename B>
789 bool Position<M, P, B>::attacks(Color color, const Point& destination, Point& source) const {
790 for (Point p = first(); p <= last(); p = next(p)) {
791 P piece = m_board[p];
792 if (piece && piece.color() == color && piece.canMove(*this, p, destination)) {
793 source = p;
794 return true;
797 return false;
800 template <typename M, typename P, typename B>
801 bool Position<M, P, B>::attacks(const Point& destination) const {
802 return attacks(turn(), destination);
805 template <typename M, typename P, typename B>
806 Point Position<M, P, B>::findPiece(Color color, typename P::Type type) const {
807 for (int i = 0; i < 8; i++)
808 for (int j = 0; j < 8; j++) {
809 Point p = Point(i,j);
810 P piece = m_board[p];
811 if (piece && piece.color() == color && piece.type() == type)
812 return p;
814 return Point::invalid();
817 template <typename M, typename P, typename B>
818 boost::shared_ptr<AbstractGenerator<M> >
819 Position<M, P, B>::createLegalGenerator() const {
820 return boost::shared_ptr<AbstractGenerator<M> >(
821 new MoveGenerator<Position, LegalMove<Position> >(*this));
824 // template <typename M, typename P, typename B>
825 // boost::shared_ptr<AbstractGenerator<M> > createPseudoLegalGenerator() const {
826 // return boost::shared_ptr<AbstractGenerator<M> >(
827 // new MoveGenerator<Position, LegalMove<Position> >(*this));
828 // }
830 template <typename M, typename P, typename B>
831 bool Position<M, P, B>::stalled() const {
832 boost::shared_ptr<AbstractGenerator<M> > generator =
833 createLegalGenerator();
834 std::vector<M> mv = generator->generate();
835 return generator->generate().size() == 0;
838 template <typename M, typename P, typename B>
839 bool Position<M, P, B>::pseudoStalled() const {
840 MoveGenerator<Position, PseudolegalMove<Position> > generator(*this);
841 return generator.generate().size() == 0;
844 template <typename M, typename P, typename B>
845 bool Position<M, P, B>::check(Color turn) const {
846 Point kingPosition = findPiece(turn, KING);
847 if (kingPosition == Point::invalid()) {
848 // a missing king is considered in check
849 return true;
851 else
852 return attacks(P::oppositeColor(turn), kingPosition);
855 template <typename M, typename P, typename B>
856 bool Position<M, P, B>::check() const {
857 return check(turn());
860 template <typename M, typename P, typename B>
861 typename Position<M, P, B>::State Position<M, P, B>::state() const {
862 if (!stalled()) return InPlay;
864 if (check())
865 return turn() == WHITE? BlackWins : WhiteWins;
866 else
867 return Draw;
871 //END Implementation
880 #endif // POSITION_H