Update the board after the animator has done its work.
[tagua/yd.git] / src / variants / xchess / position.h
blob5d29ba4e8fac689852c78085134b4ae9337c6c57
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 "variants/xchess/generator.h"
28 #include "variants/xchess/piecetype.h"
30 class AlgebraicNotation;
31 class VerboseNotation;
33 #define POLYMORPHIC_NEW(type, argsdecl, args) \
34 virtual type* _new argsdecl const { return new type args; }
36 template <typename M, typename P, typename B>
37 class Position;
39 template <typename M, typename P, typename B>
40 class PoolRef {
41 Position<M, P, B>* m_position;
42 int m_pool;
43 public:
45 PoolRef(Position<M, P, B>* position, int pool)
46 : m_position(position)
47 , m_pool(pool) {
49 int size();
50 int insert(int idx, const P& p);
51 P get(int idx);
52 P take(int idx);
55 template <typename M, typename P, typename B>
56 class Position {
57 public:
58 friend class PoolRef<M, P, B>;
59 typedef std::map<P, int> Pool;
61 protected:
62 typedef typename P::Color Color;
63 Color m_turn;
65 B m_board;
66 Pool m_pool;
67 Point m_enPassantSquare;
69 bool m_castleWhiteKing : 1;
70 bool m_castleWhiteQueen : 1;
71 bool m_castleBlackKing : 1;
72 bool m_castleBlackQueen : 1;
74 public:
75 typedef PoolRef<M, P, B> PoolReference;
76 typedef M Move;
77 typedef P Piece;
78 typedef B Board;
80 Position(int = 8, int = 8);
81 Position(const OptList& l, int = 8, int = 8);
82 Position(Color turn,
83 bool castleWhiteKing, bool castleWhiteQueen,
84 bool castleBlackKing, bool castleBlackQueen,
85 const Point& enPassant);
86 Position(const Position<M, P, B>&);
87 template <typename M1, typename P1, typename B1>
88 Position(const Position<M1, P1, B1>&);
90 Point size() const { return m_board.getSize(); }
92 POLYMORPHIC_NEW(Position, (), ())
93 POLYMORPHIC_NEW(Position, (const Position* other), (*other))
94 virtual Position* clone() const { return new Position(*this); }
95 virtual ~Position();
97 virtual QString type() const { return "chess"; }
99 bool operator==(const Position<M, P, B>&) const;
100 bool operator!=(const Position<M, P, B>&) const;
102 virtual void setup();
104 void debugInfo() const;
106 virtual const Point first() const { return m_board.first(); }
107 virtual const Point last() const { return m_board.last(); }
108 virtual Point next(const Point& p) const { return m_board.next(p); }
109 inline bool valid(const Point& p) const { return m_board.valid(p); }
111 PathInfo path(const Point&, const Point&) const;
112 const Point& enPassantSquare() const { return m_enPassantSquare; }
114 virtual PoolRef<M,P,B> pool(int index) { return PoolRef<M,P,B>(this, index); }
116 virtual P get(const Point& p) const {
117 return valid(p) ? m_board[p] : P();
119 virtual P operator[](const Point& p) const { return get(p); }
120 inline void set(const Point& p, const P& piece) {
121 if(!valid(p))
122 return;
123 m_board[p] = piece;
125 inline void removePiece(const Point& p) { set(p, 0); }
126 inline void basicMovePiece(const M&);
128 inline InteractionType movable(const Point& p) const {
129 if(!valid(p) || !m_board[p])
130 return NoAction;
131 return m_board[p].color() == m_turn ? Moving : Premoving;
133 inline Color turn() const { return m_turn; }
134 inline Color previousTurn() const { return Piece::oppositeColor(m_turn); }
135 inline const B& board() const { return m_board; }
136 inline bool castleKing(Color color) const { return color == WHITE? m_castleWhiteKing : m_castleBlackKing; }
137 inline bool castleQueen(Color color) const { return color == WHITE? m_castleWhiteQueen : m_castleBlackQueen; }
139 virtual bool attacks(Color, const Point& destination, Point& source) const;
140 virtual bool attacks(Color, const Point& destination) const;
141 virtual bool attacks(const Point& destination) const;
143 Point findPiece(Color, typename P::Type) const;
144 virtual void switchTurn();
145 virtual void setTurn(Color turn);
147 typename P::Type promotionType() const { return QUEEN; }
149 virtual void move(const M&);
150 virtual Position<M, P, B>* legallyMove(M&) const;
151 void stepBack(const Position<M, P, B>* oldPosition, const M& move);
152 virtual Color moveTurn(const M& move) const;
153 virtual bool checkPromotionType(const M&) const;
154 virtual bool pseudolegal(M&) const;
155 virtual bool testMove(M&) const;
156 virtual bool testPremove(M) const;
158 virtual M getMove(const AlgebraicNotation& san, bool& ok) const;
159 // virtual M getMove(const QString& san, bool& ok) const;
160 static M getVerboseMove(Color, const VerboseNotation& m);
162 //FIXME: Those are really very chess dependent, make them virtual at least
163 static Point kingStartingPosition(Color color) { return color == WHITE? Point(4,7) : Point(4,0); }
165 inline M kingCastleMove() const { return m_turn == WHITE?
166 M(Point(4, 7), Point(6, 7)) : M(Point(4,0), Point(6,0)); }
167 inline M queenCastleMove() const { return m_turn == WHITE?
168 M(Point(4, 7), Point(2, 7)) : M(Point(4,0), Point(2,0)); }
170 enum State {
171 InPlay,
172 WhiteWins,
173 BlackWins,
174 Draw
176 State state() const;
177 virtual boost::shared_ptr<AbstractGenerator<M> > createLegalGenerator() const;
178 virtual bool stalled() const;
179 // virtual bool pseudoStalled() const;
180 bool check() const;
181 bool check(Color) const;
183 virtual void basicDropPiece(P* piece, const Point& to);
184 virtual void executeCaptureOn(const Point& point);
186 boost::shared_ptr<P> moveHint(const M&) const;
188 void dump() const;
189 QString fen(int, int) const;
190 void fromFEN(const QString& fen, bool&);
191 QStringList borderCoords() const;
194 //typedef Position<ChessMove, ChessPiece, PieceGrid> ChessPosition;
195 std::ostream& operator<<(std::ostream& os, const class GenericPosition&);
198 #include <iostream>
199 #include "algebraicnotation.h"
201 template <typename M, typename P, typename B>
202 int PoolRef<M, P, B>::size() {
203 return 0; //BROKEN
206 template <typename M, typename P, typename B>
207 int PoolRef<M, P, B>::insert(int idx, const P& p) {
208 return 0; //BROKEN
211 template <typename M, typename P, typename B>
212 P PoolRef<M, P, B>::get(int idx) {
213 return P(); //BROKEN
216 template <typename M, typename P, typename B>
217 P PoolRef<M, P, B>::take(int idx) {
218 return P(); //BROKEN
221 template <typename M, typename P, typename B>
222 Position<M, P, B>::Position(int width, int height)
223 : m_turn(WHITE)
224 , m_board(width, height)
225 , m_enPassantSquare(Point::invalid())
226 , m_castleWhiteKing(true)
227 , m_castleWhiteQueen(true)
228 , m_castleBlackKing(true)
229 , m_castleBlackQueen(true) { }
231 template <typename M, typename P, typename B>
232 Position<M, P, B>::Position(const OptList&, int width, int height)
233 : m_turn(WHITE)
234 , m_board(width, height)
235 , m_enPassantSquare(Point::invalid())
236 , m_castleWhiteKing(true)
237 , m_castleWhiteQueen(true)
238 , m_castleBlackKing(true)
239 , m_castleBlackQueen(true) { }
241 template <typename M, typename P, typename B>
242 Position<M, P, B>::Position(Color turn, bool castleWhiteKing,
243 bool castleWhiteQueen,
244 bool castleBlackKing,
245 bool castleBlackQueen,
246 const Point& enPassant)
247 : m_turn(turn)
248 , m_board(8, 8)
249 , m_enPassantSquare(enPassant)
250 , m_castleWhiteKing(castleWhiteKing)
251 , m_castleWhiteQueen(castleWhiteQueen)
252 , m_castleBlackKing(castleBlackKing)
253 , m_castleBlackQueen(castleBlackQueen) { }
255 template <typename M, typename P, typename B>
256 Position<M, P, B>::Position(const Position<M, P, B>& other)
257 : m_turn(other.m_turn)
258 , m_board(other.m_board)
259 , m_pool(other.m_pool)
260 , m_enPassantSquare(other.m_enPassantSquare)
261 , m_castleWhiteKing(other.m_castleWhiteKing)
262 , m_castleWhiteQueen(other.m_castleWhiteQueen)
263 , m_castleBlackKing(other.m_castleBlackKing)
264 , m_castleBlackQueen(other.m_castleBlackQueen) { }
266 template <typename M, typename P, typename B>
267 template <typename M1, typename P1, typename B1>
268 Position<M, P, B>::Position(const Position<M1, P1, B1>& other)
269 : m_turn(other.turn())
270 , m_board(other.board())
271 , m_enPassantSquare(other.enPassantSquare())
272 , m_castleWhiteKing(other.castleKing(WHITE))
273 , m_castleWhiteQueen(other.castleQueen(WHITE))
274 , m_castleBlackKing(other.castleKing(BLACK))
275 , m_castleBlackQueen(other.castleQueen(BLACK)) { }
278 template <typename M, typename P, typename B>
279 Position<M, P, B>::~Position() {
283 template <typename M, typename P, typename B>
284 QStringList Position<M, P, B>::borderCoords() const
286 QStringList retv;
287 Point p = m_board.getSize();
288 for(int i=0; i<p.x; i++)
289 retv << QChar('a'+i);
290 for(int i=1; i<=p.y; i++)
291 retv += QString::number(i);
292 return retv + retv;
295 template <typename M, typename P, typename B>
296 bool Position<M, P, B>::operator==(const Position<M, P, B>& other) const {
297 #if 0
298 std::cout << "turn: " << m_turn << " " << other.m_turn << std::endl;
299 std::cout << "ep: " << m_enPassantSquare << " " << other.m_enPassantSquare << std::endl;
300 std::cout << "wk: " << m_castleWhiteKing << " " << other.m_castleWhiteKing << std::endl;
301 std::cout << "wq: " << m_castleWhiteQueen << " " << other.m_castleWhiteQueen << std::endl;
302 std::cout << "bk: " << m_castleBlackKing << " " << other.m_castleBlackKing << std::endl;
303 std::cout << "bq: " << m_castleBlackQueen << " " << other.m_castleBlackQueen << std::endl;
304 if (m_turn != other.m_turn) {
305 std::cout << "turns differ" << std::endl;
306 return false;
308 if (!(m_board == other.m_board)) {
309 std::cout << "boards differ" << std::endl;
310 return false;
312 if (m_castleWhiteKing != other.m_castleWhiteKing) {
313 std::cout << "wk differ" << std::endl;
314 return false;
316 if (m_castleWhiteQueen != other.m_castleWhiteQueen) {
317 std::cout << "wq differ" << std::endl;
318 return false;
320 if (m_castleBlackKing != other.m_castleBlackKing) {
321 std::cout << "bk differ" << std::endl;
322 return false;
324 if (m_castleBlackQueen != other.m_castleBlackQueen) {
325 std::cout << "bq differ" << std::endl;
326 return false;
328 std::cout << "equal" << std::endl;
329 return true;
330 #else
331 return m_turn == other.m_turn &&
332 m_board == other.m_board &&
333 m_enPassantSquare == other.m_enPassantSquare &&
334 m_castleWhiteKing == other.m_castleWhiteKing &&
335 m_castleWhiteQueen == other.m_castleWhiteQueen &&
336 m_castleBlackKing == other.m_castleBlackKing &&
337 m_castleBlackQueen == other.m_castleBlackQueen;
338 #endif
341 template <typename M, typename P, typename B>
342 bool Position<M, P, B>::operator!=(const Position& other) const {
343 return !(*this == other);
346 template <typename M, typename P, typename B>
347 void Position<M, P, B>::debugInfo() const {
348 #if 0
349 std::cout << "board = " << &m_board << std::endl;
350 #endif
353 #define SET_PIECE(i,j, color, type) m_board[Point(i,j)] = P(color, type)
354 template <typename M, typename P, typename B>
355 void Position<M, P, B>::setup() {
356 for (int i = 0; i < 8; i++) {
357 SET_PIECE(i, 1, BLACK, PAWN);
358 SET_PIECE(i, 6, WHITE, PAWN);
361 SET_PIECE(0,0, BLACK, ROOK);
362 SET_PIECE(1,0, BLACK, KNIGHT);
363 SET_PIECE(2,0, BLACK, BISHOP);
364 SET_PIECE(3,0, BLACK, QUEEN);
365 SET_PIECE(4,0, BLACK, KING);
366 SET_PIECE(5,0, BLACK, BISHOP);
367 SET_PIECE(6,0, BLACK, KNIGHT);
368 SET_PIECE(7,0, BLACK, ROOK);
370 SET_PIECE(0,7, WHITE, ROOK);
371 SET_PIECE(1,7, WHITE, KNIGHT);
372 SET_PIECE(2,7, WHITE, BISHOP);
373 SET_PIECE(3,7, WHITE, QUEEN);
374 SET_PIECE(4,7, WHITE, KING);
375 SET_PIECE(5,7, WHITE, BISHOP);
376 SET_PIECE(6,7, WHITE, KNIGHT);
377 SET_PIECE(7,7, WHITE, ROOK);
379 m_turn = WHITE;
380 m_enPassantSquare = Point::invalid();
381 m_castleWhiteKing = true;
382 m_castleWhiteQueen = true;
383 m_castleBlackKing = true;
384 m_castleBlackQueen = true;
386 #undef SET_PIECE
388 template <typename M, typename P, typename B>
389 PathInfo Position<M, P, B>::path(const Point& from, const Point& to) const {
390 return m_board.path(from, to);
393 template <typename M, typename P, typename B>
394 void Position<M, P, B>::movePiece(const M& move) {
395 executeCaptureOn(move.to);
396 basicMovePiece(move);
397 switchTurn();
400 template <typename M, typename P, typename B>
401 void Position<M, P, B>::executeCaptureOn(const Point& point) {
402 m_board[point] = Piece();
405 template <typename M, typename P, typename B>
406 void Position<M, P, B>::basicMovePiece(const M& move) {
407 P p = m_board[move.from];
408 Q_ASSERT(p);
410 m_board[move.to] = p;
411 m_board[move.from] = Piece();
414 template <typename M, typename P, typename B>
415 void Position<M, P, B>::basicDropPiece(P* piece, const Point& to) {
416 Q_ASSERT(piece);
417 m_board[to] = *piece;
418 switchTurn();
421 template <typename M, typename P, typename B>
422 boost::shared_ptr<P> Position<M, P, B>::moveHint(const M& move) const {
423 if (move.type() == M::Promotion)
424 return boost::shared_ptr<P>(new Piece(m_turn, move.promotionType));
425 else
426 return boost::shared_ptr<P>();
430 template <typename M, typename P, typename B>
431 bool Position<M, P, B>::checkPromotionType(const M& m) const {
432 return (m.promotionType == KNIGHT ||
433 m.promotionType == BISHOP ||
434 m.promotionType == ROOK ||
435 m.promotionType == QUEEN);
438 template <typename M, typename P, typename B>
439 bool Position<M, P, B>::pseudolegal(M& move) const {
440 if (!move.valid()) return false;
442 if (!valid(move.from)) return false;
443 if (!valid(move.to)) return false;
444 P piece = m_board[move.from];
445 Q_ASSERT(piece);
446 Color thisTurn = piece.color();
447 Color otherTurn = P::oppositeColor(thisTurn);
448 if (piece && (turn() == thisTurn)) {
449 move.setType(piece.canMove(*this, move.from, move.to));
451 if (move.type() == M::Invalid) return false;
453 if (move.type() == M::Promotion && !checkPromotionType(move))
454 return false;
456 if (move.type() == M::KingSideCastling) {
457 if (attacks(otherTurn, move.from) ||
458 attacks(otherTurn, move.from + Point(1,0))) return false;
460 else if (move.type() == M::QueenSideCastling) {
461 if (attacks(otherTurn, move.from) ||
462 attacks(otherTurn, move.from + Point(-1,0))) return false;
465 return true;
467 else return false;
470 template <typename M, typename P, typename B>
471 typename P::Color Position<M, P, B>::moveTurn(const M& move) const {
472 P piece = m_board[move.from];
473 Q_ASSERT(piece);
474 return piece.color();
477 template <typename M, typename P, typename B>
478 bool Position<M, P, B>::testMove(M& move) const {
480 if (move.status == M::Untested) {
481 if (pseudolegal(move)) {
482 Color turn = moveTurn(move);
484 // check king safety
485 std::auto_ptr<Position> tempPosition(clone());
486 tempPosition->move(move);
487 Point kingPos = tempPosition->findPiece(turn, KING);
489 if (kingPos == Point::invalid())
490 move.status = M::Illegal;
491 else if (tempPosition->attacks(P::oppositeColor(turn), kingPos))
492 move.status = M::Illegal;
493 else
494 move.status = M::Legal;
496 else
497 move.status = M::Illegal;
500 return move.status == M::Legal;
503 template <typename M, typename P, typename B>
504 M Position<M, P, B>::getMove(const AlgebraicNotation& san, bool& ok) const {
505 M candidate = M::invalid();
507 if (san.invalid()) {
508 ok = false;
509 return candidate;
512 if (san.castling != AlgebraicNotation::NoCastling) {
513 Point from = kingStartingPosition(turn());
514 Point to = from + (san.castling == AlgebraicNotation::KingSide? Point(2,0) : Point(-2,0));
515 P king = m_board[from];
516 if (!(king && king.type() == KING)) {
517 ok = false;
518 return candidate;
520 else {
521 ok = true;
522 return M(from, to);
526 if (san.from.valid()) {
527 candidate = M(san.from, san.to);
529 else {
530 for (Point i = first(); i <= last(); i = next(i)) {
531 P p = m_board[i];
532 M mv(i, san.to, static_cast<typename P::Type>(san.promotion));
533 if (i.resembles(san.from) && p && p.type() == san.type && p.color() == turn()
534 && testMove(mv)) {
536 if (candidate.valid()) {
537 ok = false;
538 return candidate; // return the first matching move
540 else candidate = mv;
545 ok = candidate.valid();
546 return candidate;
549 template <typename M, typename P, typename B>
550 M Position<M, P, B>::getMove(const QString& san, bool& ok) const {
551 return getMove(AlgebraicNotation(san), ok);
554 template <typename M, typename P, typename B>
555 M Position<M, P, B>::getVerboseMove(Color turn, const VerboseNotation& m) {
556 Point from, to;
557 if (m.castling == AlgebraicNotation::NoCastling) {
558 from = m.from;
559 to = m.to;
561 else {
562 from = kingStartingPosition(turn);
563 to = from + (m.castling == AlgebraicNotation::KingSide ? Point(2,0) : Point(-2, 0));
566 M res(from, to);
567 res.promotionType = static_cast<typename P::Type>(m.promotion);
569 return res;
572 template <typename M, typename P, typename B>
573 Position<M, P, B>* Position<M, P, B>::legallyMove(M& mv) const {
574 if (testMove(mv)) {
575 Position* res = clone();
576 res->move(mv);
577 return res;
579 else
580 return 0;
583 template <typename M, typename P, typename B>
584 void Position<M, P, B>::fromFEN(const QString& fen, bool& ok) {
585 ok = false;
587 QStringList data = fen.split(' ', QString::SkipEmptyParts);
588 const int boardIndex = 0;
589 const int turnIndex = 1;
590 const int castlingIndex = 2;
591 const int enPassantIndex = 3;
593 // read turn
594 QChar turn = data[turnIndex][0].toLower();
595 if (turn == 'w')
596 setTurn(WHITE);
597 else if (turn == 'b')
598 setTurn(BLACK);
600 // read castling
601 for (int i = 0; i < data[castlingIndex].length(); i++) {
602 QChar symbol = data[castlingIndex][i];
603 if (symbol == 'k')
604 m_castleBlackKing = true;
605 else if (symbol == 'q')
606 m_castleBlackQueen = true;
607 else if (symbol == 'K')
608 m_castleWhiteKing = true;
609 else if (symbol == 'Q')
610 m_castleWhiteQueen = true;
613 // read en-passant
614 m_enPassantSquare = Point(data[enPassantIndex], size().y);
616 // read board
617 Point cursor(0, 0);
618 for (int index = 0; index < data[boardIndex].length(); index++) {
619 QChar symbol = data[boardIndex][index];
620 if (symbol == '/') {
621 cursor = Point(0, cursor.y + 1);
623 else if (symbol.isDigit()) {
624 int k = symbol.toAscii() - '0';
625 cursor.x += k;
627 else {
628 if (!valid(cursor)) return;
629 typename P::Type type = P::getType(symbol);
630 if (type == INVALID_TYPE) return;
631 Color color = symbol.isUpper() ? WHITE : BLACK;
632 set(cursor, P(color, type));
633 cursor.x++;
637 ok = true;
640 // adapted from Maurizio Monge's rattatechess
641 template <typename M, typename P, typename B>
642 QString Position<M, P, B>::fen(int halfmove, int fullmove) const {
643 QString str;
645 // add board information
646 int cn = 0;
647 for (int i = 0; i < 8; i++) {
648 for (int j = 0; j < 8; j++) {
649 Point p = Point(j, i);
650 Piece pc = m_board[p];
651 if (!pc)
652 cn++;
653 else {
654 if (cn > 0) {
655 str += QString::number(cn);
656 cn = 0;
658 QString symbol = P::typeSymbol(pc.type());
659 if (pc.color() == BLACK)
660 symbol = symbol.toLower();
661 str += symbol;
664 if (cn > 0) {
665 str += QString::number(cn);
666 cn = 0;
668 if (i != 7)
669 str += "/";
672 // add turn information
673 str += turn() == WHITE ? " w " : " b ";
675 // add castling information
676 QString castleString;
677 if(m_castleWhiteKing)
678 castleString += "K";
679 if(m_castleWhiteQueen)
680 castleString += "Q";
681 if(m_castleBlackKing)
682 castleString += "k";
683 if(m_castleBlackQueen)
684 castleString += "k";
685 if (castleString == "") castleString = "-";
686 str += castleString + " ";
688 // add en passant information
689 if (m_enPassantSquare == Point::invalid())
690 str += "-";
691 else
692 str += m_enPassantSquare.toString(size().y);
693 str += " ";
695 // add move count information
696 str += QString::number(halfmove) + " " + QString::number(fullmove);
698 return str;
702 template <typename M, typename P, typename B>
703 void Position<M, P, B>::dump() const {
704 for (Point i = first(); i <= last(); i = next(i)) {
705 if (i.x == 0)
706 std::cout << "+---+---+---+---+---+---+---+---+" << std::endl;
708 Piece piece = m_board[i];
709 QString symbol;
710 if (piece) {
711 symbol = Piece::typeSymbol(piece.type());
712 if (piece.color() == BLACK) symbol = symbol.toLower();
714 else
715 symbol = ((i.x + i.y) % 2 == 0) ? " " : ".";
717 std::cout << "| " << symbol << " ";
718 if (i.x == 7)
719 std::cout << "|" << std::endl;
721 std::cout << "+---+---+---+---+---+---+---+---+" << std::endl;
723 for(typename Pool::const_iterator pi = m_pool.begin(); pi != m_pool.end(); ++pi) {
724 if(pi->first.color() == BLACK)
725 std::cout << Piece::typeSymbol(pi->first.type()).toLower() <<": "<<pi->second<<std::endl;
726 else
727 std::cout << Piece::typeSymbol(pi->first.type()) <<": "<<pi->second<<std::endl;
731 template <typename M, typename P, typename B>
732 void Position<M, P, B>::move(const M& move) {
733 P piece = m_board[move.from];
734 Q_ASSERT(piece);
736 Color color = piece.color();
737 typename P::Type type = piece.type();
739 executeCaptureOn(move.to);
740 basicMovePiece(move);
742 if (move.type() == M::EnPassantTrigger)
743 m_enPassantSquare = (move.to + move.from) / 2;
744 else {
745 m_enPassantSquare = Point::invalid();
747 if (move.type() == M::EnPassantCapture) {
748 Point phantom(move.to.x, move.from.y);
749 m_board[phantom] = Piece();
752 else if (move.type() == M::Promotion) {
753 typename P::Type type = move.promotionType;
754 m_board[move.to] = P(piece.color(), type);
757 else if (move.type() == M::KingSideCastling) {
758 Point rookSquare = move.to + Point(1,0);
759 Point rookDestination = move.from + Point(1,0);
761 P rook = m_board[rookSquare];
763 Q_ASSERT(rook);
764 Q_ASSERT(rook.type() == ROOK);
765 Q_UNUSED(rook);
767 basicMovePiece(M(rookSquare, rookDestination));
770 else if (move.type() == M::QueenSideCastling) {
771 Point rookSquare = move.to - Point(2,0);
772 Point rookDestination = move.from - Point(1,0);
774 P rook = m_board[rookSquare];
776 Q_ASSERT(rook);
777 Q_ASSERT(rook.type() == ROOK);
778 Q_UNUSED(rook);
780 basicMovePiece(M(rookSquare, rookDestination));
784 if (type == KING) {
785 if (color == WHITE) {
786 m_castleWhiteKing = false;
787 m_castleWhiteQueen = false;
789 else {
790 m_castleBlackKing = false;
791 m_castleBlackQueen = false;
795 if (move.from == Point(0,0) || move.to == Point(0,0))
796 m_castleBlackQueen = false;
797 else if (move.from == Point(7,0) || move.to == Point(7,0))
798 m_castleBlackKing = false;
799 else if (move.from == Point(0,7) || move.to == Point(0,7))
800 m_castleWhiteQueen = false;
801 else if (move.from == Point(7,7) || move.to == Point(7,7))
802 m_castleWhiteKing = false;
804 switchTurn();
807 template <typename M, typename P, typename B>
808 void Position<M, P, B>::switchTurn() {
809 m_turn = P::oppositeColor(turn());
812 template <typename M, typename P, typename B>
813 void Position<M, P, B>::setTurn(Color turn) {
814 m_turn = turn;
817 template <typename M, typename P, typename B>
818 bool Position<M, P, B>::testPremove(M premove) const {
819 for (Point p = first(); p <= last(); p = next(p)) {
820 P piece = m_board[p];
821 if (!piece || piece.color() != turn()) continue;
822 for (Point q = first(); q <= last(); q = next(q)) {
823 M move(p,q);
824 if (testMove(move)) {
825 Position tempPosition(*this);
826 tempPosition.move(move);
828 if (tempPosition.testMove(premove)) return true;
833 return false;
836 template <typename M, typename P, typename B>
837 bool Position<M, P, B>::attacks(Color color, const Point& destination) const {
838 Point temp;
839 return attacks(color, destination, temp);
842 template <typename M, typename P, typename B>
843 bool Position<M, P, B>::attacks(Color color, const Point& destination, Point& source) const {
844 for (Point p = first(); p <= last(); p = next(p)) {
845 P piece = m_board[p];
846 if (piece && piece.color() == color && piece.canMove(*this, p, destination)) {
847 source = p;
848 return true;
851 return false;
854 template <typename M, typename P, typename B>
855 bool Position<M, P, B>::attacks(const Point& destination) const {
856 return attacks(turn(), destination);
859 template <typename M, typename P, typename B>
860 Point Position<M, P, B>::findPiece(Color color, typename P::Type type) const {
861 for (int i = 0; i < 8; i++)
862 for (int j = 0; j < 8; j++) {
863 Point p = Point(i,j);
864 P piece = m_board[p];
865 if (piece && piece.color() == color && piece.type() == type)
866 return p;
868 return Point::invalid();
871 template <typename M, typename P, typename B>
872 boost::shared_ptr<AbstractGenerator<M> >
873 Position<M, P, B>::createLegalGenerator() const {
874 return boost::shared_ptr<AbstractGenerator<M> >(
875 new MoveGenerator<Position, LegalMove<Position> >(*this));
878 // template <typename M, typename P, typename B>
879 // boost::shared_ptr<AbstractGenerator<M> > createPseudoLegalGenerator() const {
880 // return boost::shared_ptr<AbstractGenerator<M> >(
881 // new MoveGenerator<Position, LegalMove<Position> >(*this));
882 // }
884 template <typename M, typename P, typename B>
885 bool Position<M, P, B>::stalled() const {
886 boost::shared_ptr<AbstractGenerator<M> > generator =
887 createLegalGenerator();
888 std::vector<M> mv = generator->generate();
889 return generator->generate().size() == 0;
892 template <typename M, typename P, typename B>
893 bool Position<M, P, B>::pseudoStalled() const {
894 MoveGenerator<Position, PseudolegalMove<Position> > generator(*this);
895 return generator.generate().size() == 0;
898 template <typename M, typename P, typename B>
899 bool Position<M, P, B>::check(Color turn) const {
900 Point kingPosition = findPiece(turn, KING);
901 if (kingPosition == Point::invalid()) {
902 // a missing king is considered in check
903 return true;
905 else
906 return attacks(P::oppositeColor(turn), kingPosition);
909 template <typename M, typename P, typename B>
910 bool Position<M, P, B>::check() const {
911 return check(turn());
914 template <typename M, typename P, typename B>
915 typename Position<M, P, B>::State Position<M, P, B>::state() const {
916 if (!stalled()) return InPlay;
918 if (check())
919 return turn() == WHITE? BlackWins : WhiteWins;
920 else
921 return Draw;
925 //END Implementation
934 #endif // POSITION_H