Go back to Richel Bilderbeek's homepage.

Go back to Richel Bilderbeek's C++ page.

 

 

 

 

 

(C++) Chess

 

STLQt CreatorLubuntu

 

Chess has many chess classes

Technical facts

 

 

 

 

 

 

./CppChess/CppChess.pri

 

INCLUDEPATH += \
    ../../Classes/CppChess

SOURCES += \
    ../../Classes/CppChess/chessbitboard.cpp \
    ../../Classes/CppChess/chessboard.cpp \
    ../../Classes/CppChess/chessboardfactory.cpp \
    ../../Classes/CppChess/chessboardtest.cpp \
    ../../Classes/CppChess/chessboardwidget.cpp \
    ../../Classes/CppChess/chesscastling.cpp \
    ../../Classes/CppChess/chesscolor.cpp \
    ../../Classes/CppChess/chessfile.cpp \
    ../../Classes/CppChess/chessgame.cpp \
    ../../Classes/CppChess/chessgamewidget.cpp \
    ../../Classes/CppChess/chesshelper.cpp \
    ../../Classes/CppChess/chessmove.cpp \
    ../../Classes/CppChess/chessmovefactory.cpp \
    ../../Classes/CppChess/chessmoves.cpp \
    ../../Classes/CppChess/chessmovetest.cpp \
    ../../Classes/CppChess/chesspiece.cpp \
    ../../Classes/CppChess/chesspiecefactory.cpp \
    ../../Classes/CppChess/chesspiecetest.cpp \
    ../../Classes/CppChess/chessplayer.cpp \
    ../../Classes/CppChess/chessrank.cpp \
    ../../Classes/CppChess/chessscore.cpp \
    ../../Classes/CppChess/chesssquare.cpp \
    ../../Classes/CppChess/chesssquarefactory.cpp \
    ../../Classes/CppChess/chesssquareselector.cpp \
    ../../Classes/CppChess/chesswidget.cpp

HEADERS  += \
    ../../Classes/CppChess/chessbitboard.h \
    ../../Classes/CppChess/chessboard.h \
    ../../Classes/CppChess/chessboardfactory.h \
    ../../Classes/CppChess/chessboardwidget.h \
    ../../Classes/CppChess/chesscastling.h \
    ../../Classes/CppChess/chesscolor.h \
    ../../Classes/CppChess/chessfile.h \
    ../../Classes/CppChess/chessfwd.h \
    ../../Classes/CppChess/chessgame.h \
    ../../Classes/CppChess/chessgamewidget.h \
    ../../Classes/CppChess/chesshelper.h \
    ../../Classes/CppChess/chessmove.h \
    ../../Classes/CppChess/chessmovefactory.h \
    ../../Classes/CppChess/chessmoves.h \
    ../../Classes/CppChess/chesspiece.h \
    ../../Classes/CppChess/chesspiecefactory.h \
    ../../Classes/CppChess/chessplayer.h \
    ../../Classes/CppChess/chessrank.h \
    ../../Classes/CppChess/chessscore.h \
    ../../Classes/CppChess/chesssquare.h \
    ../../Classes/CppChess/chesssquarefactory.h \
    ../../Classes/CppChess/chesssquareselector.h \
    ../../Classes/CppChess/chesswidget.h

OTHER_FILES += \
    ../../Classes/CppChess/Licence.txt

 

 

 

 

 

./CppChess/chessbitboard.h

 

#ifndef RIBI_CHESSBITBOARD_H
#define RIBI_CHESSBITBOARD_H

#include <iosfwd>
#include <vector>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#include <boost/shared_ptr.hpp>

#include "chessfwd.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace Chess {

///BitBoard is an 8x8 square of bools
struct BitBoard
{
  ///Create an empty BitBoard
  BitBoard();

  ///Set a value
  void Set(const boost::shared_ptr<const Square> s, const bool value);

  ///Get a value
  bool Get(const boost::shared_ptr<const Square> s) const;

  ///Obtain the version of this class
  static std::string GetVersion();

  ///Obtain the version history of this class
  static std::vector<std::string> GetVersionHistory();

  ///Test the BitBoard
  static void Test() noexcept;

  private:
  ///An 8x8 std::vector of bools
  std::vector<std::vector<bool>> m_v;

  friend std::ostream& operator<<(std::ostream& os, const BitBoard& b);
};

std::ostream& operator<<(std::ostream& os, const BitBoard& b);

} //~namespace Chess
} //~namespace ribi

#endif // RIBI_CHESSBITBOARD_H

 

 

 

 

 

./CppChess/chessbitboard.cpp

 

#include <algorithm>
#include <cassert>
#include <iostream>
#include <iterator>

#include "chessbitboard.h"
#include "chesssquare.h"
#include "chesssquarefactory.h"
#include "testtimer.h"
#include "trace.h"

ribi::Chess::BitBoard::BitBoard()
  : m_v(8,std::vector<bool>(8,false))
{
  #ifndef NDEBUG
  Test();
  #endif
  assert(m_v.size() == 8);
  assert(m_v[7].size() == 8);
}

std::string ribi::Chess::BitBoard::GetVersion()
{
  return "1.0";
}

std::vector<std::string> ribi::Chess::BitBoard::GetVersionHistory()
{
  return {
    "2012-01-25: version 1.0: initial version"
  };
}

void ribi::Chess::BitBoard::Set(const boost::shared_ptr<const Square> s, const bool value)
{
  const int x = s->GetFile().ToInt();
  const int y = s->GetRank().ToInt();
  #ifndef NDEBUG
  m_v.at(y).at(x) = value;
  #else
  m_v[y][x] = value;
  #endif
}

bool ribi::Chess::BitBoard::Get(const boost::shared_ptr<const Square> s) const
{
  const int x = s->GetFile().ToInt();
  const int y = s->GetRank().ToInt();
  #ifndef NDEBUG
  return m_v.at(y).at(x);
  #else
  return m_v[y][x];
  #endif
}

void ribi::Chess::BitBoard::Test() noexcept
{
  //Testing Chess::BitBoard exactly once
  {
    static bool tested = false;
    if (tested) return;
    tested = true;
  }
  ribi::Chess::SquareFactory();
  const TestTimer test_timer(__func__,__FILE__,1.0);
  const bool verbose{false};
    {
      if (verbose) { TRACE("Test Chess::BitBoard"); }
      BitBoard b;

      assert(!b.Get(SquareFactory().Create("g8")));
      b.Set(SquareFactory().Create("g8"),true);
      assert( b.Get(SquareFactory().Create(("g8"))));
      b.Set(SquareFactory().Create("g8"),false);
      assert(!b.Get(SquareFactory().Create(("g8"))));
    }
}

std::ostream& ribi::Chess::operator<<(std::ostream& os, const BitBoard& b)
{
  std::for_each(b.m_v.begin(),b.m_v.end(),
    [&os](const std::vector<bool>& v)
    {
      std::copy(v.begin(),v.end(),std::ostream_iterator<bool>(os,""));
      os << '\n';
    }
  );
  return os;
}

 

 

 

 

 

./CppChess/chessboard.h

 

#ifndef RIBI_CHESSBOARD_H
#define RIBI_CHESSBOARD_H

#include <iosfwd>
#include <set>
#include <vector>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#include <boost/logic/tribool.hpp>
#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>

#include "chessfwd.h"
#include "chesscolor.h"
#include "chessmove.h"
#include "chesscastling.h"
//#include "chesspiece.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace Chess {

struct Piece;

///Chess::Board is a class for a chessboard without gaming rules.
///Rules that handled by Chess::Board normally are:
/// - en passant
/// - castling
///Chess::Game is the class that uses a Chess::Board and adds these rules
///Rules that must be handled by Chess::Game are:
/// - keeping track of which player's turn it is
/// - determining a winner or draw
struct Board
{
  typedef boost::shared_ptr<Piece> PiecePtr;
  typedef boost::shared_ptr<const Piece> ConstPiecePtr;
  typedef std::set<PiecePtr> Pieces;
  typedef std::set<ConstPiecePtr> ConstPieces;

  Board(const Board& rhs) = delete; //BUG: this one was missing (and abused)
  Board& operator=(const Board& rhs) = delete;

  ///Check if a Move is valid to play in the current context
  ///Player must be indicated, because without castling would be ambigious
  ///Note that e2-e4 is only valid for the white player
  bool CanDoMove(const boost::shared_ptr<const Move> move, const Player player) const;

  ///Do a Move that is valid to play in the current context
  ///Player must be indicated, because without castling would be ambigious
  ///Note that e2-e4 is only valid for the white player
  void DoMove(const boost::shared_ptr<const Move> move, const Player player);

  //bool IsVisible(const Square& s);

  //const BoardVisibleType GetInSight(const Piece::Color color) const;
  //const Piece GetPiece(const int x, const int y) const;

  ///Create Pieces in their startup positions
  static Pieces GetInitialSetup();

  ///Get the Move history
  //const std::vector<boost::shared_ptr<Move>>& GetMoveHistory() const { return m_move_history; }

  ///Collect all moves that are possible for a Piece at a certain Square.
  ///If there is no Piece at that Square, no Moves are returned
  std::vector<boost::shared_ptr<Move>> GetMoves(const boost::shared_ptr<const Square> square) const;

  ///Collect all moves that are possible
  std::vector<boost::shared_ptr<Move>> GetMoves(const Player player) const;

  ///Find a Piece at a certain Square.
  ///If there is no Piece at that Square, an empty Piece is returned
  PiecePtr GetPiece(const boost::shared_ptr<const Square> square);

  ///Find a Piece at a certain Square.
  ///If there is no Piece at that Square, an empty Piece is returned
  ConstPiecePtr GetPiece(const boost::shared_ptr<const Square> square) const;

  ///Obtain all read-only Piece instances
  ConstPieces GetPieces() const;

  ///Obtain the version of this class
  static std::string GetVersion();

  ///Obtain the version history of this class
  static std::vector<std::string> GetVersionHistory();

  ///Get all squares that are visible by a player with the requested color.
  ///If the Color is set to Color::indeterminate, both players' sights
  ///are returned
  BitBoard GetVisibleSquares(const Player player) const;

  ///Is, in the current position, the player being in check?
  bool IsCheck(const Player player) const;

  ///Is the current position the active player being in checkmate?
  bool IsCheckmate(const Player player) const;

  ///The Score if the game has ended by agreement (instead of by checkmate)
  //const boost::shared_ptr<Chess::Score>& Score() const;

  #ifndef NDEBUG
  ///Tests the Board2d class
  static void Test() noexcept;
  #endif

  private:
  ///Construct a Board in the initial position, allowed by BoardFactory only
  Board(const Pieces& pieces);

  ~Board() {}

  ///All the Pieces
  Pieces m_pieces;

  ///The history of all Moves
  ///REMOVED: client has to keep track of these him/herself
  //std::vector<boost::shared_ptr<Move>> m_move_history;

  ///Check if a Player can do a castling
  bool CanDoCastling(const Castling castling, const Player player) const;

  ///Let a Player do a castling
  void DoCastling(const Castling castling, const Player player);

  ///Given a Move with a certain destination, deduce all Moves (with a starting position added)
  ///that have the same destination
  std::vector<boost::shared_ptr<const Move>> CompleteMove(
    const boost::shared_ptr<const Move> move,
    const Player player) const;

  static std::vector<boost::shared_ptr<Square >> CreateSquaresBetweenKingAndRook(
    const Player player,const Castling castling);

  ///Check if all squares between two Squares are empty (e
  ///Squares must be on one line
  bool EmptyBetween(const boost::shared_ptr<const Square> a, const boost::shared_ptr<const Square> b) const noexcept;

  ///Checks if the Move is valid in this situation
  ///??? REPLACE BY USING CANDOMOVE
  //bool IsValid(const Move& move) const;

  //friend bool operator==(const Board& lhs, const Board& rhs);
  friend class BoardFactory;
  //friend class boost::shared_ptr<Board>;
  friend boost::shared_ptr<Board> boost::make_shared<Board>(const Pieces&);

  friend void boost::checked_delete<>(      Board *);
  friend void boost::checked_delete<>(const Board *);
  friend class boost::detail::sp_ms_deleter<Board>;
  friend class boost::detail::sp_ms_deleter<const Board>;

  friend std::ostream& operator<<(std::ostream& os, const Board& board);
};

bool AreEqual(const Board::ConstPieces& lhs,const Board::ConstPieces& rhs);

bool operator==(const Board& lhs, const Board& rhs);
bool operator!=(const Board& lhs, const Board& rhs);


std::ostream& operator<<(std::ostream& os, const Board& board);

} //~namespace Chess
} //~namespace ribi

#endif // RIBI_CHESSBOARD_H

 

 

 

 

 

./CppChess/chessboard.cpp

 

#include <algorithm>
#include <cassert>
#include <iostream>
#include <stdexcept>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include <boost/lexical_cast.hpp>
#include <boost/multi_array.hpp>

#include "chessbitboard.h"
#include "chessboard.h"
#include "chessboardfactory.h"
#include "chesscastling.h"
#include "chesshelper.h"
#include "chessfile.h"
#include "chessmove.h"
#include "chesssquarefactory.h"
#include "chessmovefactory.h"
#include "chesspiece.h"
#include "chesspiecefactory.h"
#include "chessplayer.h"
#include "chessrank.h"
#include "chessscore.h"
#include "chesssquare.h"
#include "trace.h"
#pragma GCC diagnostic pop

ribi::Chess::Board::Board(const Pieces& pieces)
  : m_pieces(pieces)
{
  #ifndef NDEBUG
  Test();
  #endif
}

/*
ribi::Chess::Board::Board(const Board& other)
  //: m_move_history(other.m_move_history)
{
  #ifndef NDEBUG
  Test();
  #endif

  //Copy all Pieces
  //m_pieces = other.m_pieces;
  std::for_each(other.m_pieces.begin(), other.m_pieces.end(),
    [this](const PiecePtr& p)
    {
      assert(p);
      PiecePtr q(p->Clone());
      assert(p != q);
      assert(IsEqual(*p,*q));
      this->m_pieces.insert(q);
    }
  );
  assert(this->m_pieces.size() == other.m_pieces.size());
  assert(IsEqual(this->GetPieces(),other.GetPieces()));
  assert(IsEqual(*this,other));
}
*/

bool ribi::Chess::Board::CanDoCastling(const Castling castling, const Player player) const
{
  //Cannot castle when in check
  if (IsCheck(player)) return false;
  //Check King
  {
    const boost::shared_ptr<const Square> king_square
      = SquareFactory().Create(player == Player::white ? "e1" : "e8");
    assert(king_square);
    const ConstPiecePtr king = GetPiece(king_square);
    //Is there a King at the king's square?
    if (!king) return false;
    //Check if King has moved
    if (king->GetLastMove()) return false;
  }
  //Check Rook
  {
    const boost::shared_ptr<Square> rook_square {
      SquareFactory().Create(
        player == Player::white
          ? (castling == Castling::kingside ? "h1" : "a1")
          : (castling == Castling::kingside ? "h8" : "a8")
      )
    };
    assert(rook_square);
    const ConstPiecePtr rook = GetPiece(rook_square);
    //Is there a Rook at the rook's square?
    if (!rook) return false;
    //Check if Rook has moved
    if (rook->GetLastMove()) return false;
  }
  //Check squares in between King and Rook
  {
    const std::vector<boost::shared_ptr<Square >> squares
      = CreateSquaresBetweenKingAndRook(player,castling);
    //Check if these squares are empty
    if (std::count_if(squares.begin(),squares.end(),
      [this](const boost::shared_ptr<Square>& square)
      {
        assert(square);
        return GetPiece(square);
      }
    ) > 0)
    {
      return false;
    }
    //Check if the King needs to move through check
    const BitBoard bitboard = this->GetVisibleSquares(player == Player::white ? Player::black : Player::white);
    if (std::count_if(squares.begin(),squares.end(),
      [bitboard](const boost::shared_ptr<Square>& square)
      {
        assert(square);
        return bitboard.Get(square);
      }
    ) > 0)
    {
      return false;
    }
  }
  return true;
}

bool ribi::Chess::Board::CanDoMove(const boost::shared_ptr<const Move> move, const Player player) const
{
  const bool verbose{false};
  if (move->Score().get())
  {
    if (verbose) { TRACE("Scores are always valid moves on a Board"); }
    return true;
  }
  //Deduce from square if not a castling nor score
  if (!move->From() && move->To())
  {
    assert(move->To());
    //Check all player's pieces if they can move to that location
    //Collect all moves that end in the Move::To()
    std::vector<boost::shared_ptr<const Move>> moves = CompleteMove(move,player);
    if (moves.empty())
    {
      if (verbose) { TRACE("No moves with this destination"); }
      return false;
    }
    //The Move without a From is invalid if
    // * there is no valid move with that From
    // * there are more moves with that From
    std::vector<boost::shared_ptr<const Move>> valid;
    std::copy_if(moves.begin(),moves.end(),std::back_inserter(valid),
      [this,player](const boost::shared_ptr<const Move> m)
      {
        assert(m);
        return CanDoMove(m,player);
      }
    );
    if (valid.empty())
    {
      if (verbose) { TRACE("No valid moves with this destination"); }
      return false;
    }
    if (valid.size() > 1)
    {
      if (verbose) { TRACE("Multiple moves possible to reach the destination square"); }
      #ifndef NTRACE_BILDERBIKKEL
      std::for_each(valid.begin(),valid.end(),[](const boost::shared_ptr<const Move> m) { TRACE(m); } );
      #endif
      return false;
    }
    //There is exactly one Move found: test the complete move
    assert(valid[0]);
    return CanDoMove(valid[0],player);
  }
  //Each move here is complete, i.e. a simple move has a from and to value
  if (move->From())
  {
    const ConstPiecePtr p = this->GetPiece(move->From());
    assert(p);
    assert(p->GetSquare());
    assert(*p->GetSquare() == *move->From());
    if (p->GetColor() != player)
    {
      if (verbose) { TRACE("Cannot move opponent's pieces"); }
      return false;
    }
    if (!p->CanDoMove(move))
    {
      if (verbose) { TRACE("Piece can never do this move"); }
      return false;
    }
    if (p->GetNameChar() != move->Piece()->GetNameChar())
    {
      if (verbose) { TRACE("There is a different Piece on the square than as indicated by the Move"); }
      return false;
    }
    #ifndef NDEBUG
    #ifdef FIX_ISSUE_240
    {
      assert(p->CanDoMove(move));
      boost::shared_ptr<Board> b(BoardFactory().DeepCopy(*this));
      assert(*b == *this);
      const ConstPiecePtr q = b->GetPiece(move->From());
      assert(p);
      assert(q);
      assert(q && p);
      if ((*q != *p))
      {
        TRACE(p->ToStr());
        TRACE(q->ToStr());
        TRACE("BREAK");
      }
      assert(*q == *p);
      assert(q->CanDoMove(move));

    }
    #endif // FIX_ISSUE_240
    #endif // NDEBUG
    assert(move->Piece().get());
    if (move->Piece()->GetNameChar() != p->GetNameChar())
    {
      if (verbose) { TRACE("Type of piece in move is different than in reality"); }
      return false;
    }
    assert(move->From());
    assert(move->To());
    //Check for pieces blocking moves that span multiple squares
    if (!dynamic_cast<const PieceKnight*>(p.get()) && !EmptyBetween(move->From(),move->To()))
    {
      if (verbose) { TRACE("There are pieces blocking the move"); }
      return false;
    }
  }
  if (move->IsCastling())
  {
    assert(CanStrToCastling(move->GetStr()));
    const Castling castling = StrToCastling(move->GetStr());
    return CanDoCastling(castling,player);
  }
  //Check for capture
  if (move->To())
  {
    //Or it is a capture, or a move to an empty square
    if (move->IsCapture())
    {
      if (move->IsEnPassant())
      {
        //En-passant capture
        if (GetPiece(move->To()))
        {
          if (verbose) { TRACE("Cannot en-passant capture an occupied square"); }
          return false;
        }
        ///TODO
        //Determine captured square

        //Can only do en passant if at the captured squares there's an opponent

        //Can only do en passant if at the captured squares there's an opponent that has moved the last turn
        return true;
      }
      else
      {
        //Regular capture
        if (!GetPiece(move->To()))
        {
          if (verbose) { TRACE("Cannot capture an empty square"); }
          return false;
        }
        if (GetPiece(move->To())->GetColor() == GetPiece(move->From())->GetColor())
        {
          if (verbose) { TRACE("Cannot capture own piece"); }
          return false;
        }
      }
    }
    else
    {
      //Move is not a capture
      if (GetPiece(move->To()))
      {
        if (verbose) { TRACE("Cannot move to an occupied square"); }
        return false;
      }
      if (move->IsEnPassant())
      {
        if (verbose) { TRACE("Cannot perform an en passant capture without the move being a capture"); }
        return false;
      }
    }
  }
  //Check if move puts opponent in check
  {
    boost::shared_ptr<Board> b(BoardFactory().DeepCopy(*this));
    if (move->From())
    {
      assert(move->From());
      assert(b->GetPiece(move->From()));
      assert(b->GetPiece(move->From())->CanDoMove(move));
      b->GetPiece(move->From())->DoMove(move);
    }
    else
    {
      assert(move->IsCastling());
      assert(CanStrToCastling(move->GetStr()));
      const Castling castling = StrToCastling(move->GetStr());
      assert(CanDoCastling(castling,player));
      b->DoCastling(castling,player);
    }
    const bool check_in_real = b->IsCheck(player == Player::white ? Player::black : Player::white);
    if (check_in_real)
    {
      if (!move->IsCheck() && !move->IsCheckmate())
      {
        if (verbose) { TRACE("The move does not indicate a check, but in reality it does put the opponent into check"); }
        return false;
      }
    }
    else
    {
      //No check in reality
      if (move->IsCheck())
      {
        if (verbose) { TRACE("The move indicates a check, but it does not put opponent into check"); }
        return false;
      }
    }
  }

  //Check if move will put current player in check
  {
    boost::shared_ptr<Board> b(BoardFactory().DeepCopy(*this));
    if (move->From())
    {
      assert(move->From());
      assert(GetPiece(move->From()));
      assert(b->GetPiece(move->From()));
      assert(GetPiece(move->From())->CanDoMove(move));
      assert(*b == *this);
      #ifndef NDEBUG
      if (!b->GetPiece(move->From())->CanDoMove(move))
      {
        TRACE(*this);
        TRACE(b);
        TRACE(move);
      }

      #endif
      assert(b->GetPiece(move->From())->CanDoMove(move));
      b->GetPiece(move->From())->DoMove(move);
      //Does this check the player that tries do the move
    }
    else
    {
      assert(move->IsCastling());
      assert(CanStrToCastling(move->GetStr()));
      const Castling castling = StrToCastling(move->GetStr());
      assert(CanDoCastling(castling,player));
      b->DoCastling(castling,player);
    }
    if (b->IsCheck(player))
    {
      if (verbose) { TRACE("Move is forbidden, because it puts the current player into check"); }
      return false;
    }

  }
  //Check for move ending in checkmate
  {
    //Do move on cloned chessboard
    boost::shared_ptr<Board> b(BoardFactory().DeepCopy(*this));
    if (move->From())
    {
      assert(move->From());
      assert(b->GetPiece(move->From()));
      b->GetPiece(move->From())->DoMove(move);
    }
    else
    {
      assert(CanStrToCastling(move->GetStr()));
      boost::shared_ptr<Board> b(BoardFactory().DeepCopy(*this));
      const Castling castling = StrToCastling(move->GetStr());
      assert(b->CanDoCastling(castling,player));
      b->DoCastling(castling,player);
    }
    //Is opponent in checkmate?
    const bool checkmate_in_real = b->IsCheckmate(player == Player::white ? Player::black : Player::white);
    if (checkmate_in_real != move->IsCheckmate())
    {
      if (checkmate_in_real)
      {
        if (verbose) { TRACE("The move does not indicate a checkmate, but in reality it does put the opponent into checkmate"); }
      }
      else
      {
        if (verbose) { TRACE("The move indicates a checkmate, but it does not put opponent into checkmate"); }
      }
      return false;
    }
  }
  return true;
}

std::vector<boost::shared_ptr<const ribi::Chess::Move>>
  ribi::Chess::Board::CompleteMove(
    const boost::shared_ptr<const Move> move,
    const Player player) const
{
  const bool verbose{false};
  assert(!move->From());
  assert(move->To());
  assert(!move->Score());
  //Deduce from square if not a castling nor score

  //Check all player's pieces if they can move to that location
  //Collect all mives that end in the Move::To()
  std::vector<boost::shared_ptr<const Move>> moves;
  for (const PiecePtr& piece: m_pieces)
  {
    //Check for this player its pieces only that are of the same type as the move
    assert(move->Piece());
    if (piece->GetColor() == player && move->Piece()->GetNameChar() == piece->GetNameChar() )
    {
      //Obtain this right-colored piece its moves
      const std::vector<boost::shared_ptr<Move>> pms = piece->GetMoves();
      std::for_each(pms.begin(),pms.end(),
        [&moves,this,&move,player](const boost::shared_ptr<Move> n)
        {
          assert(n);
          //If the Move has a To, goes to the right To and is valid...
          if (n->To() && (*n->To() == *move->To()) && this->CanDoMove(n,player))
          {
            if (verbose) { TRACE(n); }
            //Store this Move
            moves.push_back(n);
          }
        }
      );
    }
  }
  return moves;
}


std::vector<boost::shared_ptr<ribi::Chess::Square >> ribi::Chess::Board::CreateSquaresBetweenKingAndRook(
  const Player player,const Castling castling)
{
  std::vector<boost::shared_ptr<Square >> v;
  if (player == Player::white)
  {
    if (castling == Castling::kingside)
    {
      {
        const boost::shared_ptr<Square > s = SquareFactory().Create("f1");
        assert(s);
        v.push_back(s);
      }
      {
        const boost::shared_ptr<Square > s = SquareFactory().Create("g1");
        assert(s);
        v.push_back(s);
      }
    }
    else
    {
      assert(castling == Castling::queenside);
      {
        const boost::shared_ptr<Square > s = SquareFactory().Create("b1");
        assert(s);
        v.push_back(s);
      }
      {
        const boost::shared_ptr<Square > s = SquareFactory().Create("c1");
        assert(s);
        v.push_back(s);
      }
      {
        const boost::shared_ptr<Square > s = SquareFactory().Create("d1");
        assert(s);
        v.push_back(s);
      }
    }
  }
  else
  {
    assert(player == Player::black);
    if (castling == Castling::kingside)
    {
      {
        const boost::shared_ptr<Square > s = SquareFactory().Create("f8");
        assert(s);
        v.push_back(s);
      }
      {
        const boost::shared_ptr<Square > s = SquareFactory().Create("g8");
        assert(s);
        v.push_back(s);
      }
    }
    else
    {
      assert(castling == Castling::queenside);
      {
        const boost::shared_ptr<Square > s = SquareFactory().Create("b8");
        assert(s);
        v.push_back(s);
      }
      {
        const boost::shared_ptr<Square > s = SquareFactory().Create("c8");
        assert(s);
        v.push_back(s);
      }
      {
        const boost::shared_ptr<Square > s = SquareFactory().Create("d8");
        assert(s);
        v.push_back(s);
      }
    }
  }
  return v;
}

void ribi::Chess::Board::DoCastling(const Castling castling, const Player player)
{
  assert(CanDoCastling(castling,player));
  //Get King
  {
    const boost::shared_ptr<const Square> king_from_square
      = SquareFactory().Create(player == Player::white ? "e1" : "e8");
    assert(king_from_square);
    //const Square king_to_square = (player == Player::white
    //  ? (castling == Castling::kingside ? Square("g1") : Square("c1"))
    //  : (castling == Castling::kingside ? Square("g8") : Square("c8")) );
    const PiecePtr king = GetPiece(king_from_square);
    assert(king);
    const boost::shared_ptr<Chess::Move> castling_move
      = Chess::MoveFactory().Create(CastlingToStr(castling));
    assert(castling_move);
    king->DoMove(castling_move);
  }
  //Check Rook
  {
    const boost::shared_ptr<Square> rook_square
      = SquareFactory().Create(player == Player::white
      ? (castling == Castling::kingside ? "h1" : "a1")
      : (castling == Castling::kingside ? "h8" : "a8")
    );
    assert(rook_square);
    const PiecePtr rook = GetPiece(rook_square);
    assert(rook);
    const boost::shared_ptr<Chess::Move> castling_move
      = Chess::MoveFactory().Create(CastlingToStr(castling));
    assert(castling_move);
    rook->DoMove(castling_move);
  }
}

void ribi::Chess::Board::DoMove(const boost::shared_ptr<const Move> move,const Player player)
{
  assert(CanDoMove(move,player));
  if (!move->From() && move->To())
  {
    assert(move->To());
    //Check all player's pieces if they can move to that location
    //Collect all moves that end in the Move::To()
    std::vector<boost::shared_ptr<const Move>> moves = CompleteMove(move,player);
    //The Move without a From is invalid if
    // * there is no valid move with that From
    // * there are more moves with that From
    assert(moves.size() == 1);
    //There is exactly one Move found: test the complete move
    assert(moves[0]);
    return DoMove(moves[0],player);
  }

  if (move->From())
  {
    PiecePtr p = GetPiece(move->From());
    assert(p);
    assert(p->CanDoMove(move));
    p->DoMove(move);
  }
  else if (move->IsCastling())
  {
    assert(CanStrToCastling(move->GetStr()));
    const Castling castling = StrToCastling( move->GetStr() );
    assert(CanDoCastling(castling,player));
    DoCastling(castling,player);
  }
  else
  {
    assert(!"Should not get here");
  }
}

bool ribi::Chess::Board::EmptyBetween(
  const boost::shared_ptr<const Square> a,
  const boost::shared_ptr<const Square> b) const noexcept
{
  const int dx = a->GetFile().ToInt() - b->GetFile().ToInt();
  const int dy = a->GetRank().ToInt() - b->GetRank().ToInt();
  //Are there squares in between to check for being occupied?
  assert(dx != 0 || dy != 0);
  //Squares are adjacent (horizontally, vertically or diagonally)
  if (dx + dy == 1) return true;

  const int step_x = (dx > 0 ? 1 : (dx < 0 ? -1 : 0));
  const int step_y = (dy > 0 ? 1 : (dy < 0 ? -1 : 0));
  const int n_steps = std::max(std::abs(dx),std::abs(dy));
  for (int i=1; i!=n_steps; ++i)
  {
    const int x = b->GetFile().ToInt() + (i * step_x);
    const int y = b->GetRank().ToInt() + (i * step_y);
    assert(x >= 0);
    assert(y >= 0);
    assert(x  < 8);
    assert(y  < 8);
    const boost::shared_ptr<const Square> square = SquareFactory().Create(File(x),Rank(y));
    assert(square);
    assert(*square != *a);
    assert(*square != *b);
    if (this->GetPiece(square)) return false;
  }
  return true;
}

//Color ribi::Chess::Board::GetActivePlayer() const
//{
//  return (m_moves.size() % 2 ? Color::black : Color::white);
//}

ribi::Chess::Board::PiecePtr
  ribi::Chess::Board::GetPiece(const boost::shared_ptr<const Square> square)
{
  const auto i = std::find_if(m_pieces.begin(),m_pieces.end(),
    [&square](const PiecePtr& p)
    {
      return *p->GetSquare() == *square;
    }
  );

  if (i == m_pieces.end()) { ribi::Chess::Board::PiecePtr p; assert(!p); return p; }
  else { assert(*i); return *i; }
}

ribi::Chess::Board::ConstPiecePtr
  ribi::Chess::Board::GetPiece(const boost::shared_ptr<const Square> square) const
{
  const auto i = std::find_if(m_pieces.begin(),m_pieces.end(),
    [&square](const PiecePtr& p)
    {
      return *p->GetSquare() == *square;
    }
  );

  if (i == m_pieces.end()) { ribi::Chess::Board::ConstPiecePtr p; assert(!p); return p; }
  else
  {
    ribi::Chess::Board::ConstPiecePtr p(*i);
    assert(p);
    assert(*p->GetSquare() == *square);
    assert(*p == *(*i));
    assert(p->GetSquare());
    return p;
  }
}

ribi::Chess::Board::ConstPieces ribi::Chess::Board::GetPieces() const
{
  return AddConst(m_pieces);
  /*
  ConstPieces v;
  std::transform(m_pieces.begin(),m_pieces.end(),std::inserter(v,v.begin()),
    [](const ribi::Chess::Board::PiecePtr& piece)
    {
      ConstPiecePtr p = piece->Clone();
      assert(IsEqual(*p,*piece));
      assert(p != piece);
      return p;
    }
  );
  return v;
  */
}

ribi::Chess::Board::Pieces ribi::Chess::Board::GetInitialSetup()
{
  ribi::Chess::Board::Pieces v;
  const auto colors { Color::black, Color::white };
  std::for_each(colors.begin(),colors.end(),
    [&v](const Color color)
    {
      //Pawns
      {
        const Chess::Rank rank = color == Color::white ? Rank(2) : Rank(7);
        for (int i=0; i!=8; ++i)
        {
          const boost::shared_ptr<Square> s(SquareFactory().Create(Chess::File(i),rank));
          assert(s);
          const boost::shared_ptr<Piece> p = PieceFactory().Create('.',color,s);
          assert(p);
          v.insert(p);
        }
      }
      {
        //Royalty
        const Chess::Rank rank = color == Color::white ? Rank(0) : Rank(7);
        {
          const boost::shared_ptr<Square> s(SquareFactory().Create(Chess::File("a"),rank));
          assert(s);
          const boost::shared_ptr<Piece> p = PieceFactory().Create('R',color,s);
          assert(p);
          v.insert(p);
        }
        {
          const boost::shared_ptr<Square> s(SquareFactory().Create(Chess::File("b"),rank));
          assert(s);
          const boost::shared_ptr<Piece> p = PieceFactory().Create('N',color,s);
          assert(p);
          v.insert(p);
        }
        {
          const boost::shared_ptr<Square> s(SquareFactory().Create(Chess::File("c"),rank));
          assert(s);
          const boost::shared_ptr<Piece> p = PieceFactory().Create('B',color,s);
          assert(p);
          v.insert(p);
        }
        {
          const boost::shared_ptr<Square> s(SquareFactory().Create(Chess::File("d"),rank));
          assert(s);
          const boost::shared_ptr<Piece> p = PieceFactory().Create('Q',color,s);
          assert(p);
          v.insert(p);
        }
        {
          const boost::shared_ptr<Square> s(SquareFactory().Create(Chess::File("e"),rank));
          assert(s);
          const boost::shared_ptr<Piece> p = PieceFactory().Create('K',color,s);
          assert(p);
          v.insert(p);
        }
        {
          const boost::shared_ptr<Square> s(SquareFactory().Create(Chess::File("f"),rank));
          assert(s);
          const boost::shared_ptr<Piece> p = PieceFactory().Create('B',color,s);
          assert(p);
          v.insert(p);
        }
        {
          const boost::shared_ptr<Square> s(SquareFactory().Create(Chess::File("g"),rank));
          assert(s);
          const boost::shared_ptr<Piece> p = PieceFactory().Create('N',color,s);
          assert(p);
          v.insert(p);
        }
        {
          const boost::shared_ptr<Square> s(SquareFactory().Create(Chess::File("h"),rank));
          assert(s);
          const boost::shared_ptr<Piece> p = PieceFactory().Create('R',color,s);
          assert(p);
          v.insert(p);
        }
      }
    }
  );
  return v;
}

std::vector<boost::shared_ptr<ribi::Chess::Move>> ribi::Chess::Board::GetMoves(const Player player) const
{
  std::vector<boost::shared_ptr<Move>> v;

  std::for_each(m_pieces.begin(),m_pieces.end(),
    [this,&v,player](const PiecePtr& p)
    {
      if (p->GetColor() == player)
      {
        assert(p->GetSquare());

        //Obtain all valid moves from the square the piece is standing on
        const std::vector<boost::shared_ptr<Move>> w = this->GetMoves(p->GetSquare());

        std::copy(w.begin(),w.end(),std::back_inserter(v));
      }
    }
  );

  return v;
}

std::vector<boost::shared_ptr<ribi::Chess::Move>> ribi::Chess::Board::GetMoves(
  const boost::shared_ptr<const Square> square) const
{
  const ConstPiecePtr piece = GetPiece(square);
  ///TODO: In Traitor's Chess you can move Pieces of the opponent
  //if (!piece || piece->GetColor() != this->GetActivePlayer()) return std::vector<boost::shared_ptr<Move>>();
  if (!piece) return std::vector<boost::shared_ptr<Move>>();
  const Player player = ColorToPlayer(piece->GetColor());

  const std::vector<boost::shared_ptr<Move>> all_moves = piece->GetMoves();
  std::vector<boost::shared_ptr<Move>> moves;
  std::copy_if(all_moves.begin(), all_moves.end(),
    std::back_inserter(moves),
    [this,player](const boost::shared_ptr<Move> move)
    {
      assert(move);
      return this->CanDoMove(move,player);
    }
  );
  return moves;
}

std::string ribi::Chess::Board::GetVersion()
{
  return "1.0";
}

std::vector<std::string> ribi::Chess::Board::GetVersionHistory()
{
  return {
    "2012-01-25: version 1.0: initial version"
  };
}

ribi::Chess::BitBoard ribi::Chess::Board::GetVisibleSquares(const Player player) const
{
  //Collect the Pieces we want to know their sights of
  std::vector<PiecePtr> pieces;
  std::copy_if(m_pieces.begin(), m_pieces.end(),
   std::back_inserter(pieces),
    [player](const PiecePtr& p)
    {
      return p->GetColor() == player;
    }
  );
  //Collect the Squares the Pieces can move to on a BitBoard
  Chess::BitBoard b;
  std::for_each(
    pieces.begin(),pieces.end(),
    [this,&b](const PiecePtr& p)
    {
      assert(p->GetSquare());
      const std::vector<boost::shared_ptr<Move>> moves = this->GetMoves(p->GetSquare());
      std::for_each(moves.begin(),moves.end(),
        [&b](const boost::shared_ptr<Move> m)
        {
          assert(m->To());
          b.Set(m->To(),true);
        }
      );
      //Copy the locations of the pieces
      b.Set(p->GetSquare(),true);
    }
  );
  return b;
}

bool ribi::Chess::Board::IsCheck(const Player player) const
{
  const bool verbose{false};
  //Find the king of the player
  const auto king_ptr = std::find_if(
    m_pieces.begin(),m_pieces.end(),
    [player,this](const ribi::Chess::Board::PiecePtr& p)
    {
      return p->GetColor() == player
        && dynamic_cast<PieceKing*>(p.get());
    }
  );
  //No King, so this player cannot be in check
  if (king_ptr == m_pieces.end())
  {
    if (verbose) { TRACE("No king"); }
    return false;
  }

  const PiecePtr king = *king_ptr;
  assert(king);

  //Collect the visible squares seen from the opponent
  //DO NOT USE GETVISIBLESQUARES: THIS LEADS TO RECURSION

  //Check if an opponent's piece looks at the current player's King
  const int cnt = std::count_if(m_pieces.begin(),m_pieces.end(),
    [king,this](const ribi::Chess::Board::PiecePtr& p)
    {
      assert(p);
      //Must not be of same color
      if (p->GetColor() == king->GetColor()) return false;
      //There must be a Move to the King's square
      const auto moves = p->GetMoves();
      const auto move = std::find_if(moves.begin(),moves.end(),
        [king](const boost::shared_ptr<Move> m)
        {
          return *m->To() == *king->GetSquare();
        }
      );
      if (move == moves.end()) return false;
      //A Knight always makes a successful attack
      if (dynamic_cast<PieceKnight*>(p.get())) return true;
      //All squares between King and attacker must be empty
      assert(king->GetSquare());
      assert(p->GetSquare());
      return EmptyBetween(king->GetSquare(),p->GetSquare());
    }
  );

  //Return if there is at least one piece attacking the King
  return cnt > 0;
}

bool ribi::Chess::Board::IsCheckmate(const Player player) const
{
  const bool verbose{false};
  if (!IsCheck(player))
  {
    if (verbose) { TRACE("Move is no checkmate, because the king is not in check"); }
    return false;
  }

  //Find the king of the player
  const auto king_ptr = std::find_if(
    m_pieces.begin(),m_pieces.end(),
    [player,this](const ribi::Chess::Board::PiecePtr& p)
    {
      return p->GetColor() == player
        && dynamic_cast<PieceKing*>(p.get());
    }
  );
  //No King, so this player cannot be in check
  if (king_ptr == m_pieces.end())
  {
    TRACE("No king");
    return false;
  }

  //Get all moves
  const std::vector<boost::shared_ptr<Move>> moves = GetMoves(player);

  //Check if all of them end in check
  const int cnt = std::count_if(moves.begin(),moves.end(),
    [this,player](const boost::shared_ptr<Move> move)
    {
      boost::shared_ptr<Board> b(BoardFactory().DeepCopy(*this));
      assert(move);
      assert(b->CanDoMove(move,player));
      //if (!b.CanDoMove(move,player)) return false;
      b->DoMove(move,player);
      if (b->IsCheck(player)) return false;
      return true;
    }
  );

  //If there are no possible moves, player is in checkmate
  if (cnt > 0)
  {
    if (verbose) { TRACE("Opponent can escape checkmate"); }
  }
  return cnt == 0;
}

/*
bool ribi::Chess::Board::IsValid(const boost::shared_ptr<Move> move) const
{
  assert(move->To());
  //Check if non-Knight Piece does not go through occupied squares
  if (move->Piece() && !dynamic_cast<PieceKnight*>(move->Piece().get())
    && ( std::abs(move->To()->GetFile().ToInt() - move->From()->GetFile().ToInt()) > 1
      || std::abs(move->To()->GetRank().ToInt() - move->From()->GetRank().ToInt()) > 1)
    )
  {
    const int dx = move->To()->GetFile().ToInt() - move->From()->GetFile().ToInt();
    const int dy = move->To()->GetRank().ToInt() - move->From()->GetRank().ToInt();
    const int step_x = (dx > 0 ? 1 : (dx < 0 ? -1 : 0));
    const int step_y = (dy > 0 ? 1 : (dy < 0 ? -1 : 0));
    const int n_steps = std::max(std::abs(dx),std::abs(dy));
    for (int i=1; i!=n_steps; ++i)
    {
      const int x = move->From()->GetFile().ToInt() + (i * step_x);
      const int y = move->From()->GetRank().ToInt() + (i * step_y);
      if (GetPiece(Square(File(x),Rank(y)))) return false;
    }
  }
  //If the move is a capture, but there is nothing to capture, the move is invalid in this context
  if (move->IsCapture() && !GetPiece(*move->To())) return false;
  //If the square to move to is occupied...
  if (GetPiece(*move->To()))
  {
    //Cannot capture a piece of own color
    ///TODO But this is possible in Cannibal Chess
    //if (GetPiece(*move->To())->GetColor() == GetActivePlayer()) return false;

    if (GetPiece(*move->From())->GetColor() != GetPiece(*move->To())->GetColor()) return move->IsCapture();
  }
  //move->IsCapture
  //move->IsCastling()

  //Does move result in the player ending in check?
  return true;
}
*/

bool ribi::Chess::AreEqual(const ribi::Chess::Board::ConstPieces& lhs,const ribi::Chess::Board::ConstPieces& rhs)
{
  if (lhs.size() != rhs.size()) return false;
  //Count unfound pieces
  return std::count_if(lhs.begin(),lhs.end(),
    [rhs](const ribi::Chess::Board::ConstPiecePtr& p)
    {
      assert(std::count_if(rhs.begin(),rhs.end(),
        [p](const ribi::Chess::Board::ConstPiecePtr& q)
        {
          return *p == *q;
        }
      ) < 2);

      return std::count_if(rhs.begin(),rhs.end(),
        [p](const ribi::Chess::Board::ConstPiecePtr& q)
        {
          return *p == *q;
        }
      ) == 1;
    }
  ) == static_cast<int>(lhs.size());
}


std::ostream& ribi::Chess::operator<<(std::ostream& os, const Board& board)
{
  const int maxx = 8;
  const int maxy = 8;

  boost::multi_array<std::string, 2> v(boost::extents[maxx][maxy]);
  for (int y=0;y!=maxy;++y)
  {
    for (int x=0; x!=maxx; ++x)
    {
      if (((x+y)%2)==0)
      {
        v[x][y] = "..";
      }
      else
      {
        v[x][y] = "__";
      }
    }
  }
  std::for_each(board.m_pieces.begin(),board.m_pieces.end(),
    [&v](const ribi::Chess::Board::PiecePtr& piece)
    {
      assert(piece);
      assert(piece->GetSquare());
      const int x = piece->GetSquare()->GetFile().ToInt();
      const int y = piece->GetSquare()->GetRank().ToInt();
      const std::string s
        = piece->GetColor() == Color::white ? "w" : "b"
        + boost::lexical_cast<std::string>(piece->GetNameChar());
      v[x][y] = s;
    }
  );

  for (int y=0;y!=maxy;++y)
  {
    for (int x=0; x!=maxx; ++x)
    {
      os << " " << v[x][y];
    }
    os << "\n";
  }

  return os;
}

bool ribi::Chess::operator==(const Board& lhs, const Board& rhs)
{
  //if (lhs.GetMoveHistory() != rhs.GetMoveHistory())
  //{
  //  return false;
  //}
  return AreEqual(lhs.GetPieces(),rhs.GetPieces());
}

bool ribi::Chess::operator!=(const Board& lhs, const Board& rhs)
{
  return !(lhs == rhs);
}

 

 

 

 

 

./CppChess/chessboardfactory.h

 

#ifndef RIBI_CHESSBOARDFACTORY_H
#define RIBI_CHESSBOARDFACTORY_H

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#include <boost/shared_ptr.hpp>

#include "chessfwd.h"
#include "chessboard.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace Chess {

///Factory for creating a Chess::Board
struct BoardFactory
{
  BoardFactory();

  boost::shared_ptr<Chess::Board> Create(
    const Chess::Board::Pieces& pieces = Chess::Board::GetInitialSetup()
  ) const;


  boost::shared_ptr<Chess::Board> DeepCopy(const Board& board) const;

  private:
  #ifndef NDEBUG
  static void Test() noexcept;
  #endif
};

} //~namespace Chess
} //~namespace ribi

#endif // RIBI_CHESSBOARDFACTORY_H

 

 

 

 

 

./CppChess/chessboardfactory.cpp

 

#include "chessboardfactory.h"

#include <algorithm>
#include <cassert>
#include <numeric>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include <boost/make_shared.hpp>
#include "chessboard.h"
#include "chesspiecefactory.h"
#pragma GCC diagnostic pop

#include "testtimer.h"

ribi::Chess::BoardFactory::BoardFactory()
{
  #ifndef NDEBUG
  Test();
  #endif
}


boost::shared_ptr<ribi::Chess::Board> ribi::Chess::BoardFactory::Create(const Chess::Board::Pieces& pieces) const
{
  const boost::shared_ptr<Chess::Board> p
    = boost::make_shared<Chess::Board>(pieces);
  assert(p);
  return p;
}

boost::shared_ptr<ribi::Chess::Board> ribi::Chess::BoardFactory::DeepCopy(const Board& board) const
{
  const Chess::Board::ConstPieces original = board.GetPieces();
  Chess::Board::Pieces pieces;
  std::transform(original.begin(),original.end(),
    std::inserter(pieces,pieces.begin()),
    [](const Chess::Board::ConstPiecePtr& piece)
    {
      assert(piece);
      Chess::Board::PiecePtr p = PieceFactory().DeepCopy(piece);
      assert(p);
      return p;
    }
  );
  boost::shared_ptr<Board> b(Create(pieces));
  assert(b);
  return b;
}

#ifndef NDEBUG
void ribi::Chess::BoardFactory::Test() noexcept
{
  {
    static bool is_tested = false;
    if (is_tested) return;
    is_tested = true;
  }
  {
    BoardFactory().Create();
  }
  const ribi::TestTimer test_timer(__func__,__FILE__,1.0);
}
#endif

 

 

 

 

 

./CppChess/chessboardtest.cpp

 

#include "chessboard.h"

#include <algorithm>
#include <cassert>

#include "chessboardfactory.h"
#include "chessbitboard.h"
#include "chessmoves.h"
#include "chessmovefactory.h"
#include "chesspiece.h"
#include "chesspiecefactory.h"
#include "chessplayer.h"
#include "chesssquarefactory.h"
#include "chessscore.h"
#include "testtimer.h"
#include "trace.h"

#ifndef NDEBUG
void ribi::Chess::Board::Test() noexcept
{
  //Testing boost::shared_ptr<Chess::Board> exactly once
  {
    static bool tested = false;
    if (tested) return;
    tested = true;
  }
  const TestTimer test_timer(__func__,__FILE__,1.0);
  const bool verbose{false};
  {
    if (verbose) { TRACE("Test Chess::Board"); }
    //Chess::Bitribi::Chess::Board::Test();
    //Chess::Move::Test();
    #ifdef FIX_ISSUE_240
    {
      if (verbose) { TRACE("Test Board operator="); }
      const boost::shared_ptr<Chess::Board> b(BoardFactory().Create());
      assert(b);
      boost::shared_ptr<Chess::Board> c(BoardFactory().DeepCopy(*b));
      assert(c);
      assert(*b == *c);
      c->DoMove(MoveFactory().Create("e2 e4"),Player::white);
      assert(*b != *c);
      const boost::shared_ptr<Chess::Board> d(c);
      assert(*c == *d);
      assert(*b != *d);
    }
    {
      if (verbose) { TRACE("Test Board operator== with fresh boards"); }
      const boost::shared_ptr<Chess::Board> b(BoardFactory().Create());
      boost::shared_ptr<Chess::Board> c(BoardFactory().Create());
      assert((*b == *c));
      c->DoMove(MoveFactory().Create("e2 e4"),Player::white);
      assert((*b != *c));
      const boost::shared_ptr<Chess::Board> d(c);
      assert((*c == *d));
      assert((*b != *d));
    }

    {
      if (verbose) { TRACE("Test Board operator== with fresh boards"); }
      const boost::shared_ptr<Chess::Board> b(BoardFactory().Create());
      boost::shared_ptr<Chess::Board> c(BoardFactory().Create());
      assert((*b == *c));
      c->DoMove(MoveFactory().Create("e2 e4"),Player::white);
      assert((*b != *c));
      const boost::shared_ptr<Chess::Board> d(c);
      assert((*c == *d));
      assert((*b != *d));
    }
    {
      if (verbose) { TRACE("Test GetMoves from initial position squares"); }
      boost::shared_ptr<Chess::Board> b(BoardFactory().Create());
      assert(!b->CanDoMove(MoveFactory().Create("Ra8 a6"),Player::black));
      assert(!b->CanDoMove(MoveFactory().Create("Ra8 a6"),Player::white));
      assert(b->GetMoves(SquareFactory().Create("a1")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("b1")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("c1")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("d1")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("e1")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("f1")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("g1")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("h1")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("a2")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("b2")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("c2")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("d2")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("e2")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("f2")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("g2")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("h2")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("a8")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("b8")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("c8")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("d8")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("e8")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("f8")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("g8")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("h8")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("a7")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("b7")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("c7")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("d7")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("e7")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("f7")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("g7")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("h7")).size() == 2);
    }
    {
      if (verbose) { TRACE("Test GetVisibleSquares in the initial position"); }
      boost::shared_ptr<Chess::Board> b(BoardFactory().Create());
      const BitBoard c = b->GetVisibleSquares(Player::white);

      assert(c.Get(SquareFactory().Create("a1"))); assert(c.Get(SquareFactory().Create("a2"))); assert(c.Get(SquareFactory().Create("a3"))); assert(c.Get(SquareFactory().Create("a4")));
      assert(c.Get(SquareFactory().Create("b1"))); assert(c.Get(SquareFactory().Create("b2"))); assert(c.Get(SquareFactory().Create("b3"))); assert(c.Get(SquareFactory().Create("b4")));
      assert(c.Get(SquareFactory().Create("c1"))); assert(c.Get(SquareFactory().Create("c2"))); assert(c.Get(SquareFactory().Create("c3"))); assert(c.Get(SquareFactory().Create("c4")));
      assert(c.Get(SquareFactory().Create("d1"))); assert(c.Get(SquareFactory().Create("d2"))); assert(c.Get(SquareFactory().Create("d3"))); assert(c.Get(SquareFactory().Create("d4")));
      assert(c.Get(SquareFactory().Create("e1"))); assert(c.Get(SquareFactory().Create("e2"))); assert(c.Get(SquareFactory().Create("e3"))); assert(c.Get(SquareFactory().Create("e4")));
      assert(c.Get(SquareFactory().Create("f1"))); assert(c.Get(SquareFactory().Create("f2"))); assert(c.Get(SquareFactory().Create("f3"))); assert(c.Get(SquareFactory().Create("f4")));
      assert(c.Get(SquareFactory().Create("g1"))); assert(c.Get(SquareFactory().Create("g2"))); assert(c.Get(SquareFactory().Create("g3"))); assert(c.Get(SquareFactory().Create("g4")));
      assert(c.Get(SquareFactory().Create("h1"))); assert(c.Get(SquareFactory().Create("h2"))); assert(c.Get(SquareFactory().Create("h3"))); assert(c.Get(SquareFactory().Create("h4")));
      assert(!c.Get(SquareFactory().Create("a5"))); assert(!c.Get(SquareFactory().Create("a6"))); assert(!c.Get(SquareFactory().Create("a7"))); assert(!c.Get(SquareFactory().Create("a8")));
      assert(!c.Get(SquareFactory().Create("b5"))); assert(!c.Get(SquareFactory().Create("b6"))); assert(!c.Get(SquareFactory().Create("b7"))); assert(!c.Get(SquareFactory().Create("b8")));
      assert(!c.Get(SquareFactory().Create("c5"))); assert(!c.Get(SquareFactory().Create("c6"))); assert(!c.Get(SquareFactory().Create("c7"))); assert(!c.Get(SquareFactory().Create("c8")));
      assert(!c.Get(SquareFactory().Create("d5"))); assert(!c.Get(SquareFactory().Create("d6"))); assert(!c.Get(SquareFactory().Create("d7"))); assert(!c.Get(SquareFactory().Create("d8")));
      assert(!c.Get(SquareFactory().Create("e5"))); assert(!c.Get(SquareFactory().Create("e6"))); assert(!c.Get(SquareFactory().Create("e7"))); assert(!c.Get(SquareFactory().Create("e8")));
      assert(!c.Get(SquareFactory().Create("f5"))); assert(!c.Get(SquareFactory().Create("f6"))); assert(!c.Get(SquareFactory().Create("f7"))); assert(!c.Get(SquareFactory().Create("f8")));
      assert(!c.Get(SquareFactory().Create("g5"))); assert(!c.Get(SquareFactory().Create("g6"))); assert(!c.Get(SquareFactory().Create("g7"))); assert(!c.Get(SquareFactory().Create("g8")));
      assert(!c.Get(SquareFactory().Create("h5"))); assert(!c.Get(SquareFactory().Create("h6"))); assert(!c.Get(SquareFactory().Create("h7"))); assert(!c.Get(SquareFactory().Create("h8")));
      b->DoMove(MoveFactory().Create("e2 e3"),Player::white);
      const BitBoard d = b->GetVisibleSquares(Player::black);
      assert(d.Get(SquareFactory().Create("a5"))); assert(d.Get(SquareFactory().Create("a6"))); assert(d.Get(SquareFactory().Create("a7"))); assert(d.Get(SquareFactory().Create("a8")));
      assert(d.Get(SquareFactory().Create("b5"))); assert(d.Get(SquareFactory().Create("b6"))); assert(d.Get(SquareFactory().Create("b7"))); assert(d.Get(SquareFactory().Create("b8")));
      assert(d.Get(SquareFactory().Create("c5"))); assert(d.Get(SquareFactory().Create("c6"))); assert(d.Get(SquareFactory().Create("c7"))); assert(d.Get(SquareFactory().Create("c8")));
      assert(d.Get(SquareFactory().Create("d5"))); assert(d.Get(SquareFactory().Create("d6"))); assert(d.Get(SquareFactory().Create("d7"))); assert(d.Get(SquareFactory().Create("d8")));
      assert(d.Get(SquareFactory().Create("e5"))); assert(d.Get(SquareFactory().Create("e6"))); assert(d.Get(SquareFactory().Create("e7"))); assert(d.Get(SquareFactory().Create("e8")));
      assert(d.Get(SquareFactory().Create("f5"))); assert(d.Get(SquareFactory().Create("f6"))); assert(d.Get(SquareFactory().Create("f7"))); assert(d.Get(SquareFactory().Create("f8")));
      assert(d.Get(SquareFactory().Create("g5"))); assert(d.Get(SquareFactory().Create("g6"))); assert(d.Get(SquareFactory().Create("g7"))); assert(d.Get(SquareFactory().Create("g8")));
      assert(d.Get(SquareFactory().Create("h5"))); assert(d.Get(SquareFactory().Create("h6"))); assert(d.Get(SquareFactory().Create("h7"))); assert(d.Get(SquareFactory().Create("h8")));
      assert(!d.Get(SquareFactory().Create("a1"))); assert(!d.Get(SquareFactory().Create("a2"))); assert(!d.Get(SquareFactory().Create("a3"))); assert(!d.Get(SquareFactory().Create("a4")));
      assert(!d.Get(SquareFactory().Create("b1"))); assert(!d.Get(SquareFactory().Create("b2"))); assert(!d.Get(SquareFactory().Create("b3"))); assert(!d.Get(SquareFactory().Create("b4")));
      assert(!d.Get(SquareFactory().Create("c1"))); assert(!d.Get(SquareFactory().Create("c2"))); assert(!d.Get(SquareFactory().Create("c3"))); assert(!d.Get(SquareFactory().Create("c4")));
      assert(!d.Get(SquareFactory().Create("d1"))); assert(!d.Get(SquareFactory().Create("d2"))); assert(!d.Get(SquareFactory().Create("d3"))); assert(!d.Get(SquareFactory().Create("d4")));
      assert(!d.Get(SquareFactory().Create("e1"))); assert(!d.Get(SquareFactory().Create("e2"))); assert(!d.Get(SquareFactory().Create("e3"))); assert(!d.Get(SquareFactory().Create("e4")));
      assert(!d.Get(SquareFactory().Create("f1"))); assert(!d.Get(SquareFactory().Create("f2"))); assert(!d.Get(SquareFactory().Create("f3"))); assert(!d.Get(SquareFactory().Create("f4")));
      assert(!d.Get(SquareFactory().Create("g1"))); assert(!d.Get(SquareFactory().Create("g2"))); assert(!d.Get(SquareFactory().Create("g3"))); assert(!d.Get(SquareFactory().Create("g4")));
      assert(!d.Get(SquareFactory().Create("h1"))); assert(!d.Get(SquareFactory().Create("h2"))); assert(!d.Get(SquareFactory().Create("h3"))); assert(!d.Get(SquareFactory().Create("h4")));
    }

    {
      if (verbose) { TRACE("Test valid moves in the initial position"); }
      boost::shared_ptr<Chess::Board> b(BoardFactory().Create());
      {
        const std::vector<std::string> v
        =
        {
          "a2 a3", "a2 a4", "b2 b3", "b2 b4",
          "c2 c3", "c2 c4", "d2 d3", "d2 d4",
          "e2 e3", "e2 e4", "f2 f3", "f2 f4",
          "g2 g3", "g2 g4", "h2 h3", "h2 h4",
          "Nb1 a3", "Nb1 c3", "Ng1 f3", "Ng1 h3",
          "1-0", "0-1", "1/2-1/2"
        };
        std::for_each(v.begin(),v.end(),
          [b](const std::string& s)
          {
            if (!b->CanDoMove(Chess::MoveFactory().Create(s),Player::white)) { TRACE(s); }
            assert(b->CanDoMove(Chess::MoveFactory().Create(s),Player::white));
          }
        );
      }
      assert(b->GetMoves(SquareFactory().Create("a1")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("b1")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("c1")).size() == 0);
      assert(!b->CanDoMove(MoveFactory().Create("Qd1 d8"),Player::white));
      assert(!b->CanDoMove(MoveFactory().Create("Qd1 d7"),Player::white));
      assert(b->GetMoves(SquareFactory().Create("d1")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("e1")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("f1")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("g1")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("h1")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("a2")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("b2")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("c2")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("d2")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("e2")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("f2")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("g2")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("h2")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("a8")).size() == 0);
      /*
      assert(b->GetMoves(SquareFactory().Create("b8")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("c8")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("d8")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("e8")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("f8")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("g8")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("h8")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("a7")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("b7")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("c7")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("d7")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("e7")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("f7")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("g7")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("h7")).size() == 0);
      */
      assert(b->GetMoves(Player::white).size() == 20);

      assert(!b->IsCheck(Player::white));
      assert(!b->IsCheckmate(Player::white));
    }

    {
      if (verbose) { TRACE("Test moves in the initial position (short notation)"); }
      boost::shared_ptr<Chess::Board> b(BoardFactory().Create());
      {
        const std::vector<std::string> v
        =
        {
          "a3", "a4", "b3", "b4",
          "c3", "c4", "d3", "d4",
          "e3", "e4", "f3", "f4",
          "g3", "g4", "h3", "h4",
          "Na3", "Nc3", "Nf3", "Nh3"
        };
        std::for_each(v.begin(),v.end(),
          [b](const std::string& s)
          {
            if (!b->CanDoMove(Chess::MoveFactory().Create(s),Player::white)) { TRACE(s); }
            assert(b->CanDoMove(Chess::MoveFactory().Create(s),Player::white));
          }
        );
      }
    }

    {
      if (verbose) { TRACE("Test a Pawn on the board at e2"); }
      const ribi::Chess::Board::Pieces v =
      {
        PieceFactory().Create('.',Color::white,"e2"),
        PieceFactory().Create('.',Color::white,"d3"),
        PieceFactory().Create('.',Color::black,"f3")
      };
      boost::shared_ptr<Board> b(BoardFactory().Create(v));
      assert( b->CanDoMove(MoveFactory().Create("e2 e3"),Player::white));
      assert( b->CanDoMove(MoveFactory().Create("e2 e4"),Player::white));
      assert( b->CanDoMove(MoveFactory().Create("e2xf3"),Player::white));
      assert(!b->CanDoMove(MoveFactory().Create("e2xd3"),Player::white));
    }

    {
      if (verbose) { TRACE("Test a Pawn on the board at e2, blocked by an opponent"); }
      const ribi::Chess::Board::Pieces v =
      {
        PieceFactory().Create('.',Color::white,"e2"),
        PieceFactory().Create('.',Color::black,"e3")
      };
      boost::shared_ptr<Board> b(BoardFactory().Create(v));
      assert(!b->CanDoMove(MoveFactory().Create("e2 e3"),Player::white));
      assert(!b->CanDoMove(MoveFactory().Create("e2 e4"),Player::white));
    }

    {
      if (verbose) { TRACE("Test a Pawn on the board at h4, blocked by an opponent"); }
      const ribi::Chess::Board::Pieces v =
      {
        PieceFactory().Create('.',Color::white,"h4"),
        PieceFactory().Create('.',Color::black,"h5")
      };
      boost::shared_ptr<Board> b(BoardFactory().Create(v));
      assert(!b->CanDoMove(MoveFactory().Create("h4 h5"),Player::white));
    }

    {
      if (verbose) { TRACE("Test a Knight on the board at d4"); }
      const ribi::Chess::Board::Pieces v =
      {
        PieceFactory().Create('N',Color::white,"d4"),
        PieceFactory().Create('.',Color::white,"c6"),
        PieceFactory().Create('.',Color::black,"e6")
      };
      boost::shared_ptr<Board> b(BoardFactory().Create(v));
      assert( b->CanDoMove(MoveFactory().Create("Nd4 b5"),Player::white));
      assert( b->CanDoMove(MoveFactory().Create("Nd4 f5"),Player::white));
      assert(!b->CanDoMove(MoveFactory().Create("Nd4xc6"),Player::white));
      assert( b->CanDoMove(MoveFactory().Create("Nd4xe6"),Player::white));
    }


    {
      if (verbose) { TRACE("Test valid moves for black after 1. e2 e4"); }
      boost::shared_ptr<Chess::Board> b(BoardFactory().Create());
      b->DoMove(MoveFactory().Create("e2 e4"),Player::white);
      {
        const std::vector<std::string> v
        =
        {
          "a7 a6", "a7 a5", "b7 b6", "b7 b5",
          "c7 c6", "c7 c5", "d7 d6", "d7 d5",
          "e7 e6", "e7 e5", "f7 f6", "f7 f5",
          "g7 g6", "g7 g5", "h7 h6", "h7 h5",
          "Nb8 a6", "Nb8 c6", "Ng8 f6", "Ng8 h6",
          "1-0", "0-1", "1/2-1/2"
        };
        std::for_each(v.begin(),v.end(),
          [b](const std::string& s)
          {
            if (!b->CanDoMove(Chess::MoveFactory().Create(s),Player::black)) { TRACE(s); }
            assert(b->CanDoMove(Chess::MoveFactory().Create(s),Player::black));
          }
        );
      }
      assert(b->GetMoves(SquareFactory().Create("a8")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("b8")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("c8")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("d8")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("e8")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("f8")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("g8")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("h8")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("a7")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("b7")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("c7")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("d7")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("e7")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("f7")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("g7")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("h7")).size() == 2);
      assert(b->GetMoves(Player::black).size() == 20);
      assert(!b->IsCheck(Player::black));
      assert(!b->IsCheckmate(Player::black));
    }

    {
      if (verbose) { TRACE("Test valid moves for white after 1. e2 e4 e7 e5"); }
      boost::shared_ptr<Chess::Board> b(BoardFactory().Create());
      b->DoMove(MoveFactory().Create("e2 e4"),Player::white);
      b->DoMove(MoveFactory().Create("e7 e5"),Player::black);
      {
        const std::vector<std::string> v
        =
        {
          "a2 a3", "a2 a4", "b2 b3", "b2 b4",
          "c2 c3", "c2 c4", "d2 d3", "d2 d4",
          "Ke1 e2","f2 f3", "f2 f4",
          "g2 g3", "g2 g4", "h2 h3", "h2 h4",
          "Nb1 a3", "Nb1 c3", "Ng1 f3", "Ng1 h3",
          "Bf1 e2", "Bf1 d3", "Bf1 c4", "Bf1 b5", "Bf1 a6",
          "Qd1 e2", "Qd1 f3", "Qd1 g4", "Qd1 h5",
          "1-0", "0-1", "1/2-1/2"
        };
        std::for_each(v.begin(),v.end(),
          [b](const std::string& s)
          {
            if (!b->CanDoMove(Chess::MoveFactory().Create(s),Player::white)) { TRACE(s); }
            assert(b->CanDoMove(Chess::MoveFactory().Create(s),Player::white));
          }
        );
      }
      assert(b->GetMoves(SquareFactory().Create("a1")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("b1")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("c1")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("d1")).size() == 4);
      assert(b->GetMoves(SquareFactory().Create("e1")).size() == 1);
      assert(b->GetMoves(SquareFactory().Create("f1")).size() == 5);
      assert(b->GetMoves(SquareFactory().Create("g1")).size() == 3);
      assert(b->GetMoves(SquareFactory().Create("h1")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("a2")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("b2")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("c2")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("d2")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("e4")).size() == 0);
      assert(b->GetMoves(SquareFactory().Create("f2")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("g2")).size() == 2);
      assert(b->GetMoves(SquareFactory().Create("h2")).size() == 2);
      assert(b->GetMoves(Player::white).size() == 29);
      assert(!b->IsCheck(Player::white));
      assert(!b->IsCheckmate(Player::white));
    }

    {
      if (verbose) { TRACE("Test Board copy constructor"); }
      boost::shared_ptr<Chess::Board> b(BoardFactory().Create());
      assert( b->GetPiece(SquareFactory().Create("e2")));
      assert(!b->GetPiece(SquareFactory().Create("e4")));
      b->DoMove(MoveFactory().Create("e2 e4"),Player::white);
      const boost::shared_ptr<Chess::Board> c(b);
      assert(*b == *c);
      assert(!b->GetPiece(SquareFactory().Create("e2")));
      assert( b->GetPiece(SquareFactory().Create("e4")));
      assert(!c->GetPiece(SquareFactory().Create("e2")));
      assert( c->GetPiece(SquareFactory().Create("e4")));
      b->DoMove(MoveFactory().Create("e7 e5"),Player::black);
      assert(*b != *c);
      assert( b->GetPiece(SquareFactory().Create("e5")));
      assert(!b->GetPiece(SquareFactory().Create("e7")));
      assert(!c->GetPiece(SquareFactory().Create("e5")));
      assert( c->GetPiece(SquareFactory().Create("e7")));
    }
    {
      if (verbose) { TRACE("Test EmptyBetween on single piece"); }
      const Pieces pieces
        =
        {
          PieceFactory().Create('K',Color::white,"b2")
        };
      boost::shared_ptr<Chess::Board> b(BoardFactory().Create(pieces));
      assert( b->EmptyBetween(SquareFactory().Create("a1"),SquareFactory().Create("c1")));
      assert( b->EmptyBetween(SquareFactory().Create("c1"),SquareFactory().Create("a1")));
      assert( b->EmptyBetween(SquareFactory().Create("a1"),SquareFactory().Create("a3")));
      assert( b->EmptyBetween(SquareFactory().Create("a3"),SquareFactory().Create("a1")));
      assert(!b->EmptyBetween(SquareFactory().Create("a1"),SquareFactory().Create("c3")));
      assert(!b->EmptyBetween(SquareFactory().Create("c3"),SquareFactory().Create("a1")));
      assert(!b->EmptyBetween(SquareFactory().Create("b1"),SquareFactory().Create("b3")));
      assert(!b->EmptyBetween(SquareFactory().Create("b3"),SquareFactory().Create("b1")));
      assert(!b->EmptyBetween(SquareFactory().Create("a2"),SquareFactory().Create("c2")));
      assert(!b->EmptyBetween(SquareFactory().Create("c2"),SquareFactory().Create("a2")));
      assert( b->EmptyBetween(SquareFactory().Create("d1"),SquareFactory().Create("d8")));
      assert( b->EmptyBetween(SquareFactory().Create("d8"),SquareFactory().Create("d1")));
      assert( b->EmptyBetween(SquareFactory().Create("a4"),SquareFactory().Create("h4")));
      assert( b->EmptyBetween(SquareFactory().Create("h4"),SquareFactory().Create("a4")));
      assert( b->EmptyBetween(SquareFactory().Create("b5"),SquareFactory().Create("f1")));
      assert( b->EmptyBetween(SquareFactory().Create("f1"),SquareFactory().Create("b5")));
    }

    {
      if (verbose) { TRACE("Test EmptyBetween after 3rd move of white in Kasparov against the World game"); }
      const Pieces pieces
        =
        {

          PieceFactory().Create('R',Color::white,"a1"),
          PieceFactory().Create('N',Color::white,"c3"),
          PieceFactory().Create('B',Color::white,"c1"),
          PieceFactory().Create('Q',Color::white,"d1"),
          PieceFactory().Create('K',Color::white,"e1"),
          PieceFactory().Create('B',Color::white,"b5"),
          PieceFactory().Create('N',Color::white,"g1"),
          PieceFactory().Create('R',Color::white,"h1"),
          PieceFactory().Create('.',Color::white,"a2"),
          PieceFactory().Create('.',Color::white,"b2"),
          PieceFactory().Create('.',Color::white,"c2"),
          PieceFactory().Create('.',Color::white,"d2"),
          PieceFactory().Create('.',Color::white,"e4"),
          PieceFactory().Create('.',Color::white,"f2"),
          PieceFactory().Create('.',Color::white,"g2"),
          PieceFactory().Create('.',Color::white,"h2"),
          PieceFactory().Create('R',Color::black,"a8"),
          PieceFactory().Create('N',Color::black,"b8"),
          PieceFactory().Create('B',Color::black,"c8"),
          PieceFactory().Create('Q',Color::black,"d8"),
          PieceFactory().Create('K',Color::black,"e8"),
          PieceFactory().Create('B',Color::black,"f8"),
          PieceFactory().Create('N',Color::black,"g8"),
          PieceFactory().Create('R',Color::black,"h8"),
          PieceFactory().Create('.',Color::black,"a7"),
          PieceFactory().Create('.',Color::black,"b7"),
          PieceFactory().Create('.',Color::black,"c5"),
          PieceFactory().Create('.',Color::black,"d6"),
          PieceFactory().Create('.',Color::black,"e7"),
          PieceFactory().Create('.',Color::black,"f7"),
          PieceFactory().Create('.',Color::black,"g7"),
          PieceFactory().Create('.',Color::black,"h7")
        };
      boost::shared_ptr<Chess::Board> b(BoardFactory().Create(pieces));
      assert( b->EmptyBetween(SquareFactory().Create("b5"),SquareFactory().Create("e8")));
      assert( b->EmptyBetween(SquareFactory().Create("e8"),SquareFactory().Create("b5")));
      assert( b->EmptyBetween(SquareFactory().Create("b5"),SquareFactory().Create("f1")));
      assert( b->EmptyBetween(SquareFactory().Create("f1"),SquareFactory().Create("b5")));
    }

    {
      if (verbose) { TRACE("Test IsCheck from setup 1"); }
      const Pieces pieces
        =
        {
          PieceFactory().Create('K',Color::white,"a1"),
          PieceFactory().Create('K',Color::black,"h8"),
          PieceFactory().Create('R',Color::white,"a8"),
          PieceFactory().Create('R',Color::black,"h1")
        };
      boost::shared_ptr<Chess::Board> b(BoardFactory().Create(pieces));
      assert(b->IsCheck(Player::white));
      assert(b->IsCheck(Player::black));
    }
    {
      if (verbose) { TRACE("Test IsCheck by playing"); }
      boost::shared_ptr<Chess::Board> b(BoardFactory().Create());
      b->DoMove(MoveFactory().Create("e2 e4"),Player::white);
      b->DoMove(MoveFactory().Create("d7 d6"),Player::black);
      if (verbose) { TRACE("Test that the move ending is check can be done"); }
      assert(b->CanDoMove(MoveFactory().Create("Bf1 b5+"),Player::white));
      if (verbose) { TRACE("Do the move ending is check"); }
      b->DoMove(MoveFactory().Create("Bf1 b5+"),Player::white);
      if (verbose) { TRACE("Test that the board detects check"); }
      assert(b->IsCheck(Player::black));
    }


    {
      if (verbose) { TRACE("Test invalid moves in the initial position"); }
      boost::shared_ptr<Chess::Board> b(BoardFactory().Create());
      {
        const std::vector<std::string> v
        =
        {
          "a7 a6", "a7 a5", "b7 b5", "b7 b5",
          "c7 c6", "c7 c5", "d7 d5", "d7 d5",
          "e7 e6", "e7 e5", "f7 f5", "f7 f5",
          "g7 g6", "g7 g5", "h7 h5", "h7 h5",
          "Nb8 a6", "Nb8 c6", "Ng8 f6", "Ng8 h6",
          "a2xa3", "a2 a4+", "b2 b3#", "b2xb4",
          "c2 c3+", "c2 c4#", "d2 d3e.p.", "d2xd4e.p.",
          "0-0", "0-0-0", "O-O", "O-O-O",
          "0-0+", "0-0-0+", "O-O+", "O-O-O+",
          "0-0#", "0-0-0#", "O-O#", "O-O-O#",
        };
        std::for_each(v.begin(),v.end(),
          [b](const std::string& s)
          {
            try
            {
              const boost::shared_ptr<const Move> move { MoveFactory().Create(s) };
              if (b->CanDoMove(Chess::MoveFactory().Create(s),Player::white)) { TRACE(s); }
              assert(!b->CanDoMove(Chess::MoveFactory().Create(s),Player::white));
            }
            catch (std::exception& e)
            {
              //OK
            }
          }
        );
      }
    }

    /*
    {
      if (verbose) { TRACE("Test Fools mate"); }
      boost::shared_ptr<Chess::Board> b;
      {
        const std::vector<std::string> v = Moves::GetGameFoolsMate();
        std::for_each(v.begin(),v.end(),
          [b](const std::string& s)
          {
            if (!b->CanDoMove(s) { TRACE(s); }
            assert(b->CanDoMove(s));
            b->DoMove(s);
          }
        );
        assert(b.Score());
        assert(b.Score().IsWhiteWinner());
      }
    }
    */

    {
      if (verbose) { TRACE("Test Shephards mate"); }
      boost::shared_ptr<Chess::Board> b(BoardFactory().Create());
      Player player = Player::white;
      {
        const std::vector<std::string> v = Moves::GetGameShephardsMate();
        std::for_each(v.begin(),v.end(),
          [&b,&player](const std::string& s)
          {
            if (!b->CanDoMove(Chess::MoveFactory().Create(s),player)) { TRACE(s); }
            assert(b->CanDoMove(Chess::MoveFactory().Create(s),player));
            b->DoMove(MoveFactory().Create(s),player);
            player = (player == Player::white ? Player::black : Player::white);
          }
        );
      }
    }

    {
      if (verbose) { TRACE("Test Kasparov Versus The World match"); }
      boost::shared_ptr<Chess::Board> b(BoardFactory().Create());
      Player player = Player::white;
      {
        const std::vector<std::string> v = Moves::GetGameKasparovVersusTheWorld();
        const std::size_t sz = v.size();
        for (std::size_t i = 0; i!=sz; ++i)
        {
          const std::string s = v[i];
          TRACE(b);
          if (!b->CanDoMove(Chess::MoveFactory().Create(s),player)) { TRACE(s);  }
          assert(b->CanDoMove(Chess::MoveFactory().Create(s),player));
          b->DoMove(MoveFactory().Create(s),player);
          player = (player == Player::white ? Player::black : Player::white);
        }
      }
    }
    #endif // FIX_ISSUE_240
  }
}
#endif

 

 

 

 

 

./CppChess/chessboardwidget.h

 

#ifndef RIBI_CHESSBOARDWIDGET_H
#define RIBI_CHESSBOARDWIDGET_H

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#include <boost/shared_ptr.hpp>

#include "chessfwd.h"
#include "chessplayer.h"
#include "chesswidget.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace Chess {

///Chess::BoardWidget is a Chess::Widget to interact with a Chess::Board
struct BoardWidget : public Chess::ChessWidget
{
  BoardWidget(boost::shared_ptr<Chess::Board> board, const Rect& geometry);

  ///Can do a move?
  bool CanDoMove(
    const boost::shared_ptr<const Chess::Square> from,
    const boost::shared_ptr<const Chess::Square> to) const noexcept;
  //bool CanDoMove(const Chess::Move& move) const;

  ///Can the square be selected?
  bool CanSelect(const boost::shared_ptr<const Chess::Square> square) const noexcept;

  ///Respond to a click
  void Click(const boost::shared_ptr<const Chess::Square> square) noexcept;

  ///Do a move
  void DoMove(const boost::shared_ptr<const Chess::Square> from, const boost::shared_ptr<const Chess::Square> to);

  ///Get which Player is active
  Player GetActivePlayer() const { return m_player; }

  ///Get the Chess::Board this Chess::Widget works on
  const boost::shared_ptr<Chess::Board> GetBoard() const { return m_board; }

  ///Set which Player is active
  void SetActivePlayer(const Player player);

  ///Test this class
  static void Test() noexcept;

  private:

  ~BoardWidget() noexcept {}

  ///The chessboard
  boost::shared_ptr<Chess::Board> m_board;

  ///The active Player
  Player m_player;

  friend void boost::checked_delete<>(BoardWidget* x);
  friend void boost::checked_delete<>(const BoardWidget* x);
  friend class boost::detail::sp_ms_deleter<      BoardWidget>;
  friend class boost::detail::sp_ms_deleter<const BoardWidget>;
};

} //~namespace Chess
} //~namespace ribi

#endif // RIBI_CHESSBOARDWIDGET_H

 

 

 

 

 

./CppChess/chessboardwidget.cpp

 

#include "chessboardwidget.h"

#include <cassert>
#include <exception>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include <boost/lexical_cast.hpp>

#include "chessboard.h"
#include "chessboardfactory.h"
#include "chesspiece.h"
#include "chessplayer.h"
#include "chesssquarefactory.h"
#include "chesssquareselector.h"
#include "chessmovefactory.h"
#include "chesswidget.h"
#include "geometry.h"
#include "trace.h"
#pragma GCC diagnostic pop

//ribi::Chess::BoardWidget::BoardWidget()
//  : Chess::Widget(Rect(0,0,0,0))
//{
//  assert(!"Should not call this function");
//  throw std::logic_error("Must not call ribi::Chess::BoardWidget::BoardWidget()");
//}

ribi::Chess::BoardWidget::BoardWidget(boost::shared_ptr<Chess::Board> board,const Rect& geometry)
  : Chess::ChessWidget(geometry),
    m_board(board),
    m_player(Player::white)
{
  #ifndef NDEBUG
  ribi::Chess::BoardWidget::Test();
  #endif
}

bool ribi::Chess::BoardWidget::CanDoMove(
  const boost::shared_ptr<const Chess::Square> from,
  const boost::shared_ptr<const Chess::Square> to) const noexcept
{
  const boost::shared_ptr<Move> move {
    MoveFactory().Create(from,to)
  };
  //A Widget can do a move if it is valid for one of the two players
  return this->GetBoard()->CanDoMove(move,Chess::Player::white)
    || this->GetBoard()->CanDoMove(move,Chess::Player::black);
}

bool ribi::Chess::BoardWidget::CanSelect(
  const boost::shared_ptr<const Chess::Square> square) const noexcept
{
  //A BoardWidget can always select a Piece
  return this->GetBoard()->GetPiece(square).get();
    //&& this->GetBoard()->GetPiece(square)->GetColor()
    //  == this->GetActivePlayer();
}

void ribi::Chess::BoardWidget::Click(const boost::shared_ptr<const Chess::Square> square) noexcept
{

  m_selector->Click(square,this->CanSelect(square));

  //Moves will only occur when there is both a cursor and a selected square
  if (!m_selector->GetSelected()) return;

  //Construct all possible Moves
  assert(m_selector->GetSelected());
  const Chess::Board::PiecePtr piece = m_board->GetPiece(m_selector->GetSelected());
  TRACE(square->ToStr());
  #ifndef NDEBUG
  if (!piece)
  {
    TRACE(m_selector->GetSelected()->ToStr());
    TRACE(square);
    std::clog << *this->GetBoard() << '\n';
  }
  #endif
  assert(piece);
  boost::shared_ptr<const Move> move;
  for (int i=0; i!=32; ++i)
  {
    std::string s
      = boost::lexical_cast<std::string>(piece->GetNameChar())
      + m_selector->GetSelected()->ToStr()
      + ( (i / 1) % 2 ? " " : "x")
      + m_selector->GetCursor()->ToStr();
    switch ( (i / 2) % 4)
    {
      case 0: s += "e.p."; break;
      case 1: s += "+"; break;
      case 2: s += "#"; break;
      case 3: break;
      default: break;
    }
    try
    {
      const boost::shared_ptr<const Move> maybe_move {
        MoveFactory().Create(s)
      };
      if (this->CanDoMove(maybe_move->From(),maybe_move->To())) move = maybe_move;
    }
    catch (std::exception& e)
    {
      //No problem
    }
  }
  if (!move) return;
  assert(m_board->CanDoMove(move,m_player));
  m_board->DoMove(move,m_player);

  m_signal_graphic_changed();
}


void ribi::Chess::BoardWidget::DoMove(
  const boost::shared_ptr<const Square>,
  const boost::shared_ptr<const Square>)
{
  assert(!"TODO");
}


void ribi::Chess::BoardWidget::SetActivePlayer(const Player player)
{
  if (player != m_player)
  {
    m_player = player;
    m_selector.reset(new SquareSelector);
  }
}

void ribi::Chess::BoardWidget::Test() noexcept
{
  //Testing Chess::Piece exactly once
  {
    static bool tested = false;
    if (tested) return;
    tested = true;
  }
  {
    const auto board(BoardFactory().Create());
    //boost::shared_ptr<Chess::BoardWidget> w
    //  = boost::make_shared<Chess::BoardWidget>(board,Geometry().CreateRect(0.0,0.0,100.0,100.0));
    auto w(boost::make_shared<Chess::BoardWidget>(board,Geometry().CreateRect(0.0,0.0,100.0,100.0)));
    w->ClickPixel(-1,-1);
    w->ClickPixel(1000,1000);
  }
  #ifdef FIX_ISSUE_240
  {
    const Rect geometry(Geometry().CreateRect(0,0,100,100));
    const auto board(BoardFactory().Create());
    //boost::shared_ptr<Chess::BoardWidget> widget
    //  = boost::make_shared<Chess::BoardWidget>(board,geometry);
    auto widget(boost::make_shared<Chess::BoardWidget>(board,geometry));

    //assert(widget->GetSelector()->GetCursor() == Chess::SquareSelector::GetInitialSquare());
    assert(widget->GetSelector()->GetCursor()->GetFile() == Chess::SquareSelector::GetInitialSquare()->GetFile());
    assert(widget->GetSelector()->GetCursor()->GetRank() == Chess::SquareSelector::GetInitialSquare()->GetRank());
    //assert(widget->GetSelector()->GetCursor()->GetFile() == Chess::File("a"));
    //assert(widget->GetSelector()->GetCursor()->GetRank() == Chess::Rank("1"));
    assert(!widget->GetSelector()->GetSelected());
    //Check clicking: cursor will always follow
    for (int x=0;x!=8;++x)
    {
      for (int y=0;y!=8;++y)
      {
        const boost::shared_ptr<const Square> square {
          SquareFactory().Create(File(x),Rank(y))
        };
        widget->Click(square);
        assert(*widget->GetSelector()->GetCursor() == *SquareFactory().Create(File(x),Rank(y)));
      }
    }
    //Check selection: Board::Widget will select any Chess::Piece, Board::Game only those of the active player
    //Click on own piece, selecting it
    widget->Click(SquareFactory().Create("b1"));
    assert(*widget->GetSelector()->GetCursor() == *SquareFactory().Create("b1"));
    assert(widget->GetSelector()->GetSelected());
    assert(*widget->GetSelector()->GetSelected() == *SquareFactory().Create("b1"));

    //Click on empty square, selection is removed
    widget->Click(SquareFactory().Create("d4"));
    assert(*widget->GetSelector()->GetCursor() == *SquareFactory().Create("d4"));
    assert(!widget->GetSelector()->GetSelected());
    //assert(*widget->GetSelector()->GetSelected() == Chess::Square("b1"));

    //Click on own piece again, selecting it
    widget->Click(SquareFactory().Create("b1"));
    assert(*widget->GetSelector()->GetCursor() == *SquareFactory().Create("b1"));
    assert(widget->GetSelector()->GetSelected());
    assert(*widget->GetSelector()->GetSelected() == *SquareFactory().Create("b1"));

    //Click on selected square, undoing selection
    widget->Click(SquareFactory().Create("b1"));
    assert(*widget->GetSelector()->GetCursor() == *SquareFactory().Create("b1"));
    assert(!widget->GetSelector()->GetSelected());

    //Click on square with black piece. Note: a Widget can select every piece
    widget->Click(SquareFactory().Create("h8"));
    assert(*widget->GetSelector()->GetCursor() == *SquareFactory().Create("h8"));
    assert( widget->GetSelector()->GetSelected());
    assert(*widget->GetSelector()->GetSelected() == *SquareFactory().Create("h8"));

    //Playing e7-e5 must succeed for a Board, must fail for a Game
    assert( board->GetPiece(SquareFactory().Create("e7")));
    assert(!board->GetPiece(SquareFactory().Create("e5")));
    widget->Click(SquareFactory().Create("e7"));
    assert(*widget->GetSelector()->GetCursor() == *SquareFactory().Create("e7"));
    assert(widget->GetSelector()->GetSelected());
    assert(*widget->GetSelector()->GetSelected() == *SquareFactory().Create("e7"));

    widget->Click(SquareFactory().Create("e5"));
    assert(*widget->GetSelector()->GetCursor() == *SquareFactory().Create("e5"));
    assert(!widget->GetSelector()->GetSelected());
    assert(!board->GetPiece(SquareFactory().Create("e7")));
    assert( board->GetPiece(SquareFactory().Create("e5")));

    //Playing e2-e4 must succeed for both Board and Game
    assert( board->GetPiece(SquareFactory().Create("e2")));
    assert(!board->GetPiece(SquareFactory().Create("e4")));
    widget->Click(SquareFactory().Create("e2"));
    assert(*widget->GetSelector()->GetCursor() == *SquareFactory().Create("e2"));
    assert(widget->GetSelector()->GetSelected());
    assert(*widget->GetSelector()->GetSelected() == *SquareFactory().Create("e2"));

    widget->Click(SquareFactory().Create("e4"));
    assert(*widget->GetSelector()->GetCursor() == *SquareFactory().Create("e4"));
    assert(!widget->GetSelector()->GetSelected());
    assert(!board->GetPiece(SquareFactory().Create("e2")));
    assert( board->GetPiece(SquareFactory().Create("e4")));
  }
  #endif //FIX_ISSUE_240
}

 

 

 

 

 

./CppChess/chesscastling.h

 

#ifndef RIBI_CHESSCASTLING_H
#define RIBI_CHESSCASTLING_H

#include <iosfwd>
#include <vector>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#include <boost/xpressive/xpressive.hpp>

#include "chessfwd.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace Chess {

enum class Castling { kingside, queenside };

std::string CastlingToStr(const Castling castling);
bool CanStrToCastling(const std::string& s);
const boost::xpressive::sregex GetCastlingRegex();
//const Square GetCastlingKingSquare(const Castling castling, const Player player);
//const Square GetCastlingRookSquare(const Castling castling, const Player player);
Castling StrToCastling(const std::string& s);

} //~namespace Chess
} //~namespace ribi

#endif // RIBI_CHESSCASTLING_H

 

 

 

 

 

./CppChess/chesscastling.cpp

 


#include <cassert>

#include <exception>

#include "chesscastling.h"
#include "trace.h"

bool ribi::Chess::CanStrToCastling(const std::string& s)
{
  return boost::xpressive::regex_match(s,GetCastlingRegex());
}

std::string ribi::Chess::CastlingToStr(const Castling castling)
{
  switch (castling)
  {
    case Castling::kingside: return "O-O";
    case Castling::queenside: return "O-O-O";
  }
  assert(!"Should not get here");
  throw std::logic_error("Unknown Castling");
}

const boost::xpressive::sregex ribi::Chess::GetCastlingRegex()
{
  static const boost::xpressive::sregex r {
    boost::xpressive::sregex::compile("(0|O)-(0|O)(-(0|O))?(\\+|\\#)?")
  };
  return r;
}

ribi::Chess::Castling ribi::Chess::StrToCastling(const std::string& s)
{
  assert(CanStrToCastling(s));
  if (s.substr(0,3) == "O-O"   || s.substr(0,3) == "0-0"  ) return Castling::kingside;
  if (s.substr(0,5) == "O-O-O" || s.substr(0,5) == "0-0-0") return Castling::queenside;
  #ifndef NDEBUG
  TRACE(s);
  #endif
  assert(!"Cannot convert std::string to Castling");
  throw std::logic_error("Cannot convert std::string to Castling");
}

 

 

 

 

 

./CppChess/chesscolor.h

 

#ifndef RIBI_CHESSCOLOR_H
#define RIBI_CHESSCOLOR_H

#include <iosfwd>
#include <string>
#include <vector>

#include "chessfwd.h"
#include "chessplayer.h"

namespace ribi {
namespace Chess {

enum class Color
{
  black, white, indeterminate, red, green, blue
};

struct ColorVersion
{
  ///Obtain the version of this class
  static std::string GetVersion();

  ///Obtain the version history of this class
  static std::vector<std::string> GetVersionHistory();
};

std::string ColorToStr(const Color c);
Player ColorToPlayer(const Color c);
std::ostream& operator<<(std::ostream& os, const Color c);

bool operator==(const Color color, const Player player);
bool operator==(const Player player, const Color color);
bool operator!=(const Color color, const Player player);
bool operator!=(const Player player, const Color color);

} //~namespace Chess
} //~namespace ribi

#endif // RIBI_CHESSCOLOR_H

 

 

 

 

 

./CppChess/chesscolor.cpp

 


#include <cassert>
#include <iostream>
#include <stdexcept>

#include "chesscolor.h"
#include "chessplayer.h"
#include "trace.h"

std::string ribi::Chess::ColorToStr(const Color c)
{
  switch (c)
  {
    case Color::black        : return "black";
    case Color::indeterminate: return "indeterminate";
    case Color::white        : return "white";
    case Color::red          : return "red";
    case Color::green        : return "green";
    case Color::blue         : return "blue";
  }
  assert(!"Should not get here");
  throw std::logic_error("Chess::ColorToStr: unimplemented Color");
}

ribi::Chess::Player ribi::Chess::ColorToPlayer(const Color c)
{
  switch (c)
  {
    case Color::white: return Player::white;
    case Color::black: return Player::black;
    default: break;
  }
  #ifndef NDEBUG
  TRACE(c);
  #endif
  assert(!"Cannot convert color to player");
  throw std::logic_error("Cannot convert color to player");
}

std::string ribi::Chess::ColorVersion::GetVersion()
{
  return "1.1";
}

std::vector<std::string> ribi::Chess::ColorVersion::GetVersionHistory()
{
  return {
    "2012-01-25: version 1.0: initial version",
    "2012-02-07: version 1.1: added colors red, green and blue for selection"
  };
}

std::ostream& ribi::Chess::operator<<(std::ostream& os, const Color c)
{
  os << ColorToStr(c);
  return os;
}

bool ribi::Chess::operator==(const Color color, const Player player)
{
  switch (player)
  {
    case Player::black: return color == Color::black;
    case Player::white: return color == Color::white;
  }
  return false;
}

bool ribi::Chess::operator==(const Player player, const Color color)
{
  return color == player;
}

bool ribi::Chess::operator!=(const Color color, const Player player)
{
  return !(color == player);
}

bool ribi::Chess::operator!=(const Player player, const Color color)
{
  return !(color == player);
}

 

 

 

 

 

./CppChess/chessfile.h

 

#ifndef RIBI_CHESSFILE_H
#define RIBI_CHESSFILE_H

#include <string>
#include <vector>

namespace ribi {
namespace Chess {

///A File is the x-coordinat on a Board
struct File
{
  ///Create a file from its single-character string, e.g. "b" for file b
  explicit File(const std::string& x);

  ///Create a file from its x-coordinat, e.g. 1 for file b
  explicit File(const int x);

  ///Obtain the version of this class
  static std::string GetVersion();

  ///Obtain the version history of this class
  static std::vector<std::string> GetVersionHistory();

  ///Test this class
  static void Test() noexcept;

  ///Convert a File to its single-character string.
  ///For example, file "a" has x-coordinat 0
  const std::string& ToStr() const { return m_s; }

  ///Convert a File to its x-coordinat.
  ///For example, file 'a' has x-coordinat 0
  int ToInt() const;

  //Increment file, e.g. from 'a' to'b'
  //File& operator++();

  //Decrement file, e.g. from 'b' to'a'
  //File& operator--();

  private:
  const std::string m_s;

  ///Convert 0 to 'a', 1 to 'b', etc...
  static std::string IntToCharToStr(const int x);
};

bool operator==(const File& lhs, const File& rhs);

} //~namespace Chess
} //~namespace ribi

#endif // RIBI_CHESSFILE_H

 

 

 

 

 

./CppChess/chessfile.cpp

 

#include "chessfile.h"

#include <algorithm>
#include <cassert>
#include <stdexcept>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include <boost/lexical_cast.hpp>

#include "testtimer.h"
#include "trace.h"
#pragma GCC diagnostic pop

ribi::Chess::File::File(const std::string& s)
  : m_s(s)
{
  #ifndef NDEBUG
  Test();
  #endif
  if (m_s.empty()) throw std::logic_error("Chess files cannot be empty");
  if (m_s.size() != 1) throw std::logic_error("Chess files consist of exactly one character");
  const char c = m_s[0];
  if (c < 'a' || c > 'h') throw std::logic_error("Chess files go from a to and including h");
  assert(c >= 'a');
  assert(c <= 'h');
}

ribi::Chess::File::File(const int x)
  : m_s(IntToCharToStr(x))
{
  #ifndef NDEBUG
  Test();
  #endif
  if (x < 0 || x > 7) throw std::logic_error("X coordinats go from 0 to and including 7");

  #ifndef NDEBUG
  const char c = m_s[0];
  assert(m_s.size() == 1);
  assert(c >= 'a');
  assert(c <= 'h');
  #endif
}

std::string ribi::Chess::File::GetVersion()
{
  return "1.0";
}

std::vector<std::string> ribi::Chess::File::GetVersionHistory()
{
  return {
    "2012-01-25: version 1.0: initial version"
  };
}

std::string ribi::Chess::File::IntToCharToStr(const int x)
{
  char c = 'a' + x;
  return boost::lexical_cast<std::string>(c);
}

void ribi::Chess::File::Test() noexcept
{
  {
    static bool tested = false;
    if (tested) return;
    tested = true;
  }
  const TestTimer test_timer(__func__,__FILE__,1.0);
  const bool verbose{false};
    {
      if (verbose) { TRACE("Test Chess::File"); }

      if (verbose) { TRACE("Test valid Files from std::string"); }
      {
        const std::vector<std::string> v = {"a","b","c","d","e","f","g","h"};
        std::for_each(v.begin(),v.end(),[](const std::string& s) { Chess::File tmp(s); } );
      }
      if (verbose) { TRACE("Test valid Files from int"); }
      {
        const std::vector<int> v = {0,1,2,3,4,5,6,7};
        std::for_each(v.begin(),v.end(),[](const int& i) { File tmp(i); } );
      }
      if (verbose) { TRACE("Test invalid Files from std::string"); }
      {
        const std::vector<std::string> v = {"A","i"," ","H","I","1","7","aa","1a","a1" };
        std::for_each(v.begin(),v.end(),
          [](const std::string& s)
          {
            try
            {
              File tmp(s);
              TRACE(s);
              assert(!"Should not get here");
            }
            catch (std::exception& e)
            {
              //OK!
            }
          }
        );
      }
      if (verbose) { TRACE("Test invalid Files from int"); }
      {
        const std::vector<int> v = {-1,8,10,11,100,111};
        std::for_each(v.begin(),v.end(),
          [](const int& i)
          {
            try
            {
              File tmp(i);
              TRACE(i);
              assert(!"Should not get here");
            }
            catch (std::exception& e)
            {
              //OK!
            }
          }
        );
      }
      if (verbose) { TRACE("Test individual files intimately"); }
      {
        File f("a");
        assert(f.ToStr() == "a");
        assert(f.ToInt() == 0);
      }
      {
        File f("h");
        assert(f.ToStr() == "h");
        assert(f.ToInt() == 7);
      }
      {
        File f(0);
        assert(f.ToStr() == "a");
        assert(f.ToInt() == 0);
      }
      {
        File f(7);
        assert(f.ToStr() == "h");
        assert(f.ToInt() == 7);
      }
    }
}

int ribi::Chess::File::ToInt() const
{
  const char c = m_s[0];
  assert(c >= 'a');
  assert(c <= 'h');

  const int value = c - 'a';
  assert(value >= 0);
  assert(value < 8);
  return value;
}

bool ribi::Chess::operator==(const File& lhs, const File& rhs)
{
  return lhs.ToStr() == rhs.ToStr();
}

 

 

 

 

 

./CppChess/chessfwd.h

 

#ifndef RIBI_CHESSFWD_H
#define RIBI_CHESSFWD_H

///Contains the CppChess forward declarations
namespace ribi {
namespace Chess {

struct BitBoard;
struct Board;
struct BoardFactory;
struct BoardWidget;
//enum class Castling;
//enum class Color;
struct File;
struct Game;
struct GameWidget;
struct Move;
struct MoveFactory;
struct Piece;
struct PieceBishop;
struct PieceFactory;
struct PieceKing;
struct PieceKnight;
struct PiecePawn;
struct PieceQueen;
struct PieceRook;
//enum class Player;
struct Rank;
struct Score;
struct Square;
struct SquareFactory;
struct SquareSelector;

} //~namespace Chess

struct Widget;

} //~namespace ribi

#endif // RIBI_CHESSFWD_H

 

 

 

 

 

./CppChess/chessgame.h

 

#ifndef RIBI_CHESSGAME_H
#define RIBI_CHESSGAME_H

#include <iosfwd>
//#include <set>
#include <vector>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#include <boost/logic/tribool.hpp>
#include <boost/shared_ptr.hpp>

#include "chessfwd.h"
#include "chesscolor.h"
#include "chessmove.h"
//#include "chesspiece.h"
#pragma GCC diagnostic pop

namespace ribi {

namespace Chess {

struct Piece;

///Chess::Board is a class for a chessboard without gaming rules.
///Rules that handled by Chess::Board normally are:
/// - en passant
/// - castling
///Chess::Game is the class that uses a Chess::Board and adds these rules
///Rules that must be handled by Chess::Game are:
/// - keeping track of which player's turn it is
/// - determining a winner or draw
struct Game
{
  typedef boost::shared_ptr<Piece> PiecePtr;
  typedef std::vector<PiecePtr> Pieces;

  ///Construct a Game in the initial position
  Game();

  ///Copy a Game
  //Game(const Game& other);

  ///Check if a Move is valid to play in the current context
  bool CanDoMove(const boost::shared_ptr<const Move> move) const;

  ///Check if this game can be played
  static bool CanDoGame(const std::vector<std::string>& moves);
  static int CanDoGameUntil(const std::vector<std::string>& moves);

  ///Do a Move that is valid to play in the current context
  void DoMove(const boost::shared_ptr<const Move> move);

  //bool IsVisible(const Square& s);

  //const GameVisibleType GetInSight(const Piece::Color color) const;
  //const Piece GetPiece(const int x, const int y) const;

  ///Whose turn is it?
  Player GetActivePlayer() const;

  ///Get the Chess::Board used for the Game
  const boost::shared_ptr<Chess::Board> GetBoard() const { return m_board; }

  ///Collect all moves that are possible for a Piece at a certain Square.
  ///If there is no Piece at that Square, no Moves are returned
  const std::vector<boost::shared_ptr<Move>> GetMoves(const boost::shared_ptr<const Square> square) const;

  ///Collect all moves that are possible
  const std::vector<boost::shared_ptr<Move>> GetMoves() const;

  ///Find a Piece at a certain Square.
  ///If there is no Piece at that Square, an empty Piece is returned
  const PiecePtr GetPiece(const boost::shared_ptr<const Square> square) const;

  ///Obtain the version of this class
  static std::string GetVersion();

  ///Obtain the version history of this class
  static std::vector<std::string> GetVersionHistory();

  ///Get all squares that are visible by a player with the requested color.
  ///If the Color is set to Color::indeterminate, both players' sights
  ///are returned
  const BitBoard GetVisibleSquares() const;

  ///Is, in the current position, the active player being in check?
  bool IsCheck() const;

  ///Is the current position the active player being in checkmate?
  bool IsCheckmate() const;

  ///The Score if the game has ended by agreement (instead of by checkmate)
  const boost::shared_ptr<Chess::Score>& Score() const;


  #ifndef NDEBUG
  ///Tests the Game class
  static void Test() noexcept;
  #endif

  private:
  ///The Chess::Board used for the Game
  const boost::shared_ptr<Chess::Board> m_board;

  std::vector<boost::shared_ptr<const Chess::Move>> m_moves;

  ///The Score if the game has ended by agreement (instead of by checkmate)
  boost::shared_ptr<Chess::Score> m_score;

  friend bool operator==(const Game& lhs, const Game& rhs);
};

bool operator==(const Game& lhs, const Game& rhs);
bool operator!=(const Game& lhs, const Game& rhs);

} //~namespace Chess
} //~namespace ribi

#endif // RIBI_CHESSGAME_H

 

 

 

 

 

./CppChess/chessgame.cpp

 

#include "chessgame.h"

#include <algorithm>
#include <cassert>
#include <iostream>
#include <stdexcept>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include "chessbitboard.h"
#include "chessboard.h"
#include "chessboardfactory.h"
#include "chesssquarefactory.h"
#include "chessfile.h"
#include "chessmove.h"
#include "chessmovefactory.h"
#include "chesspiece.h"
#include "chessplayer.h"
#include "chessrank.h"
#include "chessscore.h"
#include "chesssquare.h"
#include "testtimer.h"
#include "trace.h"
#pragma GCC diagnostic pop

ribi::Chess::Game::Game()
  : m_board(BoardFactory().Create()),
    m_moves{},
    m_score{}
{
  #ifndef NDEBUG
  Test();
  #endif
}

/*
ribi::Chess::Game::Game(const Game& other)
  : m_moves(other.m_moves)
{
  TRACE_FUNC();
  //Copy all Pieces
  //m_pieces = other.m_pieces;
  std::for_each(other.m_pieces.begin(), other.m_pieces.end(),
    [&m_pieces](const PiecePtr& p)
    {
      PiecePtr q(p->Clone());
      m_pieces.push_back(q);
    }
  );

  ///Copy the Score if the game has ended by agreement (instead of by checkmate)
  if (other.Score()) m_score.reset(new Chess::Score(*other.Score().get()));

  assert(*this == other);
}
*/

bool ribi::Chess::Game::CanDoGame(const std::vector<std::string>& moves)
{
  const int n_moves = static_cast<int>(moves.size());
  return CanDoGameUntil(moves) == n_moves;
}

int ribi::Chess::Game::CanDoGameUntil(const std::vector<std::string>& moves)
{
  Chess::Game game;
  const int n_moves = static_cast<int>(moves.size());
  for (int i=0; i!=n_moves; ++i)
  {
    const std::string s = moves[i];
    if (!game.CanDoMove(MoveFactory().Create(s))) return i;
    game.DoMove(Chess::MoveFactory().Create(s));
  }
  return n_moves;
}

bool ribi::Chess::Game::CanDoMove(const boost::shared_ptr<const Move> move) const
{
  return m_board->CanDoMove(move,GetActivePlayer());
}

void ribi::Chess::Game::DoMove(const boost::shared_ptr<const Move> move)
{
  //assert(CanDoMove(move));
  assert(!m_score);
  m_moves.push_back(move);
  if (move->From())
  {
    PiecePtr p = GetPiece(move->From());
    assert(p);
    assert(p->CanDoMove(move));
    p->DoMove(move);
  }
  else if (move->Score())
  {
    m_score = move->Score();
  }
}

const ribi::Chess::Game::PiecePtr ribi::Chess::Game::GetPiece(const boost::shared_ptr<const Square> square) const
{
  return m_board->GetPiece(square);
}

ribi::Chess::Player ribi::Chess::Game::GetActivePlayer() const
{
  return m_moves.size() % 2 ? Player::black : Player::white;
}

const std::vector<boost::shared_ptr<ribi::Chess::Move>> ribi::Chess::Game::GetMoves() const
{
  return m_board->GetMoves(GetActivePlayer());
}

const std::vector<boost::shared_ptr<ribi::Chess::Move>> ribi::Chess::Game::GetMoves(const boost::shared_ptr<const Square> square) const
{
  return m_board->GetMoves(square);
}

std::string ribi::Chess::Game::GetVersion()
{
  return "0.1";
}

std::vector<std::string> ribi::Chess::Game::GetVersionHistory()
{
  return {
    "2012-06-16: version 0.1: initial seperation from Chess::Board"
  };
}

const ribi::Chess::BitBoard ribi::Chess::Game::GetVisibleSquares() const
{
  return m_board->GetVisibleSquares(GetActivePlayer());
}

bool ribi::Chess::Game::IsCheck() const
{
  return m_board->IsCheck(GetActivePlayer());
}

bool ribi::Chess::Game::IsCheckmate() const
{
  ///TODO
  return IsCheck();
}

const boost::shared_ptr<ribi::Chess::Score>& ribi::Chess::Game::Score() const
{
  return m_score;
}

#ifndef NDEBUG
void ribi::Chess::Game::Test() noexcept
{
  {
    static bool is_tested = false;
    if (is_tested) return;
    is_tested = true;
  }
  {
    Chess::File(0);
    Chess::Rank(3);
    Chess::SquareFactory();
    Chess::Score("1-0");
    Chess::MoveFactory();
    Chess::BoardFactory();
  }
  const TestTimer test_timer(__func__,__FILE__,1.0);
  const bool verbose{false};
  {
    if (verbose) { TRACE("Testing Game"); }
    Chess::Game();
  }
}
#endif

bool ribi::Chess::operator==(const Game& lhs, const Game& rhs)
{
  if (!lhs.Score() &&  rhs.Score()) return false;
  if ( lhs.Score() && !rhs.Score()) return false;
  if ( lhs.Score() &&  rhs.Score())
  {
    if (*lhs.Score() != *rhs.Score()) return false;
  }
  return *lhs.m_board == *rhs.m_board;
}

bool ribi::Chess::operator!=(const Game& lhs, const Game& rhs)
{
  return !(lhs == rhs);
}

 

 

 

 

 

./CppChess/chessgamewidget.h

 

#ifndef RIBI_CHESSGAMEWIDGET_H
#define RIBI_CHESSGAMEWIDGET_H

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#include <boost/shared_ptr.hpp>

#include "chessfwd.h"
#include "chesswidget.h"
#pragma GCC diagnostic pop

namespace ribi {

namespace Chess {

///Chess::GameWidget is a Chess::Widget to interact with a Chess::Game
struct GameWidget : public Chess::ChessWidget
{
  GameWidget(boost::shared_ptr<Chess::Game> game, const Rect& geometry);

  ///Can do a move?
  bool CanDoMove(
    const boost::shared_ptr<const Square> from,
    const boost::shared_ptr<const Square> to
  ) const noexcept;

  ///Respond to a click
  void Click(const boost::shared_ptr<const Square> square);

  ///Do a move
  void DoMove(
    const boost::shared_ptr<const Square> from,
    const boost::shared_ptr<const Square> to
  );

  ///Get the Chess::Board this Chess::Widget works on
  const boost::shared_ptr<Chess::Game> GetGame() const { return m_game; }

  ///Test this class
  static void Test() noexcept;

  private:
  ~GameWidget() noexcept {}

  ///The chessboard
  boost::shared_ptr<Chess::Game> m_game;

  friend void boost::checked_delete<>(GameWidget* x);
};

} //~ namespace Chess
} //~ namespace ribi

#endif // RIBI_CHESSGAMEWIDGET_H

 

 

 

 

 

./CppChess/chessgamewidget.cpp

 

#include "chessgamewidget.h"

#include <cassert>
#include <string>

#include "chessboard.h"
#include "chessgame.h"
#include "chesspiece.h"
#include "chesssquarefactory.h"
#include "chesssquareselector.h"
#include "chessmovefactory.h"
#include "geometry.h"
#include "testtimer.h"

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include <boost/lexical_cast.hpp>
#include <boost/make_shared.hpp>
#pragma GCC diagnostic pop

//ribi::Chess::GameWidget::GameWidget()
//  : Chess::Widget(Rect(0,0,0,0))
//{
//  assert(!"Should not call this function");
//  throw std::logic_error("Must not call ribi::Chess::GameWidget::GameWidget()");
//}

ribi::Chess::GameWidget::GameWidget(boost::shared_ptr<Chess::Game> game, const Rect& geometry)
  : ChessWidget(geometry), m_game(game)
{
  #ifndef NDEBUG
  ribi::Chess::GameWidget::Test();
  #endif
}

void ribi::Chess::GameWidget::Click(const boost::shared_ptr<const Square> square)
{
  m_selector->Click(square,this); //BUG ?

  //Moves will only occur when there is both a cursor and a selected square
  if (!m_selector->GetSelected()) return;

  const boost::shared_ptr<const ribi::Chess::Square> from {
    m_selector->GetSelected()
  };
  const boost::shared_ptr<const ribi::Chess::Square> to {
    m_selector->GetCursor()
  };

  if (this->CanDoMove(from,to))
  {
    DoMove(from,to);
  }
}

bool ribi::Chess::GameWidget::CanDoMove(
  const boost::shared_ptr<const Square> from,
  const boost::shared_ptr<const Square> to) const noexcept
{
  //Construct all possible Moves
  assert(m_selector->GetSelected());
  const Chess::Board::PiecePtr piece = m_game->GetBoard()->GetPiece(from);
  assert(piece);
  boost::shared_ptr<const Move> move;
  for (int i=0; i!=32; ++i)
  {
    std::string s
      = boost::lexical_cast<std::string>(piece->GetNameChar())
      + from->ToStr()
      + ( (i / 1) % 2 ? " " : "x")
      + to->ToStr();
    switch ( (i / 2) % 4)
    {
      case 0: s += "e.p."; break;
      case 1: s += "+"; break;
      case 2: s += "#"; break;
      case 3: break;
      default: break;
    }
    const boost::shared_ptr<const Move> maybe_move {
      MoveFactory().Create(s)
    };
    if (m_game->CanDoMove(maybe_move)) move = maybe_move;
  }
  if (!move) return false;
  return true;
}

void ribi::Chess::GameWidget::DoMove(
  const boost::shared_ptr<const Square> from,
  const boost::shared_ptr<const Square> to)
{
  assert(CanDoMove(from,to));

  //Construct all possible Moves
  const Chess::Board::PiecePtr piece = m_game->GetBoard()->GetPiece(from);
  assert(piece);
  boost::shared_ptr<const Move> move;
  for (int i=0; i!=32; ++i)
  {
    std::string s
      = boost::lexical_cast<std::string>(piece->GetNameChar())
      + from->ToStr()
      + ( (i / 1) % 2 ? " " : "x")
      + to->ToStr();
    switch ( (i / 2) % 4)
    {
      case 0: s += "e.p."; break;
      case 1: s += "+"; break;
      case 2: s += "#"; break;
      case 3: break;
      default: break;
    }

    const boost::shared_ptr<const Move> maybe_move {
      MoveFactory().Create(s)
    };
    if (m_game->CanDoMove(maybe_move)) move = maybe_move;
    if (move) break;
  }
  assert(move);

  m_game->DoMove(move);

  m_signal_graphic_changed();

}

void ribi::Chess::GameWidget::Test() noexcept
{
  //Testing Chess::Piece exactly once
  {
    static bool is_tested = false;
    if (is_tested) return;
    is_tested = true;
  }
  const ribi::TestTimer test_timer(__func__,__FILE__,1.0);
  #ifdef FIX_ISSUE_240
  {
    {
      const boost::shared_ptr<Chess::Game> game
        = boost::make_shared<Chess::Game>();
      const boost::shared_ptr<Chess::ChessWidget> w(
        new GameWidget(game,Geometry().CreateRect(0,0,100,100)));
      w->ClickPixel(-1,-1);
      w->ClickPixel(1000,1000);
    }
    {
      const boost::shared_ptr<Chess::Game> game
        = boost::make_shared<Chess::Game>();
      const boost::shared_ptr<Chess::GameWidget> widget(
        new Chess::GameWidget(game,Geometry().CreateRect(0,0,100,100)));
      assert(widget->GetSelector()->GetCursor()->GetFile() == Chess::File("a"));
      assert(widget->GetSelector()->GetCursor()->GetRank() == Chess::Rank("1"));
      assert(!widget->GetSelector()->GetSelected());
      //Check clicking: cursor will always follow
      for (int x=0;x!=8;++x)
      {
        for (int y=0;y!=8;++y)
        {
          const boost::shared_ptr<Square> square {
            SquareFactory().Create(
              File(x),Rank(y)
            )
          };
          widget->Click(square);
          assert(*widget->GetSelector()->GetCursor() == *square);
        }
      }
      //Check selection: Board::Widget will select any Chess::Piece, Board::Game only those of the active player
      //Click on own piece, selecting it
      {
        const boost::shared_ptr<Square> square {
          SquareFactory().Create("b1")
        };
        widget->Click(square);
      }
      assert(*widget->GetSelector()->GetCursor() == *SquareFactory().Create("b1"));
      assert(widget->GetSelector()->GetSelected());
      assert(*widget->GetSelector()->GetSelected() == *SquareFactory().Create("b1"));

      //Click on empty square, selected piece remains
      widget->Click(SquareFactory().Create("d4"));
      assert(*widget->GetSelector()->GetCursor() == *SquareFactory().Create("d4"));
      assert(widget->GetSelector()->GetSelected());
      assert(*widget->GetSelector()->GetSelected() == *SquareFactory().Create("b1"));

      //Click on selected square, undoing selection
      widget->Click(SquareFactory().Create("b1"));
      assert(*widget->GetSelector()->GetCursor() == *SquareFactory().Create("b1"));
      assert(!widget->GetSelector()->GetSelected());

      //Click on enemy square, Chess::Board will select it
      widget->Click(SquareFactory().Create("h8"));
      assert(*widget->GetSelector()->GetCursor() == *SquareFactory().Create("g8"));
      assert(!widget->GetSelector()->GetSelected());

      //Playing e7-e5 must succeed for a Board, must fail for a Game
      assert( game->GetBoard()->GetPiece(SquareFactory().Create("e7")));
      assert(!game->GetBoard()->GetPiece(SquareFactory().Create("e5")));
      widget->Click(SquareFactory().Create("e7"));
      assert(*widget->GetSelector()->GetCursor() == *SquareFactory().Create("e7"));
      assert(!widget->GetSelector()->GetSelected());

      widget->Click(SquareFactory().Create("e5"));
      assert(*widget->GetSelector()->GetCursor() == *SquareFactory().Create("e5"));
      assert(!widget->GetSelector()->GetSelected());
      assert( game->GetBoard()->GetPiece(SquareFactory().Create("e7")));
      assert(!game->GetBoard()->GetPiece(SquareFactory().Create("e5")));

      //Playing e2-e4 must succeed for both Board and Game
      assert( game->GetBoard()->GetPiece(SquareFactory().Create("e2")));
      assert(!game->GetBoard()->GetPiece(SquareFactory().Create("e4")));
      widget->Click(SquareFactory().Create("e2"));
      assert(*widget->GetSelector()->GetCursor() == *SquareFactory().Create("e2"));
      assert(widget->GetSelector()->GetSelected());
      assert(*widget->GetSelector()->GetSelected() == *SquareFactory().Create("e2"));

      widget->Click(SquareFactory().Create("e4"));
      assert(*widget->GetSelector()->GetCursor() == *SquareFactory().Create("e4"));
      assert(!widget->GetSelector()->GetSelected());
      assert(!game->GetBoard()->GetPiece(SquareFactory().Create("e2")));
      assert( game->GetBoard()->GetPiece(SquareFactory().Create("e4")));
    }
  }
  #endif
}

 

 

 

 

 

./CppChess/chesshelper.h

 

#ifndef RIBI_CHESSHELPER_H
#define RIBI_CHESSHELPER_H

#include <set>
#include <vector>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#include <boost/shared_ptr.hpp>
#pragma GCC diagnostic pop

namespace ribi {

///Help adding constness a bit
template <class T>
const std::vector<boost::shared_ptr<const T>> AddConst(
  const std::vector<boost::shared_ptr<T>> v)
{
  return std::vector<boost::shared_ptr<const T>>(v.begin(),v.end());
}

///Help adding constness a bit
template <class T>
const std::set<boost::shared_ptr<const T>> AddConst(
  const std::set<boost::shared_ptr<T>> v)
{
  return std::set<boost::shared_ptr<const T>>(v.begin(),v.end());
}

} //~namespace ribi

#endif // RIBI_CHESSHELPER_H

 

 

 

 

 

./CppChess/chesshelper.cpp

 

#include "chesshelper.h"

 

 

 

 

 

./CppChess/chessmove.h

 

#ifndef RIBI_CHESSMOVE_H
#define RIBI_CHESSMOVE_H

#include <iosfwd>
#include <memory>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#include <boost/xpressive/xpressive_fwd.hpp>
#include <boost/shared_ptr.hpp>

#include "chessfwd.h"
#include "chesssquare.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace Chess {

struct Move
{
  ///Parses a Move from char* (not yet supported by GCC)
  ///Move(const char * const s) : Move(std::string(s)) {}

  ///Obtain the square the piece is moving from
  boost::shared_ptr<const Square> From() const noexcept { return m_from; }

  ///Obtain the Move in the notational form it was contructed with
  const std::string& GetStr() const { return m_str; }

  static std::string GetVersion();
  static std::vector<std::string> GetVersionHistory();

  ///Obtain whether this move is a capture
  bool IsCapture() const { return m_is_capture; }

  ///Obtain whether this move performs a castling
  bool IsCastling() const;

  ///Obtain whether this move results in a check
  bool IsCheck() const { return m_is_check; }

  ///Obtain whether this move results in a checkmate
  bool IsCheckmate() const { return m_is_checkmate; }

  ///Obtain whether this move is an en passant capture
  bool IsEnPassant() const { return m_is_en_passant; }

  ///Obtain whether this move results in a promotion
  bool IsPromotion() const { return m_is_promotion; }

  ///Parse the string to obtain the square the piece is moving from, when known
  ///Examples:
  ///* 'a2 a3' results in a Square with 'a2'
  ///* 'a3' results in an empty Square
  static boost::shared_ptr<Chess::Square> ParseFrom(const std::string& s);

  ///Obtain whether the string is a capture
  static bool ParseIsCapture(const std::string& s);

  ///Obtain whether the string results in a check
  static bool ParseIsCheck(const std::string& s);

  ///Obtain whether the string is a castling
  static bool ParseIsCastling(const std::string& s);

  ///Obtain whether the string results in a checkmate
  static bool ParseIsCheckmate(const std::string& s);

  ///Obtain whether the string results in an en passant capture
  static bool ParseIsEnPassant(const std::string& s);

  ///Obtain whether the string is a move that results in a promotion
  static bool ParseIsPromotion(const std::string& s);

  ///Parse the Piece from a string, returns nullptr if no piece cannot be determined
  static boost::shared_ptr<Chess::Piece> ParsePiece(const std::string& s) noexcept;

  ///Parse the Piece the pawn is promoted to from a string
  static boost::shared_ptr<Chess::Piece> ParsePiecePromotion(const std::string& s);

  ///Parse the Score from a string
  static boost::shared_ptr<Chess::Score> ParseScore(const std::string& s);

  ///Parse the Square the Piece is moving to
  static boost::shared_ptr<Chess::Square> ParseTo(const std::string& s);

  ///Obtain the piece type
  const boost::shared_ptr<Chess::Piece> Piece() const { return m_piece; }

  ///Obtain the piece type promoted to
  const boost::shared_ptr<Chess::Piece> PiecePromotion() const { return m_piece_promotion; }

  ///Obtain the score
  const boost::shared_ptr<Chess::Score> Score() const { return m_score; }


  #ifndef NDEBUG
  ///Tests all moves that are potentially valid,
  ///that is, there must be situations possible
  ///in which these are valid.
  static void Test() noexcept;
  #endif

  ///Obtain the square the piece is moving to
  boost::shared_ptr<const Square> To() const noexcept { return m_to; }

  ///Convert a Move to its long notational form
  std::string ToStr() const;

  private:
  ///Parses a Move from std::string.
  explicit Move(const std::string& s);

  ~Move() {}

  #define CHESS_MOVE_NOT_USE_CONST
  #ifndef CHESS_MOVE_NOT_USE_CONST
  const boost::shared_ptr<Square> m_from;
  const bool m_is_capture;
  const bool m_is_castling;
  const bool m_is_check;
  const bool m_is_checkmate;
  const bool m_is_promotion;
  const boost::shared_ptr<Chess::Piece> m_piece;
  const boost::shared_ptr<Chess::Piece> m_piece_promotion;
  const boost::shared_ptr<Chess::Score> m_score;
  const std::string m_str;
  const boost::shared_ptr<Chess::Square> m_to;
  #else
  boost::shared_ptr<const Square> m_from;
  bool m_is_capture;
  bool m_is_castling;
  bool m_is_check;
  bool m_is_checkmate;
  bool m_is_en_passant;
  bool m_is_promotion;
  boost::shared_ptr<Chess::Piece> m_piece;
  boost::shared_ptr<Chess::Piece> m_piece_promotion;
  boost::shared_ptr<Chess::Score> m_score;

  ///The Move in the same notational form as given in the contructor
  std::string m_str;

  boost::shared_ptr<const Chess::Square> m_to;
  #endif
  ///Obtain all matches of regex in a certain string
  //From http://www.richelbilderbeek.nl/CppGetRegexMatches.htm
  static std::vector<std::string> GetRegexMatches(
    const std::string& s,
    const boost::xpressive::sregex& r);

  friend void boost::checked_delete<>(Move *);

  friend class MoveFactory;
  friend bool operator==(const Move& lhs, const Move& rhs);

};

bool operator==(const Move& lhs, const Move& rhs);
bool operator!=(const Move& lhs, const Move& rhs);
std::ostream& operator<<(std::ostream& os,const Move& m);

} //~namespace Chess
} //~namespace ribi

#endif // RIBI_CHESSMOVE_H

 

 

 

 

 

./CppChess/chessmove.cpp

 

#include <cassert>
#include <stdexcept>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include <boost/lexical_cast.hpp>
#include <boost/xpressive/xpressive.hpp>

#include "chesscastling.h"
#include "chessmove.h"
#include "chessmoves.h"
#include "chesspiece.h"
#include "chesspiecefactory.h"
#include "chessmovefactory.h"
#include "chesssquarefactory.h"
#include "chessscore.h"
#include "trace.h"
#pragma GCC diagnostic pop

ribi::Chess::Move::Move(const std::string& s)
  : m_from(ParseFrom(s)),
    m_is_capture(ParseIsCapture(s)),
    m_is_castling(ParseIsCastling(s)),
    m_is_check(ParseIsCheck(s)),
    m_is_checkmate(ParseIsCheckmate(s)),
    m_is_en_passant(ParseIsEnPassant(s)),
    m_is_promotion(ParseIsPromotion(s)),
    m_piece(ParsePiece(s)),
    m_piece_promotion(ParsePiecePromotion(s)),
    m_score(ParseScore(s)),
    m_str(s),
    m_to(ParseTo(s))
{
  #ifndef NDEBUG
  Test();
  #endif

  if (s.empty()) throw std::logic_error("std::string to parse is empty");
  if (!m_to && !m_is_castling && (!m_score))
  {
    const std::string error = "ribi::Chess::Move::Move exception: m_to not initialized for non-castling non-score move " + s;
    throw std::logic_error(error.c_str());
  }

  #ifndef RIBI_CHESS_ALLOW_SHORT_NOTATION
  if (m_to && !m_from)
  {
    const std::string error = "ribi::Chess::Move::Move exception: if there is a 'to', also supply a 'from' in move " + s;
    throw std::logic_error(error.c_str());
  }
  #endif // RIBI_CHESS_ALLOW_SHORT_NOTATION
  if (!m_piece && !m_is_castling && !m_score)
  {
    const std::string error = "ribi::Chess::Move::Move exception: m_piece not initialized for non-castling non-score move " + s;
    throw std::logic_error(error.c_str());
  }

  if (m_is_en_passant && !m_is_capture) throw std::logic_error("ribi::Chess::Move::Move exception: every en passant capture is a capture");

  if (boost::xpressive::regex_search(s,boost::xpressive::sregex::compile("(e\\.p\\.)")) && !m_is_en_passant)
  {
    const std::string error = "ribi::Chess::Move::Move exception: move is an invalid en passant move: " + s;
    throw std::logic_error(error.c_str());
  }

  if (m_piece)
  {
    if (m_is_castling)
    {
      throw std::logic_error("ribi::Chess::Move::Move exception: m_piece cannot be initialized in a castling move");
    }
    if (m_score) throw std::logic_error("ribi::Chess::Move::Move exception: m_piece cannot be initialized in a score move");
    const bool valid = m_piece->CanDoMove(this);
    if (!valid)
    {
      const std::string t = "Move " + s + " invalid for " + m_piece->GetName();
      throw std::logic_error(t.c_str());
    }
  }
}

std::vector<std::string> ribi::Chess::Move::GetRegexMatches(
  const std::string& s,
  const boost::xpressive::sregex& r)
{
  std::vector<std::string> v;
  boost::xpressive::sregex_iterator cur(s.begin(),s.end(),r);
  boost::xpressive::sregex_iterator end;
  for( ; cur != end; ++cur )
  {
    const boost::xpressive::smatch& what = *cur;
    v.push_back(what[0]);
  }
  return v;
}

std::string ribi::Chess::Move::GetVersion()
{
  return "1.1";
}

std::vector<std::string> ribi::Chess::Move::GetVersionHistory()
{
  return {
    "2012-01-25: version 1.0: initial version"
    "2013-11-08: version 1.1: replaced Boost.Regex by Boost.Xpressive"
  };
}

bool ribi::Chess::Move::IsCastling() const
{
  assert(!m_is_castling || CanStrToCastling(m_str));
  return m_is_castling;
}

boost::shared_ptr<ribi::Chess::Square> ribi::Chess::Move::ParseFrom(const std::string& s)
{
  boost::shared_ptr<Chess::Square> square;
  static const boost::xpressive::sregex r { boost::xpressive::sregex::compile("[a-h][1-8]") };
  const std::vector<std::string> v = GetRegexMatches(s,r);
  #ifndef NDEBUG
  if (!(v.size() <= 2)) { TRACE(s); }
  #endif
  assert(v.size() <= 2);
  if (v.size() == 2)
  {
    square = SquareFactory().Create(v[0]);
  }
  return square;
}

bool ribi::Chess::Move::ParseIsCapture(const std::string& s)
{
  //if (s.empty()) throw std::logic_error("ribi::Chess::Move::ParseIsCapture exception: move must not be empty");
  //return boost::regex_match(s,boost::regex("[a-h]\\d?x.*"));
  static const boost::xpressive::sregex r {
    boost::xpressive::sregex::compile("(B|K|N|Q|R)?([a-h])?([1-8])?x[a-h][1-8](e.p.)?(\\+|\\#)?")
  };
  return boost::xpressive::regex_match(s,r);
}

bool ribi::Chess::Move::ParseIsCastling(const std::string& s)
{
  return CanStrToCastling(s);

  //return s == "0-0" || s == "O-O" || s == "O-O+" || s == "0-0-0" || s == "O-O-O"|| s == "O-O-O+";
}

bool ribi::Chess::Move::ParseIsCheck(const std::string& s)
{
  if (s.empty()) throw std::logic_error("ribi::Chess::Move::IsCheck(const std::string& s) exception: move must not be empty");
  return s[s.size() - 1] == '+';
}

bool ribi::Chess::Move::ParseIsCheckmate(const std::string& s)
{
  if (s.empty()) throw std::logic_error("ribi::Chess::Move::IsCheckmate(const std::string& s) exception: move must not be empty");
  return s[s.size() - 1] == '#';
}

bool ribi::Chess::Move::ParseIsEnPassant(const std::string& s)
{
  static const boost::xpressive::sregex r {
    boost::xpressive::sregex::compile("([a-h][4-5])x[a-h][3-6]e.p.(\\+|\\#)?")
  };

  if (!boost::xpressive::regex_match(s,r)) return false;
  const boost::shared_ptr<Chess::Square> from = ParseFrom(s);
  const boost::shared_ptr<Chess::Square> to = ParseTo(s);
  assert(from);
  assert(to);
  if (std::abs(from->GetFile().ToInt() - to->GetFile().ToInt()) != 1) return false;
  if (std::abs(from->GetRank().ToInt() - to->GetRank().ToInt()) != 1) return false;
  if (from->GetRank() == Chess::Rank("5") && to->GetRank() == Chess::Rank("6")) return true;
  if (from->GetRank() == Chess::Rank("4") && to->GetRank() == Chess::Rank("3")) return true;
  return false;
}

bool ribi::Chess::Move::ParseIsPromotion(const std::string& s)
{
  static const boost::xpressive::sregex r {
    boost::xpressive::sregex::compile("([a-h][1-8](x|\\s)?)?[a-h][1|8][B|N|Q|R](\\+|\\#)?")
  };
  return boost::xpressive::regex_match(s,r);
}

boost::shared_ptr<ribi::Chess::Piece> ribi::Chess::Move::ParsePiece(const std::string& s) noexcept
{
  if (s.empty())
  {
    boost::shared_ptr<ribi::Chess::Piece> p;
    return p;
  }
  const char namechar = s[0];
  boost::shared_ptr<ribi::Chess::Square> square;
  switch (namechar)
  {
    case 'B':
    case 'K':
    case 'N':
    case 'Q':
    case 'R':
      assert(s.size() >= 3);
      square = SquareFactory().Create(s.substr(1,2));
      break;
    case 'a':
    case 'b':
    case 'c':
    case 'd':
    case 'e':
    case 'f':
    case 'g':
    case 'h':
      assert(s.size() >= 2);
      square = SquareFactory().Create(s.substr(0,2));
      break;
    default:
    {
      boost::shared_ptr<ribi::Chess::Piece> p;
      return p;
    }
  }

  const Color color = Color::indeterminate;


  boost::shared_ptr<Chess::Piece> p;
  switch (namechar)
  {
    case 'B': p = PieceFactory().CreateBishop(color,square); break;
    case 'K': p = PieceFactory().CreateKing(color,square); break;
    case 'N': p = PieceFactory().CreateKnight(color,square); break;
    case 'Q': p = PieceFactory().CreateQueen(color,square); break;
    case 'R': p = PieceFactory().CreateRook(color,square); break;
    case 'a':
    case 'b':
    case 'c':
    case 'd':
    case 'e':
    case 'f':
    case 'g':
    case 'h':
      p = PieceFactory().CreatePawn(color,square); break;
    default:
    {
      boost::shared_ptr<ribi::Chess::Piece> p;
      return p;
    }
  }
  assert(p);
  return p;
}

boost::shared_ptr<ribi::Chess::Piece> ribi::Chess::Move::ParsePiecePromotion(const std::string& s)
{
  if (s.empty()) throw std::logic_error("ribi::Chess::Move::ParsePiece exception: move must not be empty");
  const boost::shared_ptr<Chess::Piece> p = PieceFactory().CreateFromPromotion(s);
  assert((p || !p) && "Allow a nullptr if a string cannot be parsed to a promoted piece");
  return p;
}

boost::shared_ptr<ribi::Chess::Score> ribi::Chess::Move::ParseScore(const std::string& s)
{
  boost::shared_ptr<Chess::Score> p;
  try
  {
    Chess::Score * const ptr = new Chess::Score(s);
    p.reset(ptr);
  }
  catch (std::exception& e)
  {
    //Move is not a Score, no problem
  }
  return p;
}

boost::shared_ptr<ribi::Chess::Square> ribi::Chess::Move::ParseTo(const std::string& s)
{
  static const boost::xpressive::sregex r {
    boost::xpressive::sregex::compile("[a-h][1-8]")
  };

  boost::shared_ptr<Chess::Square> square;
  const std::vector<std::string> v = GetRegexMatches(s,r);
  if (!v.empty())
  {
    assert(v.size() <= 2);
    const std::string t = v[ v.size() - 1];
    square = SquareFactory().Create(t);
    assert(square);
  }
  return square;
}

std::string ribi::Chess::Move::ToStr() const
{
  std::string s;
  if (m_piece)
  {
    if (!dynamic_cast<PiecePawn*>(m_piece.get()))
    {
      s += m_piece->GetNameChar();
    }
    if (m_from)
    {
      s += m_from->ToStr();
    }
    else
    {
      s += "??";
    }
    if (m_is_capture)
    {
      s += "x";
    }
    else
    {
      s += " ";
    }
    if (m_to)
    {
      s += m_to->ToStr();
    }
    else
    {
      s += "??";
    }
  }
  if (m_is_castling) s += m_str;
  if (m_is_check) s+= "+";
  if (m_is_checkmate) s+= "#";
  if (m_is_en_passant) s+= "e.p.";
  if (m_is_promotion) s+= "(promotion)";
  if (m_piece_promotion) s+= m_piece_promotion->GetNameChar();
  if (m_score) s+= m_score->ToStr();
  return s;
}

bool ribi::Chess::operator==(const Move& lhs, const Move& rhs)
{
  if (static_cast<bool>(lhs.m_from) != static_cast<bool>(rhs.m_from)) return false;
  if (lhs.m_from)
  {
    assert(rhs.m_from);
    if (*lhs.m_from != *rhs.m_from) return false;
  }
  if (lhs.m_is_capture  != rhs.m_is_capture) return false;
  if (lhs.m_is_castling != rhs.m_is_castling) return false;
  if (lhs.m_is_check != rhs.m_is_check) return false;
  if (lhs.m_is_checkmate != rhs.m_is_checkmate) return false;
  if (lhs.m_is_en_passant != rhs.m_is_en_passant) return false;
  if (lhs.m_is_promotion != rhs.m_is_promotion) return false;
  if (static_cast<bool>(lhs.m_piece) != static_cast<bool>(rhs.m_piece)) return false;
  if (lhs.m_piece)
  {
    assert(rhs.m_piece);
    if (*lhs.m_piece != *rhs.m_piece) return false;
  }

  if (static_cast<bool>(lhs.m_piece_promotion) != static_cast<bool>(rhs.m_piece_promotion)) return false;
  if (lhs.m_piece_promotion)
  {
    assert(rhs.m_piece_promotion);
    if (*lhs.m_piece_promotion != *rhs.m_piece_promotion) return false;
  }

  if (static_cast<bool>(lhs.m_score) != static_cast<bool>(rhs.m_score)) return false;
  if (lhs.m_piece_promotion)
  {
    assert(rhs.m_score);
    if (*lhs.m_score!= *rhs.m_score) return false;
  }

  return true;
}

bool ribi::Chess::operator!=(const Move& lhs, const Move& rhs)
{
  return !(lhs == rhs);
}

std::ostream& ribi::Chess::operator<<(std::ostream& os,const Move& m)
{
  os << m.GetStr();
  return os;
}

 

 

 

 

 

./CppChess/chessmovefactory.h

 

#ifndef RIBI_CHESSMOVEFACTORY_H
#define RIBI_CHESSMOVEFACTORY_H

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#include <boost/shared_ptr.hpp>

#include "chessfwd.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace Chess {

struct MoveFactory
{
  MoveFactory();

  const boost::shared_ptr<Move> Create(const std::string& s) const;

  const boost::shared_ptr<Move> Create(
    const boost::shared_ptr<const Chess::Square> from,
    const boost::shared_ptr<const Chess::Square> to
  ) const;

  const boost::shared_ptr<Move> DeepCopy(const Move& move) const;

  private:
  #ifndef NDEBUG
  static void Test() noexcept;
  #endif
};

} //~namespace Chess
} //~namespace ribi

#endif // RIBI_CHESSMOVEFACTORY_H

 

 

 

 

 

./CppChess/chessmovefactory.cpp

 

#include "chessmovefactory.h"

#include <cassert>

#include "chessmove.h"
#include "testtimer.h"

ribi::Chess::MoveFactory::MoveFactory()
{
  #ifndef NDEBUG
  Test();
  #endif
}

const boost::shared_ptr<ribi::Chess::Move>
  ribi::Chess::MoveFactory::Create(const std::string& s) const
{
  const boost::shared_ptr<ribi::Chess::Move> p {
    new Move(s)
  };
  #ifdef TODO_ISSUE_176
  assert(p);
  #endif
  return p;
}

const boost::shared_ptr<ribi::Chess::Move> ribi::Chess::MoveFactory::Create(
  const boost::shared_ptr<const Chess::Square> from,
  const boost::shared_ptr<const Chess::Square> to) const
{
  const std::string s = from->ToStr() + " " + to->ToStr();
  return Create(s);
}

const boost::shared_ptr<ribi::Chess::Move>
  ribi::Chess::MoveFactory::DeepCopy(
    const Move& move
  ) const
{
  const boost::shared_ptr<ribi::Chess::Move> p {
    Create(move.ToStr())
  };
  assert(p);
  return p;
}

#ifndef NDEBUG
void ribi::Chess::MoveFactory::Test() noexcept
{
  {
    static bool is_tested = false;
    if (is_tested) return;
    is_tested = true;
  }
  {
    Chess::Move("a2-a3");
  }
  const ribi::TestTimer test_timer(__func__,__FILE__,1.0);
}
#endif

 

 

 

 

 

./CppChess/chessmoves.h

 

#ifndef RIBI_CHESSMOVES_H
#define RIBI_CHESSMOVES_H

#include <string>
#include <vector>
#include "chesscolor.h"

namespace ribi {
namespace Chess {

///Moves is a stateless struct containing collections of moves
struct Moves
{

  //All moves in the
  //'Kasparov against the world match'
  //http://en.wikipedia.org/wiki/Kasparov_versus_the_World
  static std::vector<std::string> GetGameKasparovVersusTheWorld() noexcept;

  //Game in which white wins by checkmate in three moves
  static std::vector<std::string> GetGameShephardsMate() noexcept;

  ///Obtain invalid moves that can be performed by a bishop
  static std::vector<std::string> GetInvalidBishopMoves() noexcept;

  ///Obtain invalid moves that involve a capture
  static std::vector<std::string> GetInvalidCaptureMoves() noexcept;

  ///Obtain invalid castling moves
  static std::vector<std::string> GetInvalidCastlingMoves() noexcept;

  ///Obtain invalid moves that result in check
  static std::vector<std::string> GetInvalidCheckMoves() noexcept;

  ///Obtain invalid moves that result in checkmate
  static std::vector<std::string> GetInvalidCheckmateMoves() noexcept;

  ///Obtain invalid en passant moves
  static std::vector<std::string> GetInvalidEnPassantMoves() noexcept;

  ///Obtain invalid moves that can be performed by a king
  static std::vector<std::string> GetInvalidKingMoves() noexcept;

  ///Obtain invalid moves that can be performed by a knight
  static std::vector<std::string> GetInvalidKnightMoves() noexcept;

  ///Obtain invalid moves that can be performed by a pawn
  static std::vector<std::string> GetInvalidPawnMoves(const Chess::Color& color) noexcept;

  ///Obtain invalid moves that end in a promotion
  static std::vector<std::string> GetInvalidPromotionMoves() noexcept;

  ///Obtain invalid moves that can be performed by a queen
  static std::vector<std::string> GetInvalidQueenMoves() noexcept;

  ///Obtain invalid moves that can be performed by a rook
  static std::vector<std::string> GetInvalidRookMoves() noexcept;

  ///Obtain all moves that can be performed by a bishop
  static std::vector<std::string> GetValidBishopMoves() noexcept;

  ///Obtain moves that involve a capture
  static std::vector<std::string> GetValidCaptureMoves() noexcept;

  ///Obtain all castling moves
  static std::vector<std::string> GetValidCastlingMoves() noexcept;

  ///Obtain valid moves that result in check
  static std::vector<std::string> GetValidCheckMoves() noexcept;

  ///Obtain valid moves that result in checkmate
  static std::vector<std::string> GetValidCheckmateMoves() noexcept;

  ///Obtain en passant moves
  static std::vector<std::string> GetValidEnPassantMoves() noexcept;

  ///Obtain all moves that can be performed by a king
  static std::vector<std::string> GetValidKingMoves() noexcept;

  ///Obtain all moves that can be performed by a knight
  static std::vector<std::string> GetValidKnightMoves() noexcept;

  ///Obtain all moves that can be performed by a pawn
  static std::vector<std::string> GetValidPawnMoves(const Chess::Color& color) noexcept;

  ///Obtain moves that end in a promotion
  static std::vector<std::string> GetValidPromotionMoves() noexcept;

  ///Obtain all moves that can be performed by a queen
  static std::vector<std::string> GetValidQueenMoves() noexcept;

  ///Obtain all moves that can be performed by a rook
  static std::vector<std::string> GetValidRookMoves() noexcept;

  ///Obtain the version of this class
  static std::string GetVersion() noexcept;

  ///Obtain the version history of this class
  static std::vector<std::string> GetVersionHistory() noexcept;
};

} //~namespace Chess
} //~namespace ribi

#endif // RIBI_CHESSMOVES_H

 

 

 

 

 

./CppChess/chessmoves.cpp

 


#include <cassert>

#include "chessmoves.h"

std::vector<std::string> ribi::Chess::Moves::GetGameKasparovVersusTheWorld() noexcept
{
  return
  {
    "e4"   , "c5"  , //1
    "Nf3"  , "d6"  , //2
    "Bb5+" , "Bd7" , //3
    "Bxd7+", "Qxd7", //4
    "c4"   , "Nc6" , //5
    "Nc3"  , "Nf6" , //6
    "0-0"  , "g6"  , //7
    "d4"   , "cxd4", //8
    "Nxd4" , "Bg7" , //9
    "Nde2" , "Qe6" , //10
    "Nd5"  , "Qxe4", //11
    "Nc7+" , "Kd7" , //12
    "Nxa8" , "Qxc4", //13
    "Nb6+" , "axb6", //14
    "Nc3"  , "Ra8" , //15
    "a4"   , "Ne4" , //16
    "Nxe4" , "Qxe4", //17
    "Qb3"  , "f5"  , //18
    "Bg5"  , "Qb4" , //19
    "Qf7"  , "Be5" , //20
    "h3"   , "Rxa4", //21
    "Rxa4" , "Qxa4", //22
    "Qxh7" , "Bxb2", //23
    "Qxg6" , "Qe4" , //24
    "Qf7"  , "Bd4" , //25
    "Qb3"  , "f4"  , //26
    "Qf7"  , "Be5" , //27
    "h4"   , "b5"  , //28
    "h5"   , "Qc4" , //29
    "Qf5+" , "Qe6" , //30
    "Qxe6+", "Kxe6", //31
    "g3"   , "fxg3", //32
    "fxg3" , "b4"  , //33
    "Bf4"  , "Bd4+", //34
    "Kh1"  , "b3"  , //35
    "g4"   , "Kd5" , //36
    "g5"   , "e6"  , //37
    "h6"   , "Ne7" , //38
    "Rd1"  , "e5"  , //39
    "Be3"  , "Kc4" , //40
    "Bxd4" , "exd4", //41
    "Kg2"  , "b2"  , //42
    "Kf3"  , "Kc3" , //43
    "h7"   , "Ng6" , //44
    "Ke4"  , "Kc2" , //45
    "Rh1"  , "d3"  , //46
    "Kf5"  , "b1Q" , //47
    "Rxb1" , "Kxb1", //48
    "Kxg6" , "d2"  , //49
    "h8Q"  , "d1Q" , //50
    "Qh7"  , "b5"  , //51
    "Kf6+" , "Kb2" , //52
    "Qh2+" , "Ka1" , //53
    "Qf4"  , "b4"  , //54
    "Qxb4" , "Qf3+", //55
    "Kg7"  , "d5"  , //56
    "Qd4+" , "Kb1" , //57
    "g6"   , "Qe4" , //58
    "Qg1+" , "Kb2" , //59
    "Qf2+" , "Kc1" , //60
    "Kf6"  , "d4"  , //61
    "g7"   , "1-0"   //62
  };
}

std::vector<std::string> ribi::Chess::Moves::GetGameShephardsMate() noexcept
{
  return
  {
    "e2 e4", "e7 e5",
    "Bf1 c4", "a7 a6",
    "Qd1 f3", "a6 a5",
    "Qf3xf7#"
  };
}

std::vector<std::string> ribi::Chess::Moves::GetInvalidBishopMoves() noexcept
{
  return
  {
    "Ba1 b1", "Ba1 a2", "Ba1xb1", "Ba1xa2","Ba1 h2","Ba1 b8",
    "Ba1 a1",
    "0-0" , "0-0-0" , "O-O" , "O-O-O" ,
    "0-0+", "0-0-0+", "O-O+", "O-O-O+",
    "0-0#", "0-0-0#", "O-O#", "O-O-O#",
    "1-0", "0-1", "1/2-1/2"
  };
}

std::vector<std::string> ribi::Chess::Moves::GetInvalidCaptureMoves() noexcept
{
  return
  {

  };
}

std::vector<std::string> ribi::Chess::Moves::GetInvalidCastlingMoves() noexcept
{
  return
  {

  };
}

std::vector<std::string> ribi::Chess::Moves::GetInvalidEnPassantMoves() noexcept
{
  return
  {
    "d2 d3e.p.", "d2xd3e.p.", "d5 e6",
    "a5xb6" ,"b5xa6" ,"a4xb3" ,"b4xa3" ,
    "a5xb6+","b5xa6+","a4xb3+","b4xa3+",
    "a5xb6#","b5xa6#","a4xb3#","b4xa3#",
    "a5 b6e.p." ,"b5 a6e.p." ,"a4 b3e.p." ,"b4 a3e.p." ,
    "a5 b6e.p.+","b5 a6e.p.+","a4 b3e.p.+","b4 a3e.p.+",
    "a5 b6e.p.#","b5 a6e.p.#","a4 b3e.p.#","b4 a3e.p.#",
    "a4xb5e.p." ,"b4xa5e.p." ,"a5xb2e.p." ,"b5xa2e.p." ,
    "a4xb5e.p.+","b4xa5e.p.+","a5xb2e.p.+","b5xa2e.p.+",
    "a4xb5e.p.#","b4xa5e.p.#","a5xb2e.p.#","b5xa2e.p.#",
    "a6xb7e.p."
  };
}

std::vector<std::string> ribi::Chess::Moves::GetInvalidKingMoves() noexcept
{
  return
  {
    "Kd4 b2", "Kd4 b3", "Kd4 b4", "Kd4 b5", "Kd4 b6",
    "Kd4 c1", "Kd4 c2", "Kd4 c6", "Kd4 c7",
    "Kd4 d1", "Kd4 d2", "Kd4 d4", "Kd4 d6", "Kd4 d7",
    "Kd4 e1", "Kd4 e2", "Kd4 e6", "Kd4 e7",
    "Kd4 f2", "Kd4 f3", "Kd4 f4", "Kd4 f5", "Kd4 f6",
    "Ka1 h8", "Ka1xh8", "Ka1 a8", "Ka1 a8",
    "0-0" , "0-0-0" , "O-O" , "O-O-O" ,
    "0-0+", "0-0-0+", "O-O+", "O-O-O+",
    "0-0#", "0-0-0#", "O-O#", "O-O-O#",
    "1-0", "0-1", "1/2-1/2"
  };
}

std::vector<std::string> ribi::Chess::Moves::GetInvalidKnightMoves() noexcept
{
  return
  {
    "Nd4 d4",
    "Nd4 c3","Nd4 c4","Nd4 c5","Nd4 e3","Nd4 e4","Nd4 e5","Nd4 d3","Nd4 d5",
    "Nd4 b2","Nd4 f2","Nd4 f6","Nd4 b6",
    "Na1 h3","Na1 h7","Na1 g1","Na1 g8",
    "0-0" , "0-0-0" , "O-O" , "O-O-O" ,
    "0-0+", "0-0-0+", "O-O+", "O-O-O+",
    "0-0#", "0-0-0#", "O-O#", "O-O-O#",
    "1-0", "0-1", "1/2-1/2"
  };
}

std::vector<std::string> ribi::Chess::Moves::GetInvalidPawnMoves(const Chess::Color& color) noexcept
{
  if (color == Color::indeterminate)
  return
  {
    "a2xa3", "a3xa2", "a2 b3", "a3 b2",
    "a6xb7e.p." , "b6xa7e.p." , "a3xb2e.p." , "b3xa2e.p.",
    "a6xb7e.p.+", "b6xa7e.p.+", "a3xb2e.p.+", "b3xa2e.p.+",
    "a6xb7e.p.#", "b6xa7e.p.#", "a3xb2e.p.#", "b3xa2e.p.#"
    "0-0" , "0-0-0" , "O-O" , "O-O-O" ,
    "0-0+", "0-0-0+", "O-O+", "O-O-O+",
    "0-0#", "0-0-0#", "O-O#", "O-O-O#",
    "1-0", "0-1", "1/2-1/2"
  };
  if (color == Color::white)
  return
  {
    "a2 a1Q", "a1Q", "e4 e3", "e4xd3e.p."
  };

  if (color == Color::black)
  return
  {
     "a2 a3", "a2 a4", "a7 a8Q", "a8Q", "e4 e5", "h5xg6e.p."
  };
  assert(!"Should not get here");
  throw std::vector<std::string>();
}

std::vector<std::string> ribi::Chess::Moves::GetInvalidPromotionMoves() noexcept
{
  return
  {

  };
}

std::vector<std::string> ribi::Chess::Moves::GetInvalidQueenMoves() noexcept
{
  return
  {
    "Qa1 b7" , "Qa1 h2" , "Qa1 h7" ,
    "Qa1 b7+", "Qa1 h2+", "Qa1 h7+",
    "Qa1 b7#", "Qa1 h2#", "Qa1 h7#",
    "Qa1xb7" , "Qa1xh2" , "Qa1xh7" ,
    "Qa1xb7+", "Qa1xh2+", "Qa1xh7+",
    "Qa1xb7#", "Qa1xh2#", "Qa1xh7#",
    "Qd5xe6e.p.", "Qd5xe6e.p.+", "Qd5xe6+e.p.","Qd5xe6e.p.#", "Qd5xe6#e.p.",
    "0-0", "O-O"

  };
}

std::vector<std::string> ribi::Chess::Moves::GetInvalidRookMoves() noexcept
{
  return
  {
    "Ra1 b8", "Ra1 h2", "Ra1 h8"
  };
}

std::vector<std::string> ribi::Chess::Moves::GetValidBishopMoves() noexcept
{
  return
  {
    "Bd4 a1","Bd4 b2","Bd4 c3","Bd4 e5","Bd4 f6","Bd4 g7","Bd4 g7",
    "Bd4 a1+","Bd4 b2+","Bd4 c3+","Bd4 e5+","Bd4 f6+","Bd4 g7+","Bd4 g7+",
    "Bd4 a1#","Bd4 b2#","Bd4 c3#","Bd4 e5#","Bd4 f6#","Bd4 g7#","Bd4 g7#",
    "Ba1","Bb2","Bc3","Be5","Bf6","Bg7","Bg7",
    "Ba1+","Bb2+","Bc3+","Be5+","Bf6+","Bg7+","Bg7+",
    "Ba1#","Bb2#","Bc3#","Be5#","Bf6#","Bg7#","Bg7#"
  };
}

std::vector<std::string> ribi::Chess::Moves::GetValidCaptureMoves() noexcept
{
  return
  {
    "axb3","axb3+","axb3#","a2xb3","a2xb3+","a2xb3#",
    "Baxb3","Baxb3+","Baxb3#","Ba2xb3","Ba2xb3+","Ba2xb3#",
    "a5xb6e.p." ,"b5xa6e.p." ,"a4xb3e.p." ,"b4xa3e.p." ,
    "a5xb6e.p.+","b5xa6e.p.+","a4xb3e.p.+","b4xa3e.p.+",
    "a5xb6e.p.#","b5xa6e.p.#","a4xb3e.p.#","b4xa3e.p.#"
  };
}

std::vector<std::string> ribi::Chess::Moves::GetValidCastlingMoves() noexcept
{
  return
  {
    "0-0","0-0+","0-0#","0-0-0","0-0-0+","0-0-0#",
    "O-O","O-O+","O-O#","O-O-O","O-O-O+","O-O-O#"
  };
}

std::vector<std::string> ribi::Chess::Moves::GetValidCheckMoves() noexcept
{
  return
  {
    "a3+","a2 a3+","a2xb3+","Ba3+",
    "Ba2 b3+","Ba2xb3+",
    "O-O+","O-O-O+","0-0+","0-0-0+", "Bf1 b5+"
  };
}

std::vector<std::string> ribi::Chess::Moves::GetValidCheckmateMoves() noexcept
{
  return
  {

  };
}

std::vector<std::string> ribi::Chess::Moves::GetValidEnPassantMoves() noexcept
{
  return
  {
    "a5xb6e.p." ,"b5xa6e.p." ,"a4xb3e.p." ,"b4xa3e.p." ,
    "a5xb6e.p.+","b5xa6e.p.+","a4xb3e.p.+","b4xa3e.p.+",
    "a5xb6e.p.#","b5xa6e.p.#","a4xb3e.p.#","b4xa3e.p.#"
  };
}

std::vector<std::string> ribi::Chess::Moves::GetValidKingMoves() noexcept
{
  return
  {
    "Kd4 c3","Kd4 c4","Kd4 c5","Kd4 d5","Kd4 e5","Kd4 e4","Kd4 e3","Kd4 d3",
    "Kd4xc3","Kd4xc4","Kd4xc5","Kd4xd5","Kd4xe5","Kd4xe4","Kd4xe3","Kd4xd3",
    "Kd4 c3+","Kd4 c4+","Kd4 c5+","Kd4 d5+","Kd4 e5+","Kd4 e4+","Kd4 e3+","Kd4 d3+",
    "Kd4xc3+","Kd4xc4+","Kd4xc5+","Kd4xd5+","Kd4xe5+","Kd4xe4+","Kd4xe3+","Kd4xd3+",
    "Kd4 c3#","Kd4 c4#","Kd4 c5#","Kd4 d5#","Kd4 e5#","Kd4 e4#","Kd4 e3#","Kd4 d3#",
    "Kd4xc3#","Kd4xc4#","Kd4xc5#","Kd4xd5#","Kd4xe5#","Kd4xe4#","Kd4xe3#","Kd4xd3#",
    "Kf1 g1"
   };
}

std::vector<std::string> ribi::Chess::Moves::GetValidKnightMoves() noexcept
{
  return
  {
    "Nd4 b3" ,"Nd4 c2" ,"Nd4 e2" ,"Nd4 f3" ,"Nd4 f5" ,"Nd4 e6" ,"Nd4 c6" ,"Nd4 b5" ,
    "Nd4 b3+","Nd4 c2+","Nd4 e2+","Nd4 f3+","Nd4 f5+","Nd4 e6+","Nd4 c6+","Nd4 b5+",
    "Nd4 b3#","Nd4 c2#","Nd4 e2#","Nd4 f3#","Nd4 f5#","Nd4 e6#","Nd4 c6#","Nd4 b5#",
    "Nd4xb3" ,"Nd4xc2" ,"Nd4xe2" ,"Nd4xf3" ,"Nd4xf5" ,"Nd4xe6" ,"Nd4xc6" ,"Nd4xb5" ,
    "Nd4xb3+","Nd4xc2+","Nd4xe2+","Nd4xf3+","Nd4xf5+","Nd4xe6+","Nd4xc6+","Nd4xb5+",
    "Nd4xb3#","Nd4xc2#","Nd4xe2#","Nd4xf3#","Nd4xf5#","Nd4xe6#","Nd4xc6#","Nd4xb5#",
    "Nb3" ,"Nc2" ,"Ne2" ,"Nf3" ,"Nf5" ,"Ne6" ,"Nc6" ,"Nb5" ,
    "Nb3+","Nc2+","Ne2+","Nf3+","Nf5+","Ne6+","Nc6+","Nb5+",
    "Nb3#","Nc2#","Ne2#","Nf3#","Nf5#","Ne6#","Nc6#","Nb5#"
  };
}

std::vector<std::string> ribi::Chess::Moves::GetValidPawnMoves(const Chess::Color& color) noexcept
{
  if (color == Color::indeterminate)
  return
  {
    "a2 a3" , "a2 a4" , "a2 a1Q" , "a7 a8Q" , "a3" , "a4" , "a8Q" , "a1Q",
    "a2 a3+", "a2 a4+", "a2 a1Q+", "a7 a8Q+", "a3+", "a4+", "a8Q+", "a1Q+",
    "a2 a3#", "a2 a4#", "a2 a1Q#", "a7 a8Q#", "a3#", "a4#", "a8Q#", "a1Q#",
    "a2xb3" , "a3xb2" , "b3xa4" , "b3xc4" , "b3xa2" , "b3xc2" ,
    "a2xb3+", "a3xb2+", "b3xa4+", "b3xc4+", "b3xa2+", "b3xc2+",
    "a2xb3#", "a3xb2#", "b3xa4#", "b3xc4#", "b3xa2#", "b3xc2#",
    "e4 e5", "e4 e3",
    "a5xb6e.p." , "b5xa6e.p." , "a4xb3e.p." , "b4xa3e.p.",
    "a5xb6e.p.+", "b5xa6e.p.+", "a4xb3e.p.+", "b4xa3e.p.+",
    "a5xb6e.p.#", "b5xa6e.p.#", "a4xb3e.p.#", "b4xa3e.p.#"
  };
  if (color == Color::white)
  return
  {
    "a2 a3", "a2 a4", "a7 a8Q", "a3", "a4", "a8Q", "e4 e5"
  };
  if (color == Color::black)
  return
  {
    "a2 a1Q", "a1Q", "a3", "a4", "a7 a6", "a7 a5", "e4 e3"
  };
  assert(!"Should not get here");
  return std::vector<std::string>();
}

std::vector<std::string> ribi::Chess::Moves::GetValidPromotionMoves() noexcept
{
  return
  {
    "a8B","a8N","a8Q","a8R","a1B","a1N","a1Q","a1R",
    "a8B+","a8N+","a8Q+","a8R+","a1B+","a1N+","a1Q+","a1R+",
    "a8B#","a8N#","a8Q#","a8R#","a1B#","a1N#","a1Q#","a1R#",
    "a2 a1Q","a2 a1Q+","a2 a1Q#"
  };
}

std::vector<std::string> ribi::Chess::Moves::GetValidQueenMoves() noexcept
{
  return
  {
    "Qd4 d1","Qd4 d2","Qd4 d3","Qd4 d5","Qd4 d6","Qd4 d7","Qd4 d8",
    "Qd4 a4","Qd4 b4","Qd4 c4","Qd4 e4","Qd4 f4","Qd4 g4","Qd4 h4",
    "Qd4xd1","Qd4xd2","Qd4xd3","Qd4xd5","Qd4xd6","Qd4xd7","Qd4xd8",
    "Qd4xa4","Qd4xb4","Qd4xc4","Qd4xe4","Qd4xf4","Qd4xg4","Qd4xh4",
    "Qd4 d1+","Qd4 d2+","Qd4 d3+","Qd4 d5+","Qd4 d6+","Qd4 d7+","Qd4 d8+",
    "Qd4 a4+","Qd4 b4+","Qd4 c4+","Qd4 e4+","Qd4 f4+","Qd4 g4+","Qd4 h4+",
    "Qd4xd1+","Qd4xd2+","Qd4xd3+","Qd4xd5+","Qd4xd6+","Qd4xd7+","Qd4xd8+",
    "Qd4xa4+","Qd4xb4+","Qd4xc4+","Qd4xe4+","Qd4xf4+","Qd4xg4+","Qd4xh4+",
    "Qd4 d1#","Qd4 d2#","Qd4 d3#","Qd4 d5#","Qd4 d6#","Qd4 d7#","Qd4 d8#",
    "Qd4 a4#","Qd4 b4#","Qd4 c4#","Qd4 e4#","Qd4 f4#","Qd4 g4#","Qd4 h4#",
    "Qd4xd1#","Qd4xd2#","Qd4xd3#","Qd4xd5#","Qd4xd6#","Qd4xd7#","Qd4xd8#",
    "Qd4xa4#","Qd4xb4#","Qd4xc4#","Qd4xe4#","Qd4xf4#","Qd4xg4#","Qd4xh4#",
    "Qd1","Qd2","Qd3","Qd5","Qd6","Qd7","Qd8",
    "Qa4","Qb4","Qc4","Qe4","Qf4","Qg4","Qh4",
    "Qd1+","Qd2+","Qd3+","Qd5+","Qd6+","Qd7+","Qd8+",
    "Qa4+","Qb4+","Qc4+","Qe4+","Qf4+","Qg4+","Qh4+",
    "Qd1#","Qd2#","Qd3#","Qd5#","Qd6#","Qd7#","Qd8#",
    "Qa4#","Qb4#","Qc4#","Qe4#","Qf4#","Qg4#","Qh4#",
    "Qd4 a1","Qd4 b2","Qd4 c3","Qd4 e5","Qd4 f6","Qd4 g7","Qd4 g7",
    "Qd4 a1+","Qd4 b2+","Qd4 c3+","Qd4 e5+","Qd4 f6+","Qd4 g7+","Qd4 g7+",
    "Qd4 a1#","Qd4 b2#","Qd4 c3#","Qd4 e5#","Qd4 f6#","Qd4 g7#","Qd4 g7#",
    "Qa1","Qb2","Qc3","Qe5","Qf6","Qg7","Qg7",
    "Qa1+","Qb2+","Qc3+","Qe5+","Qf6+","Qg7+","Qg7+",
    "Qa1#","Qb2#","Qc3#","Qe5#","Qf6#","Qg7#","Qg7#", "Qf7 f6"
  };
}

std::vector<std::string> ribi::Chess::Moves::GetValidRookMoves() noexcept
{
  return
  {
    "Rd4 d1","Rd4 d2","Rd4 d3","Rd4 d5","Rd4 d6","Rd4 d7","Rd4 d8",
    "Rd4 a4","Rd4 b4","Rd4 c4","Rd4 e4","Rd4 f4","Rd4 g4","Rd4 h4",
    "Rd4xd1","Rd4xd2","Rd4xd3","Rd4xd5","Rd4xd6","Rd4xd7","Rd4xd8",
    "Rd4xa4","Rd4xb4","Rd4xc4","Rd4xe4","Rd4xf4","Rd4xg4","Rd4xh4",
    "Rd4 d1+","Rd4 d2+","Rd4 d3+","Rd4 d5+","Rd4 d6+","Rd4 d7+","Rd4 d8+",
    "Rd4 a4+","Rd4 b4+","Rd4 c4+","Rd4 e4+","Rd4 f4+","Rd4 g4+","Rd4 h4+",
    "Rd4xd1+","Rd4xd2+","Rd4xd3+","Rd4xd5+","Rd4xd6+","Rd4xd7+","Rd4xd8+",
    "Rd4xa4+","Rd4xb4+","Rd4xc4+","Rd4xe4+","Rd4xf4+","Rd4xg4+","Rd4xh4+",
    "Rd4 d1#","Rd4 d2#","Rd4 d3#","Rd4 d5#","Rd4 d6#","Rd4 d7#","Rd4 d8#",
    "Rd4 a4#","Rd4 b4#","Rd4 c4#","Rd4 e4#","Rd4 f4#","Rd4 g4#","Rd4 h4#",
    "Rd4xd1#","Rd4xd2#","Rd4xd3#","Rd4xd5#","Rd4xd6#","Rd4xd7#","Rd4xd8#",
    "Rd4xa4#","Rd4xb4#","Rd4xc4#","Rd4xe4#","Rd4xf4#","Rd4xg4#","Rd4xh4#",
    "Rd1","Rd2","Rd3","Rd5","Rd6","Rd7","Rd8",
    "Ra4","Rb4","Rc4","Re4","Rf4","Rg4","Rh4",
    "Rd1+","Rd2+","Rd3+","Rd5+","Rd6+","Rd7+","Rd8+",
    "Ra4+","Rb4+","Rc4+","Re4+","Rf4+","Rg4+","Rh4+",
    "Rd1#","Rd2#","Rd3#","Rd5#","Rd6#","Rd7#","Rd8#",
    "Ra4#","Rb4#","Rc4#","Re4#","Rf4#","Rg4#","Rh4#"
  };
}

std::string ribi::Chess::Moves::GetVersion() noexcept
{
  return "1.0";
}

std::vector<std::string> ribi::Chess::Moves::GetVersionHistory() noexcept
{
  return {
    "2012-01-25: version 1.0: initial version"
  };
}

 

 

 

 

 

./CppChess/chessmovetest.cpp

 

#include "chessmove.h"

#include <cassert>

#include "chessmoves.h"
#include "chesspiece.h"
#include "chesssquarefactory.h"
#include "testtimer.h"
#include "trace.h"


#ifndef NDEBUG
void ribi::Chess::Move::Test() noexcept
{
  {
    static bool tested = false;
    if (tested) return;
    tested = true;
  }
  {
    Chess::Square::Test();
    Chess::Piece::Test();
  }
  const TestTimer test_timer(__func__,__FILE__,1.0);
  const bool verbose{false};
  if (verbose) { TRACE("Test Chess::Move operators and copy constructors"); }
  {
    Chess::Move m("a2 a3");
    Chess::Move n("a2 a3");
    assert(m == n);
  }
  {
    Chess::Move m("a2 a3");
    Chess::Move n("a3 a2");
    assert(m != n);
  }
  {
    Chess::Move m("a2 a3");
    Chess::Move n(m);
    assert(m == n);
  }

  if (verbose) { TRACE("Test Chess::Move parsing of the square the piece is moving from"); }

  assert((*Move::ParseFrom( "a2 a3")==*SquareFactory().Create(Chess::File("a"),Chess::Rank("2"))));
  assert((*Move::ParseFrom("Bb3 c5")==*SquareFactory().Create(Chess::File("b"),Chess::Rank("3"))));
  assert((*Move::ParseFrom("Kc4 d4")==*SquareFactory().Create(Chess::File("c"),Chess::Rank("4"))));
  assert((*Move::ParseFrom("Nd5 e6")==*SquareFactory().Create(Chess::File("d"),Chess::Rank("5"))));
  assert((*Move::ParseFrom("Qe6 f7")==*SquareFactory().Create(Chess::File("e"),Chess::Rank("6"))));
  assert((*Move::ParseFrom("Rf7 h7")==*SquareFactory().Create(Chess::File("f"),Chess::Rank("7"))));
  assert(!ribi::Chess::Move::ParseFrom("a3"));
  assert(!ribi::Chess::Move::ParseFrom("0-0"));
  assert(!ribi::Chess::Move::ParseFrom("0-0+"));
  assert(!ribi::Chess::Move::ParseFrom("0-0#"));
  assert(!ribi::Chess::Move::ParseFrom("O-O"));
  assert(!ribi::Chess::Move::ParseFrom("O-O+"));
  assert(!ribi::Chess::Move::ParseFrom("O-O#"));
  assert(!ribi::Chess::Move::ParseFrom("0-0-0"));
  assert(!ribi::Chess::Move::ParseFrom("0-0-0+"));
  assert(!ribi::Chess::Move::ParseFrom("0-0-0#"));
  assert(!ribi::Chess::Move::ParseFrom("O-O-O"));
  assert(!ribi::Chess::Move::ParseFrom("O-O-O+"));
  assert(!ribi::Chess::Move::ParseFrom("O-O-O#"));

  if (verbose) { TRACE("Testing valid capture moves"); }
  {
    const std::vector<std::string> v = Moves::GetValidCaptureMoves();
    std::for_each(v.begin(),v.end(),
      [](const std::string& s)
      {
        if (!ribi::Chess::Move::ParseIsCapture(s)) { TRACE(s); }
        assert(ribi::Chess::Move::ParseIsCapture(s));
      }
    );
  }
  if (verbose) { TRACE("Testing valid castling moves"); }
  {
    const std::vector<std::string> v = Moves::GetValidCastlingMoves();
    std::for_each(v.begin(),v.end(),
      [](const std::string& s)
      {
        if (!ribi::Chess::Move::ParseIsCastling(s)) { TRACE(s); }
        assert(ribi::Chess::Move::ParseIsCastling(s));
      }
    );
  }

  assert(!ribi::Chess::Move::ParseIsCastling("a3"));

  if (verbose) { TRACE("Testing valid moves that result in check"); }
  {
    const std::vector<std::string> v = Moves::GetValidCheckMoves();
    std::for_each(v.begin(),v.end(),
      [](const std::string& s)
      {
        if (!ribi::Chess::Move::ParseIsCheck(s)) { TRACE(s); }
        assert(ribi::Chess::Move::ParseIsCheck(s));
      }
    );
  }
  assert(!ribi::Chess::Move::ParseIsCheck("a2 a3"));
  assert(!ribi::Chess::Move::ParseIsCheck("a2xb3"));
  assert(!ribi::Chess::Move::ParseIsCheck("Ba3"));
  assert(!ribi::Chess::Move::ParseIsCheck("Ba2 b3"));
  assert(!ribi::Chess::Move::ParseIsCheck("Ba2xb3"));
  assert(!ribi::Chess::Move::ParseIsCheck("a2 a3#"));
  assert(!ribi::Chess::Move::ParseIsCheck("a2xb3#"));
  assert(!ribi::Chess::Move::ParseIsCheck("Ba3#"));
  assert(!ribi::Chess::Move::ParseIsCheck("Ba2 b3#"));
  assert(!ribi::Chess::Move::ParseIsCheck("Ba2xb3#"));
  assert(!ribi::Chess::Move::ParseIsCheck("O-O"));
  assert(!ribi::Chess::Move::ParseIsCheck("O-O-O"));
  assert(!ribi::Chess::Move::ParseIsCheck("0-0"));
  assert(!ribi::Chess::Move::ParseIsCheck("0-0-0"));
  assert(!ribi::Chess::Move::ParseIsCheck("O-O#"));
  assert(!ribi::Chess::Move::ParseIsCheck("O-O-O#"));
  assert(!ribi::Chess::Move::ParseIsCheck("0-0#"));
  assert(!ribi::Chess::Move::ParseIsCheck("0-0-0#"));

  if (verbose) { TRACE("Testing valid moves that result in checkmate"); }
  assert(ribi::Chess::Move::ParseIsCheckmate("a3#"));
  assert(ribi::Chess::Move::ParseIsCheckmate("a2 a3#"));
  assert(ribi::Chess::Move::ParseIsCheckmate("a2xb3#"));
  assert(ribi::Chess::Move::ParseIsCheckmate("Ba3#"));
  assert(ribi::Chess::Move::ParseIsCheckmate("Ba2 b3#"));
  assert(ribi::Chess::Move::ParseIsCheckmate("Ba2xb3#"));
  assert(ribi::Chess::Move::ParseIsCheckmate("O-O#"));
  assert(ribi::Chess::Move::ParseIsCheckmate("O-O-O#"));
  assert(ribi::Chess::Move::ParseIsCheckmate("0-0#"));
  assert(ribi::Chess::Move::ParseIsCheckmate("0-0-0#"));
  assert(!ribi::Chess::Move::ParseIsCheckmate("a2 a3"));
  assert(!ribi::Chess::Move::ParseIsCheckmate("a2xb3"));
  assert(!ribi::Chess::Move::ParseIsCheckmate("Ba3"));
  assert(!ribi::Chess::Move::ParseIsCheckmate("Ba2 b3"));
  assert(!ribi::Chess::Move::ParseIsCheckmate("Ba2xb3"));
  assert(!ribi::Chess::Move::ParseIsCheckmate("a2 a3+"));
  assert(!ribi::Chess::Move::ParseIsCheckmate("a2xb3+"));
  assert(!ribi::Chess::Move::ParseIsCheckmate("Ba3+"));
  assert(!ribi::Chess::Move::ParseIsCheckmate("Ba2 b3+"));
  assert(!ribi::Chess::Move::ParseIsCheckmate("Ba2xb3+"));
  assert(!ribi::Chess::Move::ParseIsCheckmate("O-O"));
  assert(!ribi::Chess::Move::ParseIsCheckmate("O-O-O"));
  assert(!ribi::Chess::Move::ParseIsCheckmate("0-0"));
  assert(!ribi::Chess::Move::ParseIsCheckmate("0-0-0"));
  assert(!ribi::Chess::Move::ParseIsCheckmate("O-O+"));
  assert(!ribi::Chess::Move::ParseIsCheckmate("O-O-O+"));
  assert(!ribi::Chess::Move::ParseIsCheckmate("0-0+"));
  assert(!ribi::Chess::Move::ParseIsCheckmate("0-0-0+"));

  if (verbose) { TRACE("Testing valid en passant moves"); }
  {
    const std::vector<std::string> v = Moves::GetValidEnPassantMoves();
    std::for_each(v.begin(),v.end(),
      [](const std::string& s)
      {
        assert(ribi::Chess::Move::ParseIsEnPassant(s));
      }
    );
  }

  if (verbose) { TRACE("Testing invalid en passant moves"); }
  {
    const std::vector<std::string> v = Moves::GetInvalidEnPassantMoves();
    std::for_each(v.begin(),v.end(),
      [](const std::string& s)
      {
        if (ribi::Chess::Move::ParseIsEnPassant(s)) TRACE(s);
        assert(!ribi::Chess::Move::ParseIsEnPassant(s));
      }
    );
  }


  if (verbose) { TRACE("Testing valid moves that end in a promotion"); }
  {
    const std::vector<std::string> v = Moves::GetValidPromotionMoves();
    std::for_each(v.begin(),v.end(),
      [](const std::string& s)
      {
        assert(ribi::Chess::Move::ParseIsPromotion(s));
      }
    );
  }
  if (verbose) { TRACE("Testing ParseTo"); }

  ///Test parsing of the square the piece is moving to
  assert((*Move::ParseTo("a2 a3")==*SquareFactory().Create(Chess::File("a"),Chess::Rank("3"))));
  assert((*Move::ParseTo(   "a3")==*SquareFactory().Create(Chess::File("a"),Chess::Rank("3"))));
  assert((*Move::ParseTo("Bb3 c5")==*SquareFactory().Create(Chess::File("c"),Chess::Rank("5"))));
  assert((*Move::ParseTo("Kc4 d4")==*SquareFactory().Create(Chess::File("d"),Chess::Rank("4"))));
  assert((*Move::ParseTo("Nd5 e6")==*SquareFactory().Create(Chess::File("e"),Chess::Rank("6"))));
  assert((*Move::ParseTo("Qe6 f7")==*SquareFactory().Create(Chess::File("f"),Chess::Rank("7"))));
  assert((*Move::ParseTo("Rf7 h7")==*SquareFactory().Create(Chess::File("h"),Chess::Rank("7"))));
  assert(!ribi::Chess::Move::ParseTo("0-0"));
  assert(!ribi::Chess::Move::ParseTo("0-0+"));
  assert(!ribi::Chess::Move::ParseTo("0-0#"));
  assert(!ribi::Chess::Move::ParseTo("O-O"));

  assert(!ribi::Chess::Move::ParseTo("O-O+"));
  assert(!ribi::Chess::Move::ParseTo("O-O#"));
  assert(!ribi::Chess::Move::ParseTo("0-0-0"));
  assert(!ribi::Chess::Move::ParseTo("0-0-0+"));
  assert(!ribi::Chess::Move::ParseTo("0-0-0#"));
  assert(!ribi::Chess::Move::ParseTo("O-O-O"));
  assert(!ribi::Chess::Move::ParseTo("O-O-O+"));
  assert(!ribi::Chess::Move::ParseTo("O-O-O#"));

  if (verbose) { TRACE("Testing ParsePiece"); }
  assert(ribi::Chess::Move::ParsePiece("Ba1 b2")->GetNameChar() == 'B');
  assert(ribi::Chess::Move::ParsePiece("Ka1 b1")->GetNameChar() == 'K');
  assert(ribi::Chess::Move::ParsePiece("Na1 b3")->GetNameChar() == 'N');
  assert(ribi::Chess::Move::ParsePiece("Qa1 b1")->GetNameChar() == 'Q');
  assert(ribi::Chess::Move::ParsePiece("Ra1 b1")->GetNameChar() == 'R');
  assert(ribi::Chess::Move::ParsePiece("a2 a4")->GetNameChar() == '.');

  #ifdef FIX_ISSUE_240
  try
  {
    const auto piece(Chess::Move("0-0").Piece());
    assert(!"Should not get here");
  }
  catch (std::logic_error&)
  {
    //OK
  }
  try
  {
    const auto piece(Chess::Move("O-O-O").Piece());
    assert(!"Should not get here");
  }
  catch (std::logic_error&)
  {
    //OK
  }
  #endif // FIX_ISSUE_240

  if (verbose) { TRACE("Test complete moves for validity"); }
  //Test valid moves being valid as a move: the history of the chessgame must point out
  //if the move is valid in its context
  {
    const std::vector<std::string> v
     = {
      "a2 a3", "a2 a4", "a3 a4", "a4 a5", "a5 a6", "a6 a7", //white pawn at A file all its movements without promotion
      "a2xb3", "a3xb4", "a4xb5", "a5xb6", "a6xb7",          //white pawn at A file all its captures without promotion
      "a7 a6", "a7 a5", "a6 a5", "a5 a4", "a4 a3", "a3 a2", //black pawn at A file all its movements without promotion
      //Short notation
      #ifdef RIBI_CHESS_ALLOW_SHORT_NOTATION
      "a2", "a3", "a4", "a4", "a5", "a6", "a7", //pawn at A file all its movements without promotion
      "b2", "b3", "b4", "b4", "b5", "b6", "b7", //pawn at B file all its movements without promotion
      "c2", "c3", "c4", "c4", "c5", "c6", "c7", //pawn at C file all its movements without promotion
      "d2", "d3", "d4", "d4", "d5", "d6", "d7", //pawn at D file all its movements without promotion
      "e2", "e3", "e4", "e4", "e5", "e6", "e7", //pawn at E file all its movements without promotion
      "f2", "f3", "f4", "f4", "f5", "f6", "f7", //pawn at F file all its movements without promotion
      "g2", "g3", "g4", "g4", "g5", "g6", "g7", //pawn at G file all its movements without promotion
      "h2", "h3", "h4", "h4", "h5", "h6", "h7", //pawn at H file all its movements without promotion
      #endif
      "O-O","O-O-O","0-0","0-0-0",     //Castling
      "O-O+","O-O-O+","0-0+","0-0-0+", //Castling
      "O-O#","O-O-O#","0-0#","0-0-0#", //Castling
      "1-0","0-1","1/2-1/2"

    };
    std::for_each(v.begin(),v.end(),
      [](const std::string& s)
      {
        try
        {
          Chess::Move m(s);
        }
        catch (std::exception& e)
        {
          TRACE(s);
          TRACE(e.what());
          assert(!"Should not get here");
        }
      }
    );
  }
  //Test invalid moves being invalid
  {
    std::vector<std::string> v
     =
      {
        "B0-0" , "B0-0-0", "BO-O", "BO-O-O",
        "B0-0+", "B0-0-0+", "BO-O+", "BO-O-O+",
        "B0-0#", "B0-0-0#", "BO-O#", "BO-O-O#"
        //"ND4xe6"
      };
    std::for_each(v.begin(),v.end(),
      [](const std::string& s)
      {
        try
        {
          Chess::Move m(s);
          TRACE(s);
          TRACE(m.ToStr());
          assert(!"Should not get here");
        }
        catch (std::exception& e)
        {
          //OK
        }
      }
    );
  }
  #ifdef FIX_ISSUE_240
  if (verbose) { TRACE("Test complete moves intimately"); }
  {
    const Chess::Move m("a3");
    assert(!m.From()); //From is unknown
    assert(!m.IsCapture());
    assert(!m.IsCastling());
    assert(!m.IsCheck());
    assert(!m.IsCheckmate());
    assert(!m.IsPromotion());
    assert(m.Piece());
    assert(dynamic_cast<Chess::PiecePawn*>(m.Piece().get()));
    assert(!m.PiecePromotion());
    assert((*m.To().get()==*SquareFactory().Create("a3")));
  }

  if (verbose) { TRACE("Test Kasparov against the world match"); }
  {
    const std::vector<std::string> v = Chess::Moves::GetGameKasparovVersusTheWorld();
    std::for_each(v.begin(),v.end(),
      [](const std::string& s)
      {
        try
        {
          //TRACE(s);
          Chess::Move m(s);
        }
        catch (std::exception& e)
        {
          TRACE(s);
          TRACE(e.what());
          assert(!"Should not get here");
        }
      }
    );
  }
  #endif // FIX_ISSUE_240
}
#endif

 

 

 

 

 

./CppChess/chesspiece.h

 

#ifndef RIBI_CHESSPIECE_H
#define RIBI_CHESSPIECE_H

#include <vector>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"

#include <boost/checked_delete.hpp>
#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>

#include "chesscolor.h"
#include "chessfwd.h"
//#include "chesssquare.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace Chess {

//A Piece has
//- a (possibly undetermined) position
//- a (possibly undetermined) color
struct Piece
{
  virtual ~Piece() noexcept {}

  ///Determines if this Piece can possibly do this move
  bool CanDoMove(const boost::shared_ptr<const Move>& move) const noexcept { return CanDoMove(move.get()); }
  virtual bool CanDoMove(const Move * const move) const noexcept = 0;

  ///Perform a Move on a Piece
  void DoMove(const boost::shared_ptr<const Move> move);

  ///Obtain the (possibily indeterminate) Color of a Piece
  Color GetColor() const noexcept;

  ///Obtain the last move this Piece did.
  boost::shared_ptr<const Move> GetLastMove() const noexcept { return m_last_move; }

  ///Returns all Moves to be done by a Piece.
  ///These moves are all valid (for example, on an empty board), but might be invalid in the current chessgame.
  virtual std::vector<boost::shared_ptr<Move>> GetMoves() const noexcept = 0;

  ///Obtain the Square the piece is standing on
  boost::shared_ptr<const Square> GetSquare() const noexcept;

  ///Convert a Piece type to a its full name, e.g. 'knight'
  virtual std::string GetName() const noexcept = 0;

  ///Convert a Piece type to a its notational character, e.g 'N'
  virtual char GetNameChar() const noexcept = 0;

  ///Returns the color and symbol
  //const std::pair<char,char> GetSymbol() const;

  ///Obtain the version of this class
  static std::string GetVersion() noexcept;

  ///Obtain the version history of this class
  static std::vector<std::string> GetVersionHistory() noexcept;

  #ifndef NDEBUG
  ///Test all Pieces
  static void Test() noexcept;
  #endif

  ///Convert a Piece to std::string for operator<<
  std::string ToStr() const noexcept;

  protected:

  Piece(
    const Color color,
    const boost::shared_ptr<const Square>& square);

  ///Triple number of moves by adding check and checkmate
  static const std::vector<boost::shared_ptr<Move>> AddCheckAndCheckmate(const std::vector<boost::shared_ptr<Move>>& v);

  ///Clone a Piece
  virtual boost::shared_ptr<Piece> Clone() const = 0;

  private:

  ///The piece its color
  const Color m_color;

  ///The last move this Piece did.
  boost::shared_ptr<const Move> m_last_move;

  ///The piece its location
  boost::shared_ptr<const Square> m_square;

  friend void boost::checked_delete<>(Piece *);
};

struct PieceBishop : public Piece
{
  ///Determines if this Piece can possibly do this move
  bool CanDoMove(const Move* const move) const noexcept;

  std::vector<boost::shared_ptr<Move>> GetMoves() const noexcept;

  ///Convert a Piece type to a its notational character, e.g 'N'
  char GetNameChar() const noexcept { return 'B'; }

  ///Convert a Piece type to a its full name, e.g. 'knight'
  std::string GetName() const noexcept { return "bishop"; }

  #ifndef NDEBUG
  ///Test Bishop
  static void Test() noexcept;
  #endif

  ///Convert a Piece to std::string for operator<<
  std::string ToStr() const noexcept;

  private:
  PieceBishop(
    const Color color,
    const boost::shared_ptr<const Square> square,
    const PieceFactory& lock
  );
  PieceBishop(const PieceBishop&) = delete;
  PieceBishop& operator=(const PieceBishop&) = delete;

  ///Clone this Piece
  boost::shared_ptr<Piece> Clone() const;

  ~PieceBishop() noexcept {}

  friend void boost::checked_delete<>(PieceBishop *);
  friend struct PieceFactory;

  //Cannot get these to compile
  //friend boost::shared_ptr<      PieceBishop> boost::make_shared<      PieceBishop>(const Color color,const boost::shared_ptr<const Square> square);
  //friend boost::shared_ptr<const PieceBishop> boost::make_shared<const PieceBishop>(const Color color,const boost::shared_ptr<const Square> square);

  //Keep these for possible `reference
  //friend class boost::detail::sp_ms_deleter<PieceBishop>;
  //friend class boost::detail::sp_ms_deleter<const PieceBishop>;

};

struct PieceKing : public Piece
{

  ///Determines if this Piece can possibly do this move
  bool CanDoMove(const Move* const move) const noexcept;

  std::vector<boost::shared_ptr<Move>> GetMoves() const noexcept;
  //void Move(const Square& to);

  ///Convert a Piece type to a its notational character, e.g 'N'
  char GetNameChar() const noexcept { return 'K'; }

  ///Convert a Piece type to a its full name, e.g. 'knight'
  std::string GetName() const noexcept { return "king"; }

  #ifndef NDEBUG
  ///Test PieceKing
  static void Test() noexcept;
  #endif

  ///Convert a Piece to std::string for operator<<
  std::string ToStr() const noexcept;

  private:
  PieceKing(
    const Color color,
    const boost::shared_ptr<const Square> square,
    const PieceFactory& lock
  );

  ///Clone this Piece
  boost::shared_ptr<Piece> Clone() const;

  ~PieceKing() noexcept {}

  friend void boost::checked_delete<>(PieceKing *);

  ///Keep track of whether king has moved for castling
  bool m_has_moved;

  friend struct PieceFactory;
};

struct PieceKnight : public Piece
{
  ///Determines if this Piece can possibly do this move
  bool CanDoMove(const Move* const move) const noexcept;


  ///Returns all Moves to be done by a Piece.
  ///These moves are all valid, but might be invalid in the current chessgame.
  std::vector<boost::shared_ptr<Move>> GetMoves() const noexcept;

  char GetNameChar() const noexcept { return 'N'; }

  ///Convert a Piece type to a its full name, e.g. 'knight'
  std::string GetName() const noexcept { return "knight"; }

  #ifndef NDEBUG
  ///Test PieceKnight
  static void Test() noexcept;
  #endif

  ///Convert a Piece to std::string for operator<<
  std::string ToStr() const noexcept;

  private:
  PieceKnight(
    const Color color,
    const boost::shared_ptr<const Square> square,
    const PieceFactory& lock
  );

  ///Clone this Piece
  boost::shared_ptr<Piece> Clone() const;

  ~PieceKnight() noexcept {}
  friend void boost::checked_delete<>(PieceKnight *);
  friend struct PieceFactory;
};

struct PiecePawn : public Piece
{
  ///Determines if this Piece can possibly do this move
  bool CanDoMove(const Move* const move) const noexcept;

  std::vector<boost::shared_ptr<Move>> GetMoves() const noexcept;
  char GetNameChar() const noexcept { return '.'; }

  ///Convert a Piece type to a its full name, e.g. 'knight'
  std::string GetName() const noexcept { return "pawn"; }

  #ifndef NDEBUG
  ///Test PiecePawn
  static void Test() noexcept;
  #endif

  ///Convert a Piece to std::string for operator<<
  std::string ToStr() const noexcept;

  private:
  PiecePawn(
    const Color color,
    const boost::shared_ptr<const Square> square,
    const PieceFactory& lock
  );

  ///Clone this Piece
  boost::shared_ptr<Piece> Clone() const;

  ~PiecePawn() noexcept {}

  friend void boost::checked_delete<>(PiecePawn *);
  friend struct PieceFactory;
};

struct PieceQueen : public Piece
{
  ///Determines if this Piece can possibly do this move
  bool CanDoMove(const Move* const move) const noexcept;

  std::vector<boost::shared_ptr<Move>> GetMoves() const noexcept;
  char GetNameChar() const noexcept { return 'Q'; }

  ///Convert a Piece type to a its full name, e.g. 'king'
  std::string GetName() const noexcept { return "queen"; }

  #ifndef NDEBUG
  ///Test PieceQueen
  static void Test() noexcept;
  #endif

  ///Convert a Piece to std::string for operator<<
  std::string ToStr() const noexcept;

  private:

  PieceQueen(
    const Color color,
    const boost::shared_ptr<const Square> square,
    const PieceFactory& lock
  );

  ///Clone this Piece
  boost::shared_ptr<Piece> Clone() const;

  ~PieceQueen() noexcept {}
  friend void boost::checked_delete<>(PieceQueen *);
  friend struct PieceFactory;
};

struct PieceRook : public Piece
{
  ///Determines if this Piece can possibly do this move
  bool CanDoMove(const Move* const move) const noexcept;

  std::vector<boost::shared_ptr<Move>> GetMoves() const noexcept;

  char GetNameChar() const noexcept { return 'R'; }

  ///Convert a Piece type to a its full name, e.g. 'king'
  std::string GetName() const noexcept { return "rook"; }

  #ifndef NDEBUG
  static void Test() noexcept;
  #endif

  ///Convert a Piece to std::string for operator<<
  std::string ToStr() const noexcept;

  private:
  PieceRook(
    const Color color,
    const boost::shared_ptr<const Square> square,
    const PieceFactory& lock
  );

  ///Clone this Piece
  boost::shared_ptr<Piece> Clone() const;

  ~PieceRook() noexcept {}
  friend void boost::checked_delete<>(PieceRook *);

  ///Keep track of whether rook has moved for castling
  bool m_has_moved;

  friend struct PieceFactory;
};


bool operator==(const Piece& lhs, const Piece& rhs);
bool operator!=(const Piece& lhs, const Piece& rhs);
std::ostream& operator<<(std::ostream& os, const Piece& piece);

} //~namespace Chess
} //~namespace ribi

#endif // RIBI_CHESSPIECE_H

 

 

 

 

 

./CppChess/chesspiece.cpp

 

#include "chesspiece.h"

#include <cassert>
#include <iostream>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include <boost/lexical_cast.hpp>
#include <boost/make_shared.hpp>

#include "chesscolor.h"
#include "chessmove.h"
#include "chessmovefactory.h"
#include "chessmoves.h"
#include "chesspiecefactory.h"
#include "chesssquarefactory.h"
#include "chessrank.h"
#include "chesssquare.h"

#include "trace.h"
#pragma GCC diagnostic pop

ribi::Chess::Piece::Piece(
  const Color color,
  const boost::shared_ptr<const Square> &square)
: m_color(color),
   m_last_move{},
   m_square(square)
{
  #ifndef NDEBUG
  ribi::Chess::Piece::Test();
  #endif
}

const std::vector<boost::shared_ptr<ribi::Chess::Move>>
  ribi::Chess::Piece::AddCheckAndCheckmate(const std::vector<boost::shared_ptr<Move>>& v)
{
  std::vector<boost::shared_ptr<Move>> w;
  std::for_each(v.begin(),v.end(),
    [&w](const boost::shared_ptr<Move>& move)
    {
      assert(move);
      assert(!move->IsCheck());
      assert(!move->IsCheckmate());
      //assert(!move->IsScore());
      w.push_back(move);
      {
        const boost::shared_ptr<Move> m = MoveFactory().Create(
          move->ToStr() + "+"
        );
        assert(m);
        w.push_back(m);
      }
      {
        const boost::shared_ptr<Move> m = MoveFactory().Create(
          move->ToStr() + "#"
        );
        assert(m);
        w.push_back(m);
      }
    }
  );
  assert(w.size() == v.size() * 3);
  return w;
}

void ribi::Chess::Piece::DoMove(const boost::shared_ptr<const Move> move)
{
  assert(CanDoMove(move));
  m_square = move->To();
  m_last_move = move;
}

ribi::Chess::Color ribi::Chess::Piece::GetColor() const noexcept
{
  return m_color;
}

boost::shared_ptr<const ribi::Chess::Square> ribi::Chess::Piece::GetSquare() const noexcept
{
  return m_square;
}

std::string ribi::Chess::Piece::GetVersion() noexcept
{
  return "1.0";
}

std::vector<std::string> ribi::Chess::Piece::GetVersionHistory() noexcept
{
  return {
    "2012-01-25: version 1.0: initial version"
  };
}

std::string ribi::Chess::Piece::ToStr() const noexcept
{
  return Chess::ColorToStr(GetColor())
    + " "
    + this->GetName()
    + " at "
    + (this->GetSquare() ? this->GetSquare()->ToStr() : "an indetermined position");
}

ribi::Chess::PieceBishop::PieceBishop(
  const Color color,
  const boost::shared_ptr<const Square> square,
  const PieceFactory&
)
  : Piece(color,square)
{
  //assert(GetColor() != Color::indeterminate);
}

bool ribi::Chess::PieceBishop::CanDoMove(const Chess::Move * const move) const noexcept
{
  if (!move->Piece() || !dynamic_cast<PieceBishop*>(move->Piece().get()))
  {
    //Not a Bishop move
    return false;
  }
  /*
  #ifndef NDEBUG
  if(!
    (
         (!move->From() && !GetSquare())
      || (move->From() && !GetSquare())
      || (move->From() && GetSquare() && *move->From() == *this->GetSquare()  )
    )
  )
  {
    TRACE(move);
    TRACE(move->From());
    TRACE(GetSquare());
    if (move->From()) TRACE(*move->From());
    if (GetSquare()) TRACE(*GetSquare());
    TRACE("BREAK");
  }
  #endif
  assert(
    (
         (!move->From() && !GetSquare())
      || (move->From() && !GetSquare())
      || (move->From() && GetSquare() && *move->From() == *this->GetSquare()  )
    )
    && "Assume Move and Bishop to have the same start position");
  */
  assert(move->Piece() && dynamic_cast<PieceBishop*>(move->Piece().get())
    && "Assume this is a Bishop move");
  assert(move->To() && "All Bishop moves have a to field");
  assert(!move->IsCastling() && "Bishop moves are not castling moves");
  assert(!move->Score() && "Bishop moves are not final scores");


  if (move->From())
  {
    const int dx = move->From()->GetFile().ToInt() - move->To()->GetFile().ToInt();
    if (dx == 0) return false;
    const int dy = move->From()->GetRank().ToInt() - move->To()->GetRank().ToInt();
    return std::abs(dx) == std::abs(dy);
  }
  else
  {
    return move->To().get();
  }
}

boost::shared_ptr<ribi::Chess::Piece> ribi::Chess::PieceBishop::Clone() const
{
  const auto p = PieceFactory().Create(GetNameChar(),GetColor(),GetSquare());
  assert(p);
  assert(*p       == *this && "Must be a copy");
  assert( p.get() !=  this && "Must be a deep copy");
  return p;
}

std::vector<boost::shared_ptr<ribi::Chess::Move>> ribi::Chess::PieceBishop::GetMoves() const noexcept
{
  std::vector<boost::shared_ptr<Move>> v;
  for (int i=1; i!=8; ++i)
  {
    //North-east
    try
    {
      const boost::shared_ptr<Square> s = SquareFactory().Create(
        Chess::File(this->GetSquare()->GetFile().ToInt() + i),
        Chess::Rank(this->GetSquare()->GetRank().ToInt() - i)
      );
      {
        const boost::shared_ptr<Move> m = MoveFactory().Create(
          boost::lexical_cast<std::string>(this->GetNameChar()) + this->GetSquare()->ToStr() + " " + s->ToStr()
        );
        v.push_back(m);
      }
      {
        const boost::shared_ptr<Move> m = MoveFactory().Create(
          boost::lexical_cast<std::string>(this->GetNameChar()) + this->GetSquare()->ToStr() + "x" + s->ToStr()
        );
        assert(m);
        v.push_back(m);
      }
      {
        const boost::shared_ptr<Move> m = MoveFactory().Create(
          boost::lexical_cast<std::string>(this->GetNameChar()) + this->GetSquare()->ToStr() + " " + s->ToStr() + "+"
        );
        assert(m);
        v.push_back(m);
      }
      {
        const boost::shared_ptr<Move> m = MoveFactory().Create(
          boost::lexical_cast<std::string>(this->GetNameChar()) + this->GetSquare()->ToStr() + "x" + s->ToStr() + "+"
        );
        assert(m);
        v.push_back(m);
      }
      {
        const boost::shared_ptr<Move> m = MoveFactory().Create(
          boost::lexical_cast<std::string>(this->GetNameChar()) + this->GetSquare()->ToStr() + " " + s->ToStr() + "#"
        );
        assert(m);
        v.push_back(m);
      }
      {
        const boost::shared_ptr<Move> m = MoveFactory().Create(
          boost::lexical_cast<std::string>(this->GetNameChar()) + this->GetSquare()->ToStr() + "x" + s->ToStr() + "#"
        );
        assert(m);
        v.push_back(m);
      }
    }
    catch (std::exception& e)
    {
      //No problem
    }
    //South-east
    try
    {
      const boost::shared_ptr<Square> s = SquareFactory().Create(
        Chess::File(this->GetSquare()->GetFile().ToInt() + i),
        Chess::Rank(this->GetSquare()->GetRank().ToInt() + i)
      );
      const boost::shared_ptr<Move> m = MoveFactory().Create(boost::lexical_cast<std::string>(this->GetNameChar()) + this->GetSquare()->ToStr() + " " + s->ToStr());
      assert(m);
      v.push_back(m);
    }
    catch (std::exception& e)
    {
      //No problem
    }
    //South-west
    try
    {
      const boost::shared_ptr<Square> s = SquareFactory().Create(
        Chess::File(this->GetSquare()->GetFile().ToInt() - i),
        Chess::Rank(this->GetSquare()->GetRank().ToInt() + i));
      const boost::shared_ptr<Move> m = MoveFactory().Create(boost::lexical_cast<std::string>(this->GetNameChar()) + this->GetSquare()->ToStr() + " " + s->ToStr());
      v.push_back(m);
    }
    catch (std::exception& e)
    {
      //No problem
    }
    //North-west
    try
    {
      const boost::shared_ptr<Square> s = SquareFactory().Create(
        Chess::File(this->GetSquare()->GetFile().ToInt() - i),
        Chess::Rank(this->GetSquare()->GetRank().ToInt() - i)
      );
      const boost::shared_ptr<Move> m = MoveFactory().Create(boost::lexical_cast<std::string>(this->GetNameChar()) + this->GetSquare()->ToStr() + " " + s->ToStr());
      v.push_back(m);
    }
    catch (std::exception& e)
    {
      //No problem
    }

  }
  //Triple number of moves by adding check and checkmate
  v = AddCheckAndCheckmate(v);

  return v;
}

/*
PieceEmpty::PieceEmpty()
  : Piece(Color::indeterminate,Square(0,0))
{
  assert(GetColor() == Color::indeterminate);
}

const std::vector<Square> PieceEmpty::GetMoves() const
{
  return std::vector<Square>();
}

bool PieceEmpty::CanDoMove(const boost::shared_ptr<const Chess::Move> move) const
{

}
*/

ribi::Chess::PieceKing::PieceKing(
  const Color color,
  const boost::shared_ptr<const Square> square,
  const PieceFactory&
)
  : Piece(color,square),
    m_has_moved{false}

{
  //assert(GetColor() != Color::indeterminate);

}

bool ribi::Chess::PieceKing::CanDoMove(const Chess::Move * const move) const noexcept
{
  if (!move->Piece() || !dynamic_cast<PieceKing*>(move->Piece().get()))
  {
    //Not a King move
    return false;
  }
  assert(
    (
         (!move->From() && !GetSquare())
      || (move->From() && !GetSquare())
      || (move->From() && GetSquare() && *move->From() == *this->GetSquare())
    )
    && "Assume Move and Piece to have the same start position");
  assert(move->Piece() && dynamic_cast<Piece*>(move->Piece().get())
    && "Assume this is a King move");
  assert(move->To() && "All King moves have a to field");
  assert(!move->IsCastling() && "King moves are not castling moves");
  assert(!move->Score() && "King moves are not final scores");

  if (move->From())
  {
    const int dx = move->From()->GetFile().ToInt() - move->To()->GetFile().ToInt();
    const int dy = move->From()->GetRank().ToInt() - move->To()->GetRank().ToInt();

    if (dx == 0 && dy == 0) return false;
    return std::abs(dx) <= 1 && std::abs(dy) <= 1;
  }
  else
  {
    return move->To().get();
  }
}

boost::shared_ptr<ribi::Chess::Piece> ribi::Chess::PieceKing::Clone() const
{
  //const boost::shared_ptr<Piece> p(new PieceKing(*this));
  const auto p = PieceFactory().Create(GetNameChar(),GetColor(),GetSquare());
  assert(p);
  assert(*p == *this && "Must be a copy");
  assert( p.get() !=  this && "Must be a deep copy");
  return p;
}

std::vector<boost::shared_ptr<ribi::Chess::Move>> ribi::Chess::PieceKing::GetMoves() const noexcept
{
  std::vector<boost::shared_ptr<Move>> v;
  std::vector<std::pair<int,int>> ds
    = { {0,-1}, {1,-1}, {1,0}, {1,1}, {0,1}, {-1,1}, {-1,0}, {-1,-1} };
  std::for_each(ds.begin(), ds.end(),
    [&v,this](const std::pair<int,int>& p)
    {
      try
      {
        const boost::shared_ptr<Square> s = SquareFactory().Create(
          Chess::File(this->GetSquare()->GetFile().ToInt() + p.first),
          Chess::Rank(this->GetSquare()->GetRank().ToInt() + p.second)
        );

        boost::shared_ptr<Move> m = MoveFactory().Create(
          boost::lexical_cast<std::string>(this->GetNameChar())
          + this->GetSquare()->ToStr()
          + " "
          + s->ToStr());
        v.push_back(m);
      }
      catch (std::exception& e)
      {
        //No problem
      }
    }
  );
  //Triple number of moves by adding check and checkmate
  v = AddCheckAndCheckmate(v);
  return v;
}

ribi::Chess::PieceKnight::PieceKnight(
  const Chess::Color color,
  const boost::shared_ptr<const Square> square,
  const PieceFactory&
)
  : Piece(color,square)
{
  //assert(GetColor() != Color::indeterminate);

}

bool ribi::Chess::PieceKnight::CanDoMove(const Chess::Move * const move) const noexcept
{
  if (!move->Piece() || !dynamic_cast<PieceKnight*>(move->Piece().get()))
  {
    //Not a Knight move
    return false;
  }
  assert(
    (
         (!move->From() && !GetSquare())
      || (move->From() && !GetSquare())
      || (move->From() && GetSquare() && (*move->From() == *this->GetSquare()))
    )
    && "Assume Move and Knight to have the same start position");
  assert(move->Piece() && dynamic_cast<PieceKnight*>(move->Piece().get())
    && "Assume this is a Knight move");
  assert(move->To() && "All Knight moves have a to field");
  assert(!move->IsCastling() && "Knight moves are not castling moves");
  assert(!move->Score() && "Knight moves are not final scores");

  if (move->From())
  {
    const int dx = move->From()->GetFile().ToInt() - move->To()->GetFile().ToInt();
    const int dy = move->From()->GetRank().ToInt() - move->To()->GetRank().ToInt();
    return
         (std::abs(dx) == 1 || std::abs(dx) == 2)
      && (std::abs(dy) == 1 || std::abs(dy) == 2)
      &&  std::abs(dx) != std::abs(dy);
  }
  else
  {
    return true;
  }
}

boost::shared_ptr<ribi::Chess::Piece> ribi::Chess::PieceKnight::Clone() const
{
  //const boost::shared_ptr<Piece> p(new PieceKnight(*this));
  const auto p = PieceFactory().Create(GetNameChar(),GetColor(),GetSquare());
  assert(p);
  assert(*p == *this && "Must be a copy");
  assert( p.get() !=  this && "Must be a deep copy");
  return p;
}

std::vector<boost::shared_ptr<ribi::Chess::Move>> ribi::Chess::PieceKnight::GetMoves() const noexcept
{
  std::vector<boost::shared_ptr<Move>> v;
  std::vector<std::pair<int,int>> ds
    = { {1,2}, {2,1}, {-1,2}, {-2,1}, {1,-2}, {2,-1}, {-1,-2}, {-2,-1} };
  std::for_each(ds.begin(), ds.end(),
    [&v,this](const std::pair<int,int>& p)
    {
      try
      {
        const boost::shared_ptr<Square> s = SquareFactory().Create(
          Chess::File(this->GetSquare()->GetFile().ToInt() + p.first),
          Chess::Rank(this->GetSquare()->GetRank().ToInt() + p.second)
        );

        boost::shared_ptr<Move> m = MoveFactory().Create(
          boost::lexical_cast<std::string>(this->GetNameChar())
          + this->GetSquare()->ToStr()
          + " "
          + s->ToStr());
        v.push_back(m);
      }
      catch (std::exception& e)
      {
        //No problem
      }
    }
  );
  //Triple number of moves by adding check and checkmate
  v = AddCheckAndCheckmate(v);
  return v;
}

ribi::Chess::PiecePawn::PiecePawn(
  const Color color,
  const boost::shared_ptr<const Square> square,
  const PieceFactory&
)
  : Piece(color,square)
{
  //assert(GetColor() != Color::indeterminate);
}

bool ribi::Chess::PiecePawn::CanDoMove(const Chess::Move * const move) const noexcept
{
  if (!move->Piece() || !dynamic_cast<PiecePawn*>(move->Piece().get()))
  {
    //Not a Pawn move
    return false;
  }

  if (!(
    (
         (!move->From() && !GetSquare())
      || (move->From() && !GetSquare())
      || (move->From() && GetSquare() && (*move->From() == *this->GetSquare()))
    )))
  {
    TRACE(move);
    TRACE(move->From());
    TRACE(GetSquare());
    TRACE("BREAK");
  }

  assert(
    (
         (!move->From() && !GetSquare())
      || (move->From() && !GetSquare())
      || (move->From() && GetSquare() && (*move->From() == *this->GetSquare()))
    )
    && "Assume Move and PiecePawn to have the same start position");
  assert(move->Piece() && dynamic_cast<PiecePawn*>(move->Piece().get())
    && "Assume this is a Pawn move");
  assert(move->To() && "All Pawn moves have a to field");
  assert(!move->IsCastling() && "Pawn moves are not castling moves");
  assert((!move->IsEnPassant() || (move->IsEnPassant() && move->IsCapture()))
    && "Assume that all en passant captures are captures");

  //Do all checks when the 'from' Square is known
  if (move->From())
  {
    const int dx = move->To()->GetFile().ToInt() - move->From()->GetFile().ToInt();
    if (std::abs(dx) > 1) return false;
    if (std::abs(dx) == 1 && !move->IsCapture()) return false;
    if (dx == 0 && move->IsCapture()) return false;

    const int dy = move->To()->GetRank().ToInt() - move->From()->GetRank().ToInt();
    if (std::abs(dy) > 2) return false; //A pawn move two squares at most

    if (this->GetColor() == Color::white)
    {
      if (dy <= 0) return false; //A white pawn must move forward
      if (move->From()->GetRank() == Rank("2") && dy == 2) return true;
      if (!(move->From()->GetRank() == Rank("2")) && dy == 2) return false;
      return dy == 1;
    }
    else if (this->GetColor() == Color::black)
    {
      if (dy >= 0) return false; //A black pawn must move backward in the y direction
      if (move->From()->GetRank() == Rank("7") && dy == -2) return true;
      if (!(move->From()->GetRank() == Rank("7")) && dy == -2) return false;
      return dy == -1;
    }
    else if (this->GetColor() == Color::indeterminate)
    {
      if (move->From()->GetRank() == Rank("2") && dy ==  2) return true;
      if (move->From()->GetRank() == Rank("7") && dy == -2) return true;
      if (!(move->From()->GetRank() == Rank("2")) && dy ==  2) return false;
      if (!(move->From()->GetRank() == Rank("7")) && dy == -2) return false;
    }
  }

  if (move->IsEnPassant())
  {
    if (!move->IsCapture()) return false;
    if (GetColor() == Color::indeterminate)
    {
      return
        (move->From()->GetRank().ToStr() == "4"
          && move->To()->GetRank().ToStr() == "3")
        || ( move->From()->GetRank().ToStr() == "5"
          && move->To()->GetRank().ToStr() == "6");
    }
    if (GetColor() == Color::white)
    {
      return ( move->From()->GetRank().ToStr() == "5"
          && move->To()->GetRank().ToStr() == "6");
    }
    if (GetColor() == Color::black)
    {
      return move->From()->GetRank().ToStr() == "4"
          && move->To()->GetRank().ToStr() == "3";
    }
  }

  //Pawn moves in the right direction when from is known
  if (this->GetColor() == Color::white && move->To()->GetRank() == Chess::Rank("1"))
  {
    return false;
  }
  if (this->GetColor() == Color::black && move->To()->GetRank() == Chess::Rank("8"))
  {
    return false;
  }

  if (move->To()->GetRank() == Chess::Rank("1") || move->To()->GetRank() == Chess::Rank("8"))
  {
    return move->IsPromotion();
  }
  return true;
}

boost::shared_ptr<ribi::Chess::Piece> ribi::Chess::PiecePawn::Clone() const
{
  //const boost::shared_ptr<Piece> p(new PiecePawn(*this));
  const auto p = PieceFactory().Create(GetNameChar(),GetColor(),GetSquare());
  assert(p);
  assert(*p == *this && "Must be a copy");
  assert( p.get() !=  this && "Must be a deep copy");
  return p;
}

std::vector<boost::shared_ptr<ribi::Chess::Move>> ribi::Chess::PiecePawn::GetMoves() const noexcept
{
  std::vector<boost::shared_ptr<Move>> v;

  std::vector<std::pair<int,int>> ds;
  if (GetColor() != Color::black)
  {
    //Add white moves
    ds.push_back( {  0, 2 } );
    ds.push_back( {  0, 1 } );
    ds.push_back( { -1, 1 } );
    ds.push_back( {  1, 1 } );
  }
  if (GetColor() != Color::white)
  {
    //Add black moves
    ds.push_back( {  0,-2 } );
    ds.push_back( {  0,-1 } );
    ds.push_back( { -1,-1 } );
    ds.push_back( {  1,-1 } );
  }

  std::for_each(ds.begin(), ds.end(),
    [&v,this](const std::pair<int,int>& p)
    {
      try
      {
        const boost::shared_ptr<Square> s = SquareFactory().Create(
          Chess::File(this->GetSquare()->GetFile().ToInt() + p.first),
          Chess::Rank(this->GetSquare()->GetRank().ToInt() + p.second)
        );

        //TRACE(p.first); TRACE(p.second);
        boost::shared_ptr<Move> m = MoveFactory().Create(this->GetSquare()->ToStr()
          + (p.first == 0 ? " " : "x")
          + s->ToStr());
        //TRACE(m);
        v.push_back(m);
      }
      catch (std::exception& e)
      {
        //TRACE(e.what());
        //No problem
      }
    }
  );
  //Triple number of moves by adding check and checkmate
  v = AddCheckAndCheckmate(v);
  return v;
}

ribi::Chess::PieceQueen::PieceQueen(
  const Color color,
  const boost::shared_ptr<const Square> square,
  const PieceFactory&
)
  : Piece(color,square)
{
  //assert(GetColor() != Color::indeterminate);

}

bool ribi::Chess::PieceQueen::CanDoMove(const Chess::Move * const move) const noexcept
{
  if (!move->Piece() || !dynamic_cast<PieceQueen*>(move->Piece().get()))
  {
    //Not a Queen move
    return false;
  }
  assert(
    (
         (!move->From() && !GetSquare())
      || (move->From() && !GetSquare())
      || (move->From() && GetSquare() && (*move->From() == *this->GetSquare()))
    )
    && "Assume Move and Queen to have the same start position");
  assert(move->Piece() && dynamic_cast<PieceQueen*>(move->Piece().get())
    && "Assume this is a Queen move");
  assert(move->To() && "All Queen moves have a to field");
  assert(!move->IsCastling() && "Queen moves are not castling moves");
  assert(!move->Score() && "Queen moves are not final scores");

  if (move->From())
  {
    const int dx = move->From()->GetFile().ToInt() - move->To()->GetFile().ToInt();
    const int dy = move->From()->GetRank().ToInt() - move->To()->GetRank().ToInt();
    if (dx == 0 && dy == 0) return false;
    return (dx == 0 || dy == 0 || std::abs(dx) == std::abs(dy));
  }
  else
  {
    return true;
  }
}

boost::shared_ptr<ribi::Chess::Piece> ribi::Chess::PieceQueen::Clone() const
{
  //const boost::shared_ptr<Piece> p(new PieceQueen(*this));
  const auto p = PieceFactory().Create(GetNameChar(),GetColor(),GetSquare());
  assert(p);
  assert(*p == *this && "Must be a copy");
  assert( p.get() !=  this && "Must be a deep copy");
  return p;
}

std::vector<boost::shared_ptr<ribi::Chess::Move>> ribi::Chess::PieceQueen::GetMoves() const noexcept
{
  std::vector<boost::shared_ptr<Move>> v;
  for (int i=1; i!=8; ++i)
  {
    //North
    try
    {
      const boost::shared_ptr<Square> s = SquareFactory().Create(
        Chess::File(this->GetSquare()->GetFile().ToInt() + 0),
        Chess::Rank(this->GetSquare()->GetRank().ToInt() - i)
      );
      const boost::shared_ptr<Move> m = MoveFactory().Create(boost::lexical_cast<std::string>(this->GetNameChar()) + this->GetSquare()->ToStr() + " " + s->ToStr());
      v.push_back(m);
    }
    catch (std::exception& e)
    {
      //No problem
    }
    //North-east
    try
    {
      const boost::shared_ptr<Square> s = SquareFactory().Create(
        Chess::File(this->GetSquare()->GetFile().ToInt() + i),
        Chess::Rank(this->GetSquare()->GetRank().ToInt() - i));
      const boost::shared_ptr<Move> m = MoveFactory().Create(boost::lexical_cast<std::string>(this->GetNameChar()) + this->GetSquare()->ToStr() + " " + s->ToStr());
      v.push_back(m);
    }
    catch (std::exception& e)
    {
      //No problem
    }
    //East
    try
    {
      const boost::shared_ptr<Square> s = SquareFactory().Create(
        Chess::File(this->GetSquare()->GetFile().ToInt() + i),
        Chess::Rank(this->GetSquare()->GetRank().ToInt() + 0));
      const boost::shared_ptr<Move> m = MoveFactory().Create(boost::lexical_cast<std::string>(this->GetNameChar()) + this->GetSquare()->ToStr() + " " + s->ToStr());
      v.push_back(m);
    }
    catch (std::exception& e)
    {
      //No problem
    }
    //South-east
    try
    {

      const boost::shared_ptr<Square> s = SquareFactory().Create(
        Chess::File(this->GetSquare()->GetFile().ToInt() + i),
        Chess::Rank(this->GetSquare()->GetRank().ToInt() + i));
      const boost::shared_ptr<Move> m = MoveFactory().Create(boost::lexical_cast<std::string>(this->GetNameChar()) + this->GetSquare()->ToStr() + " " + s->ToStr());
      v.push_back(m);
    }
    catch (std::exception& e)
    {
      //No problem
    }
    //South
    try
    {

      const boost::shared_ptr<Square> s = SquareFactory().Create(
        Chess::File(this->GetSquare()->GetFile().ToInt() + 0),
        Chess::Rank(this->GetSquare()->GetRank().ToInt() + i));
      const boost::shared_ptr<Move> m = MoveFactory().Create(boost::lexical_cast<std::string>(this->GetNameChar()) + this->GetSquare()->ToStr() + " " + s->ToStr());
      v.push_back(m);
    }
    catch (std::exception& e)
    {
      //No problem
    }
    //South-west
    try
    {

      const boost::shared_ptr<Square> s = SquareFactory().Create(
        Chess::File(this->GetSquare()->GetFile().ToInt() - i),
        Chess::Rank(this->GetSquare()->GetRank().ToInt() + i));
      const boost::shared_ptr<Move> m = MoveFactory().Create(boost::lexical_cast<std::string>(this->GetNameChar()) + this->GetSquare()->ToStr() + " " + s->ToStr());
      v.push_back(m);
    }
    catch (std::exception& e)
    {
      //No problem
    }
    //West
    try
    {

      const boost::shared_ptr<Square> s = SquareFactory().Create(
        Chess::File(this->GetSquare()->GetFile().ToInt() - i),
        Chess::Rank(this->GetSquare()->GetRank().ToInt() + 0));
      const boost::shared_ptr<Move> m = MoveFactory().Create(boost::lexical_cast<std::string>(this->GetNameChar()) + this->GetSquare()->ToStr() + " " + s->ToStr());
      v.push_back(m);
    }
    catch (std::exception& e)
    {
      //No problem
    }
    //North-west
    try
    {
      const boost::shared_ptr<Square> s = SquareFactory().Create(
        Chess::File(this->GetSquare()->GetFile().ToInt() - i),
        Chess::Rank(this->GetSquare()->GetRank().ToInt() - i));
      const boost::shared_ptr<Move> m = MoveFactory().Create(boost::lexical_cast<std::string>(this->GetNameChar()) + this->GetSquare()->ToStr() + " " + s->ToStr());
      v.push_back(m);
    }
    catch (std::exception& e)
    {
      //No problem
    }

  }
  //Triple number of moves by adding check and checkmate
  v = AddCheckAndCheckmate(v);
  return v;
}

ribi::Chess::PieceRook::PieceRook(
  const Color color,
  const boost::shared_ptr<const Square> square,
  const PieceFactory&
)
  : Piece(color,square),
    m_has_moved{false}
{
  //assert(GetColor() != Color::indeterminate);

}

bool ribi::Chess::PieceRook::CanDoMove(const Chess::Move * const move) const noexcept
{
  if (!move->Piece() || !dynamic_cast<PieceRook*>(move->Piece().get()))
  {
    //Not a Rook move
    return false;
  }
  assert(
    (
         (!move->From() && !GetSquare())
      || (move->From() && !GetSquare())
      || (move->From() && GetSquare() && (*move->From() == *this->GetSquare()))
    )
    && "Assume Move and Rook to have the same start position");
  assert(move->Piece() && dynamic_cast<PieceRook*>(move->Piece().get())
    && "Assume this is a Rook move");
  assert(move->To() && "All Rook moves have a to field");
  assert(!move->IsCastling() && "Rook moves are not castling moves");
  assert(!move->Score() && "Rook moves are not final scores");

  if (move->IsEnPassant()) return false;

  if (move->From())
  {
    const int dx = move->From()->GetFile().ToInt() - move->To()->GetFile().ToInt();
    const int dy = move->From()->GetRank().ToInt() - move->To()->GetRank().ToInt();
    if (dx == 0 && dy == 0) return false;
    return (dx == 0 || dy == 0);
  }
  else
  {
    return true;
  }
}

boost::shared_ptr<ribi::Chess::Piece> ribi::Chess::PieceRook::Clone() const
{
  //const boost::shared_ptr<Piece> p(new PieceRook(*this));
  const auto p = PieceFactory().Create(GetNameChar(),GetColor(),GetSquare());
  assert(p);
  assert(*p == *this && "Must be a copy");
  assert( p.get() !=  this && "Must be a deep copy");
  return p;
}

std::vector<boost::shared_ptr<ribi::Chess::Move>> ribi::Chess::PieceRook::GetMoves() const noexcept
{
  std::vector<boost::shared_ptr<Move>> v;
  for (int i=1; i!=8; ++i)
  {
    //North
    try
    {
      const boost::shared_ptr<Square> s = SquareFactory().Create(
        Chess::File(this->GetSquare()->GetFile().ToInt() + 0),
        Chess::Rank(this->GetSquare()->GetRank().ToInt() - i));
      const boost::shared_ptr<Move> m = MoveFactory().Create(boost::lexical_cast<std::string>(this->GetNameChar()) + this->GetSquare()->ToStr() + " " + s->ToStr());
      v.push_back(m);
    }
    catch (std::exception& e)
    {
      //No problem
    }
    //East
    try
    {
      const boost::shared_ptr<Square> s = SquareFactory().Create(
        Chess::File(this->GetSquare()->GetFile().ToInt() + i),
        Chess::Rank(this->GetSquare()->GetRank().ToInt() + 0));
      const boost::shared_ptr<Move> m = MoveFactory().Create(boost::lexical_cast<std::string>(this->GetNameChar()) + this->GetSquare()->ToStr() + " " + s->ToStr());
      v.push_back(m);
    }
    catch (std::exception& e)
    {
      //No problem
    }
    //South
    try
    {
      const boost::shared_ptr<Square> s = SquareFactory().Create(
        Chess::File(this->GetSquare()->GetFile().ToInt() + 0),
        Chess::Rank(this->GetSquare()->GetRank().ToInt() + i));
      const boost::shared_ptr<Move> m = MoveFactory().Create(boost::lexical_cast<std::string>(this->GetNameChar()) + this->GetSquare()->ToStr() + " " + s->ToStr());
      v.push_back(m);
    }
    catch (std::exception& e)
    {
      //No problem
    }
    //West
    try
    {

      const boost::shared_ptr<Square> s = SquareFactory().Create(
        Chess::File(this->GetSquare()->GetFile().ToInt() - i),
        Chess::Rank(this->GetSquare()->GetRank().ToInt() + 0));
      const boost::shared_ptr<Move> m = MoveFactory().Create(boost::lexical_cast<std::string>(this->GetNameChar()) + this->GetSquare()->ToStr() + " " + s->ToStr());
      v.push_back(m);
    }
    catch (std::exception& e)
    {
      //No problem
    }
  }
  //Triple number of moves by adding check and checkmate
  v = AddCheckAndCheckmate(v);
  return v;
}

std::ostream& ribi::Chess::operator<<(std::ostream& os, const Piece& piece)
{
  os << piece.ToStr();
  return os;
}

bool ribi::Chess::operator==(const Piece& lhs, const Piece& rhs)
{

  if (lhs.GetColor() != rhs.GetColor()) return false;

  if (static_cast<bool>(lhs.GetLastMove()) != static_cast<bool>(rhs.GetLastMove())) return false;
  if (lhs.GetLastMove())
  {
    assert(rhs.GetLastMove());
    if (*lhs.GetLastMove() != *rhs.GetLastMove())
    {
      return false;
    }
  }
  if (static_cast<bool>(lhs.GetSquare()) != static_cast<bool>(rhs.GetSquare()))
  {
    return false;
  }
  if (lhs.GetSquare())
  {
    assert(rhs.GetSquare());
    if (*lhs.GetSquare() != *rhs.GetSquare())
    {
      return false;
    }
  }
  return true;
}

bool ribi::Chess::operator!=(const Piece& lhs, const Piece& rhs)
{
  return !(lhs == rhs);
}

 

 

 

 

 

./CppChess/chesspiecefactory.h

 

#ifndef RIBI_CHESSPIECEFACTORY_H
#define RIBI_CHESSPIECEFACTORY_H

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#include <boost/shared_ptr.hpp>
#include "chessfwd.h"
#include "chesscolor.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace Chess {

struct PieceFactory
{
  PieceFactory();

  boost::shared_ptr<Piece> Create(
    const char namechar,
    const Color color,
    const boost::shared_ptr<const Square> square
  ) const noexcept;

  //For convenience
  boost::shared_ptr<Piece> Create(
    const char namechar,
    const Color color,
    const std::string& square
  ) const noexcept;

  boost::shared_ptr<PieceBishop> CreateBishop(
    const Color color,
    const boost::shared_ptr<const Square> square
  ) const noexcept;

  boost::shared_ptr<PieceKing> CreateKing(
    const Color color,
    const boost::shared_ptr<const Square> square
  ) const noexcept;

  boost::shared_ptr<PieceKnight> CreateKnight(
    const Color color,
    const boost::shared_ptr<const Square> square
  ) const noexcept;

  boost::shared_ptr<PiecePawn> CreatePawn(
    const Color color,
    const boost::shared_ptr<const Square> square
  ) const noexcept;

  boost::shared_ptr<PieceQueen> CreateQueen(
    const Color color,
    const boost::shared_ptr<const Square> square
  ) const noexcept;

  boost::shared_ptr<PieceRook> CreateRook(
    const Color color,
    const boost::shared_ptr<const Square> square
  ) const noexcept;

  boost::shared_ptr<Piece> CreateFromMove(
    const Color color,
    const std::string& s
  ) const noexcept;

  boost::shared_ptr<Piece> CreateFromPromotion(const std::string& s) const noexcept;

  boost::shared_ptr<Piece> DeepCopy(const boost::shared_ptr<const Piece> piece) const noexcept;

  private:
  #ifndef NDEBUG
  static void Test() noexcept;
  #endif
};

} //~namespace Chess
} //~namespace ribi

#endif // RIBI_CHESSPIECEFACTORY_H

 

 

 

 

 

./CppChess/chesspiecefactory.cpp

 

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include "chesspiecefactory.h"

#include <stdexcept>

#include <boost/make_shared.hpp>

#include "chessmove.h"
#include "chessmovefactory.h"
#include "chesspiece.h"
#include "chesssquarefactory.h"
#include "trace.h"
#include "testtimer.h"
#pragma GCC diagnostic pop

ribi::Chess::PieceFactory::PieceFactory()
{
  #ifndef NDEBUG
  Test();
  #endif
}

boost::shared_ptr<ribi::Chess::Piece> ribi::Chess::PieceFactory::Create(
  const char namechar,
  const Color color,
  const boost::shared_ptr<const Square> square) const noexcept
{
  assert(square);
  boost::shared_ptr<Piece> p;
  switch(namechar)
  {
    case 'B': return CreateBishop(color,square);
    case 'K': return CreateKing(color,square);
    case 'N': return CreateKnight(color,square);
    case 'Q': return CreateQueen(color,square);
    case 'R': return CreateRook(color,square);
    case '.': return CreatePawn(color,square);
    default: assert(!"Should not get here");
  }
  assert(p);
  return p;
}

boost::shared_ptr<ribi::Chess::Piece> ribi::Chess::PieceFactory::Create(
  const char namechar,
  const Color color,
  const std::string& square_str
) const noexcept
{
  const boost::shared_ptr<const Square> square {
    SquareFactory().Create(square_str)
  };
  assert(square);
  boost::shared_ptr<Piece> p;
  return Create(namechar,color,square);
}

boost::shared_ptr<ribi::Chess::PieceBishop> ribi::Chess::PieceFactory::CreateBishop(
  const Color color,
  const boost::shared_ptr<const Square> square
) const noexcept
{
  //Cannot use boost::make_shared here, because I fail at making
  //boost::make_shared a friend
  const boost::shared_ptr<PieceBishop> p(
    new PieceBishop(color,square,*this)
  );
  assert(p);
  return p;
}

boost::shared_ptr<ribi::Chess::Piece> ribi::Chess::PieceFactory::CreateFromMove(
  const Color color,
  const std::string& s
) const noexcept
{
  if (s.empty()) throw std::logic_error("ribi::Chess::PieceFactory().CreateFromMove exception: move must not be empty");
  const boost::shared_ptr<Move> move {
    MoveFactory().Create(s)
  };
  #ifdef TODO_ISSUE_176
  assert(move);
  #else
  if (!move) throw std::logic_error("ribi::Chess::PieceFactory().CreateFromMove exception: move empty");
  #endif
  boost::shared_ptr<const Square> square {
    move->To()
  };
  if (!square) square = move->From();

  boost::shared_ptr<Piece> piece;
  const char c = s[0];
  switch(c)
  {
    case 'B': return CreateBishop(color,square);
    case 'K': return CreateKing(color,square);
    case 'N': return CreateKnight(color,square);
    case 'Q': return CreateQueen(color,square);
    case 'R': return CreateRook(color,square);
    case 'a':
    case 'b':
    case 'c':
    case 'd':
    case 'e':
    case 'f':
    case 'g':
    case 'h':
      return CreatePawn(color,square);
    //Return a nullptr instead
    //default:
    //  assert("ribi::Chess::PieceFactory().CreateFromMove exception: unknown piece");
  }
  return piece;
}

boost::shared_ptr<ribi::Chess::Piece> ribi::Chess::PieceFactory::CreateFromPromotion(const std::string& s
) const noexcept
{
  if (s.empty()) throw std::logic_error("ribi::Chess::PieceFactory().CreateFromPromotion exception: move must not be empty");

  boost::shared_ptr<Chess::Piece> p;

  const char c = s[s.size() - 1];
  switch(c)
  {
    case 'B': return CreateBishop(Chess::Color::indeterminate,boost::shared_ptr<Square>());
    case 'K': return CreateKing(Chess::Color::indeterminate,boost::shared_ptr<Square>());
    case 'N': return CreateKnight(Chess::Color::indeterminate,boost::shared_ptr<Square>());
    case 'Q': return CreateQueen(Chess::Color::indeterminate,boost::shared_ptr<Square>());
    case 'R': return CreateRook(Chess::Color::indeterminate,boost::shared_ptr<Square>());
    //allow nullptr
    //default:
    //  assert(!"ribi::Chess::PieceFactory().CreateFromPromotion: Cannot promote to a pawn, or invalid promotion");
    //  throw std::logic_error("ribi::Chess::PieceFactory().CreateFromPromotion: Cannot promote to a pawn, or invalid promotion");
  }
  assert( (p || !p) && "If a string is not a promotion, return a nullptr");
  return p;
}

boost::shared_ptr<ribi::Chess::PieceKing> ribi::Chess::PieceFactory::CreateKing(
  const Color color,
  const boost::shared_ptr<const Square> square
) const noexcept
{
  //Cannot use boost::make_shared here, because I fail at making
  //boost::make_shared a friend
  const boost::shared_ptr<PieceKing> p(
    new PieceKing(color,square,*this)
  );
  assert(p);
  return p;
}

boost::shared_ptr<ribi::Chess::PieceKnight> ribi::Chess::PieceFactory::CreateKnight(
  const Color color,
  const boost::shared_ptr<const Square> square
) const noexcept
{
  //Cannot use boost::make_shared here, because I fail at making
  //boost::make_shared a friend
  const boost::shared_ptr<PieceKnight> p(
    new PieceKnight(color,square,*this)
  );
  assert(p);
  return p;
}

boost::shared_ptr<ribi::Chess::PiecePawn> ribi::Chess::PieceFactory::CreatePawn(
  const Color color,
  const boost::shared_ptr<const Square> square
) const noexcept
{
  //Cannot use boost::make_shared here, because I fail at making
  //boost::make_shared a friend
  const boost::shared_ptr<PiecePawn> p(
    new PiecePawn(color,square,*this)
  );
  assert(p);
  return p;
}

boost::shared_ptr<ribi::Chess::PieceQueen> ribi::Chess::PieceFactory::CreateQueen(
  const Color color,
  const boost::shared_ptr<const Square> square
) const noexcept
{
  //Cannot use boost::make_shared here, because I fail at making
  //boost::make_shared a friend
  const boost::shared_ptr<PieceQueen> p(
    new PieceQueen(color,square,*this)
  );
  assert(p);
  return p;
}

boost::shared_ptr<ribi::Chess::PieceRook> ribi::Chess::PieceFactory::CreateRook(
  const Color color,
  const boost::shared_ptr<const Square> square
) const noexcept
{
  //Cannot use boost::make_shared here, because I fail at making
  //boost::make_shared a friend
  const boost::shared_ptr<PieceRook> p(
    new PieceRook(color,square,*this)
  );
  assert(p);
  return p;
}

boost::shared_ptr<ribi::Chess::Piece> ribi::Chess::PieceFactory::DeepCopy(
  const boost::shared_ptr<const Piece> original_piece
) const noexcept
{
  const auto cloned_piece(
    PieceFactory().Create(
      original_piece->GetNameChar(),
      original_piece->GetColor(),
      original_piece->GetSquare()
    )
  );
  assert(cloned_piece);
  assert(*original_piece == *cloned_piece && "Must be a copy");
  assert(original_piece != cloned_piece && "Must be a deep copy");
  return cloned_piece;
}

#ifndef NDEBUG
void ribi::Chess::PieceFactory::Test() noexcept
{
  {
    static bool is_tested = false;
    if (is_tested) return;
    is_tested = true;
  }
  Piece::Test();
  const TestTimer test_timer(__func__,__FILE__,1.0);
  PieceFactory f;

  #ifdef FIX_ISSUE_240
  {
    const boost::shared_ptr<Piece> piece = f.CreateFromMove(Color::indeterminate,"Na3 b4");
    assert(piece);
    assert(piece->GetSquare());
    assert(piece->GetSquare() == SquareFactory().Create("a3"));
  }
  #endif // FIX_ISSUE_240
}
#endif

 

 

 

 

 

./CppChess/chesspiecetest.cpp

 

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include "chesspiece.h"

#include <cassert>
#include <future>

#include <boost/make_shared.hpp>

#include "chessmove.h"
#include "chessmovefactory.h"
#include "chessmoves.h"
#include "chesssquarefactory.h"
#include "chesspiecefactory.h"
#include "testtimer.h"
#include "trace.h"
#pragma GCC diagnostic pop

///Is there an elemnt in v for IsEqual(*p,*v)
template <class T, class U>
bool IsPresent(boost::shared_ptr<T> p,const std::vector<boost::shared_ptr<U>> v)
{
  assert(p);
  return std::count_if(v.begin(),v.end(),
    [p](const boost::shared_ptr<T> q)
    {
      assert(q);
      return *p == *q;
    }
  ) > 0;
}

#ifndef NDEBUG
void ribi::Chess::Piece::Test() noexcept
{
  {
    static bool tested = false;
    if (tested) return;
    tested = true;
  }
  {
    ribi::Chess::PieceBishop::Test();
    ribi::Chess::PieceKing::Test();
    ribi::Chess::PieceKnight::Test();
    ribi::Chess::PiecePawn::Test();
    ribi::Chess::PieceQueen::Test();
    ribi::Chess::PieceRook::Test();
    ribi::Chess::PieceFactory();
  }
  const TestTimer test_timer(__func__,__FILE__,1.0);
  const bool verbose{false};
    {
      if (verbose) { TRACE("Test Chess::Piece"); }
      {
        const boost::shared_ptr<Square> s = SquareFactory().Create("e4");
        assert(s);
        const boost::shared_ptr<Square> t = SquareFactory().Create("e4");
        assert(t);
        const boost::shared_ptr<Piece> p = PieceFactory().Create('B',Color::white,s);
        assert(p);
        const boost::shared_ptr<Piece> q = PieceFactory().Create('B',Color::white,t);
        assert(q);
        assert(*p == *q);

      }
    }
}


void ribi::Chess::PieceBishop::Test() noexcept
{
  {
    static bool is_tested = false;
    if (is_tested) return;
    is_tested = true;
  }
  #ifdef FIX_ISSUE_240
  if (verbose) { TRACE("Test Bishop for valid moves"); }
  {
    const std::vector<std::string> v = Moves::GetValidBishopMoves();

    std::for_each(v.begin(),v.end(),
      [](const std::string& s)
      {
        const boost::shared_ptr<const Move> move
          = MoveFactory().Create(s);
        assert(move);
        {
          boost::shared_ptr<Piece> p
            = PieceFactory().CreateBishop(Chess::Color::indeterminate,boost::shared_ptr<Square>());
          assert(p->CanDoMove(move));
        }
        {
          boost::shared_ptr<Piece> p
            = PieceFactory().CreateBishop(Chess::Color::white,boost::shared_ptr<Square>());
          assert(p->CanDoMove(move));
        }
        {
          boost::shared_ptr<Piece> p
            = PieceFactory().CreateBishop(Chess::Color::black,boost::shared_ptr<Square>());
          assert(p->CanDoMove(move));
        }
        {
          boost::shared_ptr<Piece> p
            = PieceFactory().CreateFromMove(Chess::Color::indeterminate,s);
          assert(p->CanDoMove(move));
        }
        {
          boost::shared_ptr<Piece> p
            = PieceFactory().CreateFromMove(Chess::Color::white,s);
          assert(p->CanDoMove(move));
        }
        {
          boost::shared_ptr<Piece> p
            = PieceFactory().CreateFromMove(Chess::Color::black,s);
          assert(p->CanDoMove(move));
        }
      }
    );
  }
  if (verbose) { TRACE("Test Bishop for invalid moves") }
  {
    const std::vector<std::string> v = Moves::GetInvalidBishopMoves();
    std::for_each(v.begin(),v.end(),
      [](const std::string& s)
      {
        try
        {
          const boost::shared_ptr<const Move> move
            = MoveFactory().Create(s);
          assert(move);
          {
            boost::shared_ptr<Piece> p
              = PieceFactory().CreateBishop(Chess::Color::indeterminate,boost::shared_ptr<Square>());
            assert(!p->CanDoMove(move));
          }
          {
            boost::shared_ptr<Piece> p
              = PieceFactory().CreateBishop(Chess::Color::white,boost::shared_ptr<Square>());
            assert(!p->CanDoMove(move));
          }
          {
            boost::shared_ptr<Piece> p
              = PieceFactory().CreateBishop(Chess::Color::black,boost::shared_ptr<Square>());
            assert(!p->CanDoMove(move));
          }
          {
            boost::shared_ptr<Piece> p
              = PieceFactory().CreateBishop(Chess::Color::indeterminate,Move::ParseFrom(s));
            assert(!p->CanDoMove(move));
          }
          {
            boost::shared_ptr<Piece> p
              = PieceFactory().CreateBishop(Chess::Color::white,Move::ParseFrom(s));
            assert(!p->CanDoMove(move));
          }
          {
            boost::shared_ptr<Piece> p
              = PieceFactory().CreateBishop(Chess::Color::black,Move::ParseFrom(s));
            assert(!p->CanDoMove(move));
          }
        }
        catch (std::exception& e)
        {
          //Move is correctly determined to be invalid
        }
      }
    );
  }
}
  #endif // FIX_ISSUE_240

}

void ribi::Chess::PieceKing::Test() noexcept
{
  {
    static bool is_tested = false;
    if (is_tested) return;
    is_tested = true;
  }
  const bool verbose{false};
  if (verbose) { TRACE("Test King for valid moves") }
  {
    const std::vector<std::string> v = Moves::GetValidKingMoves();
    std::for_each(v.begin(),v.end(),
      [](const std::string& s)
      {
        const boost::shared_ptr<const Move> move
          = MoveFactory().Create(s);
        assert(move);
        {
          boost::shared_ptr<Piece> p
            = PieceFactory().CreateKing(Chess::Color::indeterminate,boost::shared_ptr<Square>());
          assert(p->CanDoMove(move));
        }
        {
          boost::shared_ptr<Piece> p
            = PieceFactory().CreateKing(Chess::Color::white,boost::shared_ptr<Square>());
          assert(p->CanDoMove(move));
        }
        {
          boost::shared_ptr<Piece> p
            = PieceFactory().CreateKing(Chess::Color::black,boost::shared_ptr<Square>());
          assert(p->CanDoMove(move));
        }
        {
          boost::shared_ptr<Piece> p
            = PieceFactory().CreateKing(Chess::Color::indeterminate,Move::ParseFrom(s));
          assert(p->CanDoMove(move));
        }
        {
          boost::shared_ptr<Piece> p
            = PieceFactory().CreateKing(Chess::Color::white,Move::ParseFrom(s));
          assert(p->CanDoMove(move));
        }
        {
          boost::shared_ptr<Piece> p
            = PieceFactory().CreateKing(Chess::Color::black,Move::ParseFrom(s));
          assert(p->CanDoMove(move));
        }
      }
    );
  }

  if (verbose) { TRACE("Test King for invalid moves") }
  {
    const std::vector<std::string> v = Moves::GetInvalidKingMoves();
    std::for_each(v.begin(),v.end(),
      [](const std::string& s)
      {
        try
        {
          const boost::shared_ptr<const Move> move
            = MoveFactory().Create(s);
          assert(move);
          {
            boost::shared_ptr<Piece> p
              = PieceFactory().CreateKing(Chess::Color::indeterminate,boost::shared_ptr<Square>());
            if (p->CanDoMove(move)) { TRACE(s); }
            assert(!p->CanDoMove(move));
          }
          {
            boost::shared_ptr<Piece> p
             = PieceFactory().CreateKing(Chess::Color::indeterminate,Move::ParseFrom(s));
            assert(!p->CanDoMove(move));
          }
        }
        catch (std::exception& e)
        {
          //OK!
        }
      }
    );
  }
}

void ribi::Chess::PieceKnight::Test() noexcept
{
  {
    static bool is_tested = false;
    if (is_tested) return;
    is_tested = true;
  }
  #ifdef FIX_ISSUE_240

  if (verbose) { TRACE("Test Knight for valid moves"); }
  {
    const std::vector<std::string> v = Moves::GetValidKnightMoves();
    std::for_each(v.begin(),v.end(),
      [](const std::string& s)
      {
        const boost::shared_ptr<const Move> move
          = MoveFactory().Create(s);
        assert(move);
        {
          boost::shared_ptr<Piece> p
            = PieceFactory().CreateKnight(Chess::Color::indeterminate,boost::shared_ptr<Square>());
          assert(p->CanDoMove(move));
        }
        {
          boost::shared_ptr<Piece> p
            = PieceFactory().CreateKnight(Chess::Color::white,boost::shared_ptr<Square>());
          assert(p->CanDoMove(move));
        }
        {
          boost::shared_ptr<Piece> p
            = PieceFactory().CreateKnight(Chess::Color::black,boost::shared_ptr<Square>());
          assert(p->CanDoMove(move));
        }
        {
          boost::shared_ptr<Piece> p
            = PieceFactory().CreateKnight(Chess::Color::indeterminate,Move::ParseFrom(s));
          assert(p->CanDoMove(move));
        }
        {
          boost::shared_ptr<Piece> p
            = PieceFactory().CreateKnight(Chess::Color::white,Move::ParseFrom(s));
          assert(p->CanDoMove(move));
        }
        {
          boost::shared_ptr<Piece> p
            = PieceFactory().CreateKnight(Chess::Color::black,Move::ParseFrom(s));
          assert(p->CanDoMove(move));
        }
      }
    );
  }

  if (verbose) { TRACE("Test Knight for invalid moves") }
  {
    const std::vector<std::string> v = Moves::GetInvalidKnightMoves();
    std::for_each(v.begin(),v.end(),
      [](const std::string& s)
      {
        try
        {
          const boost::shared_ptr<const Move> move
            = MoveFactory().Create(s);
          assert(move);
          {
            boost::shared_ptr<Piece> p
              = PieceFactory().CreateKnight(Chess::Color::indeterminate,boost::shared_ptr<Square>());
            if (p->CanDoMove(move)) { TRACE(s); }
            assert(!p->CanDoMove(move));
          }
          {
            boost::shared_ptr<Piece> p
              = PieceFactory().CreateKnight(Chess::Color::indeterminate,Move::ParseFrom(s));
            assert(!p->CanDoMove(move));
          }
        }
        catch (std::exception& e)
        {
          //OK!
        }
      }
    );
  }
  if (verbose) { TRACE("Test Knight for generating its own moves"); }
  {
    const boost::shared_ptr<Square> square = SquareFactory().Create("d4");
    assert(square);
    boost::shared_ptr<Piece> piece = PieceFactory().Create('N',Color::white,square);
    assert(piece);
    const std::vector<boost::shared_ptr<Move>> moves = piece->GetMoves();
    assert(moves.size() == 8 * 3); //*3 due to non-check, check and checkmate moves
    const boost::shared_ptr<const Move> move = MoveFactory().Create("Nd4 c2");
    assert(move);
    assert(IsPresent(move,moves));
    //assert(std::find(moves.begin(),moves.end(),move) != moves.end());
  }
  {
    const boost::shared_ptr<Square> square = SquareFactory().Create("a1");
    assert(square);
    boost::shared_ptr<Piece> piece = PieceFactory().Create('N',Color::white,square);
    assert(piece);
    const std::vector<boost::shared_ptr<Move>> moves = piece->GetMoves();
    assert(moves.size() == 2 * 3); //*3 due to non-check, check and checkmate moves
    const boost::shared_ptr<const Move> move = MoveFactory().Create("Na1 b3");
    assert(move);
    assert(IsPresent(move,moves));
    //assert(std::find(moves.begin(),moves.end(),MoveFactory().Create("Na1 b3")) != moves.end());
  }
  {
    const boost::shared_ptr<Square> square = SquareFactory().Create("b1");
    assert(square);
    boost::shared_ptr<Piece> piece = PieceFactory().Create('N',Color::black,square);
    assert(piece);
    const std::vector<boost::shared_ptr<Move>> moves = piece->GetMoves();
    assert(moves.size() == 3 * 3); //*3 due to non-check, check and checkmate moves
    const boost::shared_ptr<const Move> move = MoveFactory().Create("Nb1 c3");
    assert(move);
    assert(IsPresent(move,moves));
    //assert(std::find(moves.begin(),moves.end(),MoveFactory().Create("Nb1 c3")) != moves.end());
  }
  #endif // FIX_ISSUE_240
}

void ribi::Chess::PiecePawn::Test() noexcept
{
  {
    static bool is_tested = false;
    if (is_tested) return;
    is_tested = true;
  }
  #ifdef FIX_ISSUE_240
  if (verbose) { TRACE("Test Pawn for valid moves") }
  for (int i=0; i!=3; ++i)
  {
    const Chess::Color color = (i == 0 ? Color::indeterminate : (i == 1 ? Color::white : Color::black));
    const std::vector<std::string> v = Moves::GetValidPawnMoves(color);
    std::for_each(v.begin(),v.end(),
      [color](const std::string& s)
      {
        const boost::shared_ptr<const Move> move
          = MoveFactory().Create(s);
        assert(move);
        {
          boost::shared_ptr<Piece> p
            = PieceFactory().CreatePawn(color,boost::shared_ptr<Square>());
          assert(p->CanDoMove(move));
        }
        {
          boost::shared_ptr<Piece> p
            = PieceFactory().CreatePawn(color,Move::ParseFrom(s));
          assert(p->CanDoMove(move));
        }
      }
    );
  }

  if (verbose) { TRACE("Test Pawn for invalid moves") }
  for (int i=0; i!=3; ++i)
  {
    const Chess::Color color = (i == 0 ? Color::indeterminate : (i == 1 ? Color::white : Color::black));
    const std::vector<std::string> v = Moves::GetInvalidPawnMoves(Color::indeterminate);
    std::for_each(v.begin(),v.end(),
      [color](const std::string& s)
      {
        try
        {
          const boost::shared_ptr<const Move> move
            = MoveFactory().Create(s);
          assert(move);
          {
            boost::shared_ptr<Piece> p
              = PieceFactory().CreatePawn(color,boost::shared_ptr<Square>());
            if (p->CanDoMove(move)) { TRACE(s); }
            assert(!p->CanDoMove(move));
          }
          {
            boost::shared_ptr<Piece> p
              = PieceFactory().CreatePawn(color,Move::ParseFrom(s));
            assert(!p->CanDoMove(move));
          }
        }
        catch (std::exception& e)
        {
          //OK!
        }
      }
    );
  }

  if (verbose) { TRACE("Test Pawn intimately"); }
  {
    boost::shared_ptr<Piece> p
      = PieceFactory().CreatePawn(Chess::Color::white,boost::shared_ptr<Square>());
    assert(p);
    {
      const boost::shared_ptr<const Move> move = MoveFactory().Create("a2 a3");
      assert(move);
      assert(p->CanDoMove(move));
    }
    {
      const boost::shared_ptr<const Move> move = MoveFactory().Create("a2 a4");
      assert(move);
      assert(p->CanDoMove(move));
    }
    {
      const boost::shared_ptr<const Move> move = MoveFactory().Create("a2 a1Q");
      assert(move);
      assert(p->CanDoMove(move));
    }
    {
      const boost::shared_ptr<const Move> move = MoveFactory().Create("a7 a8Q");
      assert(move);
      assert(p->CanDoMove(move));
    }
    {
      const boost::shared_ptr<const Move> move = MoveFactory().Create("a3");
      assert(move);
      assert(p->CanDoMove(move));
    }
    {
      const boost::shared_ptr<const Move> move = MoveFactory().Create("a4");
      assert(move);
      assert(p->CanDoMove(move));
    }
    {
      const boost::shared_ptr<const Move> move = MoveFactory().Create("a1Q");
      assert(move);
      assert(p->CanDoMove(move));
    }
    {
      const boost::shared_ptr<const Move> move = MoveFactory().Create("a8Q");
      assert(move);
      assert(p->CanDoMove(move));
    }
  }

  {
    boost::shared_ptr<Piece> p
      = PieceFactory().CreatePawn(Chess::Color::black,boost::shared_ptr<Square>());
    assert(p);
    {
      const boost::shared_ptr<const Move> move = MoveFactory().Create("a2 a3");
      assert(move);
      assert(p->CanDoMove(move));
    }
    {
      const boost::shared_ptr<const Move> move = MoveFactory().Create("a2 a4");
      assert(move);
      assert(p->CanDoMove(move));
    }
    {
      const boost::shared_ptr<const Move> move = MoveFactory().Create("a2 a1Q");
      assert(move);
      assert(p->CanDoMove(move));
    }
    {
      const boost::shared_ptr<const Move> move = MoveFactory().Create("a7 a8Q");
      assert(move);
      assert(p->CanDoMove(move));
    }
    {
      const boost::shared_ptr<const Move> move = MoveFactory().Create("a3");
      assert(move);
      assert(p->CanDoMove(move));
    }
    {
      const boost::shared_ptr<const Move> move = MoveFactory().Create("a4");
      assert(move);
      assert(p->CanDoMove(move));
    }
    {
      const boost::shared_ptr<const Move> move = MoveFactory().Create("a1Q");
      assert(move);
      assert(p->CanDoMove(move));
    }
    {
      const boost::shared_ptr<const Move> move = MoveFactory().Create("a8Q");
      assert(move);
      assert(p->CanDoMove(move));
    }
  }


  {
    //const boost::shared_ptr<const Square> square = SquareFactory().Create("e4");
    //assert(square);
    const boost::shared_ptr<const Piece> p = PieceFactory().Create('.',Chess::Color::indeterminate,"e4");
    assert(p);

    {
      const boost::shared_ptr<const Move> move = MoveFactory().Create("e4 e5");
      assert(move);
      assert(p->CanDoMove(move));
    }
    {
      const boost::shared_ptr<const Move> move = MoveFactory().Create("e4xd5");
      assert(move);
      assert(p->CanDoMove(move));
    }
    {
      const boost::shared_ptr<const Move> move = MoveFactory().Create("e4xf5");
      assert(move);
      assert(p->CanDoMove(move));
    }
    {
      const boost::shared_ptr<const Move> move = MoveFactory().Create("e4 e3");
      assert(move);
      assert(p->CanDoMove(move));
    }
    {
      const boost::shared_ptr<const Move> move = MoveFactory().Create("e4xd3");
      assert(move);
      assert(p->CanDoMove(move));
    }
    {
      const boost::shared_ptr<const Move> move = MoveFactory().Create("e4xf3");
      assert(move);
      assert(p->CanDoMove(move));
    }
  }
  {
    //const boost::shared_ptr<const Square> square = SquareFactory().Create("e4");
    //assert(square);
    const boost::shared_ptr<const Piece> p = PieceFactory().Create('.',Chess::Color::white,"e4");
    assert(p);
    {
      const boost::shared_ptr<const Move> move = MoveFactory().Create("e4 e5");
      assert(move);
      assert(p->CanDoMove(move));
    }
    {
      const boost::shared_ptr<const Move> move = MoveFactory().Create("e4xd5");
      assert(move);
      assert(p->CanDoMove(move));
    }
    {
      const boost::shared_ptr<const Move> move = MoveFactory().Create("e4xf5");
      assert(move);
      assert(p->CanDoMove(move));
    }
    {
      const boost::shared_ptr<const Move> move = MoveFactory().Create("e4 e3");
      assert(move);
      assert(p->CanDoMove(move));
    }
    {
      const boost::shared_ptr<const Move> move = MoveFactory().Create("e4xd3");
      assert(move);
      assert(p->CanDoMove(move));
    }
    {
      const boost::shared_ptr<const Move> move = MoveFactory().Create("e4xf3");
      assert(move);
      assert(p->CanDoMove(move));
    }

  }
  {
    const boost::shared_ptr<const Piece> p = PieceFactory().Create('.',Chess::Color::black,"e4");
    assert(p);
    //boost::shared_ptr<Piece> p(new PiecePawn(Chess::Color::black,boost::shared_ptr<Square>(new Square("e4"))));

    {
      const boost::shared_ptr<const Move> move = MoveFactory().Create("e4 e5");
      assert(move);
      assert(p->CanDoMove(move));
    }
    {
      const boost::shared_ptr<const Move> move = MoveFactory().Create("e4xd4");
      assert(move);
      assert(p->CanDoMove(move));
    }
    {
      const boost::shared_ptr<const Move> move = MoveFactory().Create("e4xf5");
      assert(move);
      assert(p->CanDoMove(move));
    }
    {
      const boost::shared_ptr<const Move> move = MoveFactory().Create("e4 e3");
      assert(move);
      assert(p->CanDoMove(move));
    }
    {
      const boost::shared_ptr<const Move> move = MoveFactory().Create("e4xd3");
      assert(move);
      assert(p->CanDoMove(move));
    }
    {
      const boost::shared_ptr<const Move> move = MoveFactory().Create("e4xf3");
      assert(move);
      assert(p->CanDoMove(move));
    }
  }

  if (verbose) { TRACE("Test Pawn at e4 for generating its own moves"); }
  {
    const boost::shared_ptr<const Piece> p = PieceFactory().Create('.',Chess::Color::indeterminate,"e4");
    assert(p);
    //const PiecePawn p(Color::indeterminate,boost::shared_ptr<Square>(new Square("e4")));
    const std::vector<boost::shared_ptr<Move>> moves = p->GetMoves();

    assert(std::find(moves.begin(),moves.end(),MoveFactory().Create("e4 e5")) != moves.end());
    assert(std::find(moves.begin(),moves.end(),MoveFactory().Create("e4xd5")) != moves.end());
    assert(std::find(moves.begin(),moves.end(),MoveFactory().Create("e4xf5")) != moves.end());
    assert(std::find(moves.begin(),moves.end(),MoveFactory().Create("e4 e3")) != moves.end());
    assert(std::find(moves.begin(),moves.end(),MoveFactory().Create("e4xd3")) != moves.end());
    assert(std::find(moves.begin(),moves.end(),MoveFactory().Create("e4xf3")) != moves.end());
    assert(moves.size() == 6 * 3); //*3 due to non-check, check and checkmate moves
  }
  {
    const boost::shared_ptr<const Piece> p = PieceFactory().Create('.',Chess::Color::white,"e4");
    assert(p);
    //PiecePawn p(Color::white,boost::shared_ptr<Square>(new Square("e4")));
    const std::vector<boost::shared_ptr<Move>> moves = p->GetMoves();
    assert(std::find(moves.begin(),moves.end(),MoveFactory().Create("e4 e5")) != moves.end());
    assert(std::find(moves.begin(),moves.end(),MoveFactory().Create("e4xd5")) != moves.end());
    assert(std::find(moves.begin(),moves.end(),MoveFactory().Create("e4xf5")) != moves.end());
    assert(moves.size() == 3 * 3); //*3 due to non-check, check and checkmate moves
  }
  {
    const boost::shared_ptr<const Piece> p = PieceFactory().Create('.',Chess::Color::black,"e4");
    assert(p);
    //PiecePawn p(Color::black,boost::shared_ptr<Square>(new Square("e4")));
    const std::vector<boost::shared_ptr<Move>> moves = p->GetMoves();
    assert(std::find(moves.begin(),moves.end(),MoveFactory().Create("e4 e3")) != moves.end());
    assert(std::find(moves.begin(),moves.end(),MoveFactory().Create("e4xd3")) != moves.end());
    assert(std::find(moves.begin(),moves.end(),MoveFactory().Create("e4xf3")) != moves.end());
    assert(moves.size() == 3 * 3); //*3 due to non-check, check and checkmate moves
  }
  #endif // FIX_ISSUE_240

}

void ribi::Chess::PieceQueen::Test() noexcept
{
  {
    static bool is_tested = false;
    if (is_tested) return;
    is_tested = true;
  }
  #ifdef FIX_ISSUE_240
  if (verbose) { TRACE("Test Queen for valid moves"); }
  {
    const std::vector<std::string> v = Moves::GetValidQueenMoves();
    std::for_each(v.begin(),v.end(),
      [](const std::string& s)
      {
        const boost::shared_ptr<const Move> move
          = MoveFactory().Create(s);
        assert(move);
        {
          boost::shared_ptr<Piece> p
            = PieceFactory().CreateQueen(Chess::Color::indeterminate,boost::shared_ptr<Square>());
          assert(p->CanDoMove(move));
        }
        {
          boost::shared_ptr<Piece> p
            = PieceFactory().CreateQueen(Chess::Color::white,boost::shared_ptr<Square>());
          assert(p->CanDoMove(move));
        }
        {
          boost::shared_ptr<Piece> p
            = PieceFactory().CreateQueen(Chess::Color::black,boost::shared_ptr<Square>());
          assert(p->CanDoMove(move));
        }
        {
          boost::shared_ptr<Piece> p
            = PieceFactory().CreateQueen(Chess::Color::indeterminate,Move::ParseFrom(s));
          assert(p->CanDoMove(move));
        }
        {
          boost::shared_ptr<Piece> p
            = PieceFactory().CreateQueen(Chess::Color::white,Move::ParseFrom(s));
          assert(p->CanDoMove(move));
        }
        {
          boost::shared_ptr<Piece> p
            = PieceFactory().CreateQueen(Chess::Color::black,Move::ParseFrom(s));
          assert(p->CanDoMove(move));
        }
      }
    );
  }
  if (verbose) { TRACE("Test Queen for invalid moves"); }
  {
    const std::vector<std::string> v = Moves::GetInvalidQueenMoves();
    std::for_each(v.begin(),v.end(),
      [](const std::string& s)
      {
        try
        {
          const boost::shared_ptr<const Move> move
            = MoveFactory().Create(s);
          assert(move);
          {
            boost::shared_ptr<Piece> p
              = PieceFactory().CreateQueen(Chess::Color::indeterminate,boost::shared_ptr<Square>());
            if (p->CanDoMove(move)) { TRACE(s); }
            assert(!p->CanDoMove(move));
          }
          {
            boost::shared_ptr<Piece> p
              = PieceFactory().CreateQueen(Chess::Color::indeterminate,Move::ParseFrom(s));
            assert(!p->CanDoMove(move));
          }
        }
        catch (std::exception& e)
        {
          //OK!
        }
      }
    );
  }

  if (verbose) { TRACE("Test Queen for generating its own moves"); }
  {
    const boost::shared_ptr<const Piece> p = PieceFactory().Create('Q',Chess::Color::white,"d4");
    assert(p);
    //PieceQueen q(Color::white,boost::shared_ptr<Square>(new Square("d4")));
    const std::vector<boost::shared_ptr<Move>> moves = p->GetMoves();
    assert(moves.size() == 27 * 3); //*3 due to non-check, check and checkmate moves
    const boost::shared_ptr<const Move> move = MoveFactory().Create("Qd4 h8");
    assert(move);
    assert(IsPresent(move,moves));
    //assert(std::find(moves.begin(),moves.end(),MoveFactory().Create("Qd4 h8")) != moves.end());
  }
  {
    const boost::shared_ptr<const Piece> p = PieceFactory().Create('Q',Chess::Color::white,"a1");
    assert(p);
    //PieceQueen q(Color::white,boost::shared_ptr<Square>(new Square("a1")));
    const std::vector<boost::shared_ptr<Move>> moves = p->GetMoves();
    assert(moves.size() == 21 * 3); //*3 due to non-check, check and checkmate moves
    const boost::shared_ptr<const Move> move = MoveFactory().Create("Qa1 h1");
    assert(move);
    assert(IsPresent(move,moves));
    //assert(std::find(moves.begin(),moves.end(),MoveFactory().Create("Qa1 h1")) != moves.end());
  }
  {
    const boost::shared_ptr<const Piece> p = PieceFactory().Create('Q',Chess::Color::black,"b1");
    assert(p);
    //PieceQueen q(Color::white,boost::shared_ptr<Square>(new Square("b1")));
    const std::vector<boost::shared_ptr<Move>> moves = p->GetMoves();
    assert(moves.size() == 21 * 3); //*3 due to non-check, check and checkmate moves
    const boost::shared_ptr<const Move> move = MoveFactory().Create("Qb1 b8");
    assert(move);
    assert(IsPresent(move,moves));
    //assert(std::find(moves.begin(),moves.end(),MoveFactory().Create("Qb1 b8")) != moves.end());
  }
  #endif // FIX_ISSUE_240
}

void ribi::Chess::PieceRook::Test() noexcept
{
  {
    static bool is_tested = false;
    if (is_tested) return;
    is_tested = true;
  }
  #ifdef FIX_ISSUE_240
  if (verbose) { TRACE("Test Rook for valid moves"); }
  {
    const std::vector<std::string> v = Moves::GetValidRookMoves();
    std::for_each(v.begin(),v.end(),
      [](const std::string& s)
      {
        const boost::shared_ptr<const Move> move
          = MoveFactory().Create(s);
        assert(move);
        {
          boost::shared_ptr<Piece> p
            = PieceFactory().CreateRook(Chess::Color::indeterminate,boost::shared_ptr<Square>());
          assert(p->CanDoMove(move));
        }
        {
          boost::shared_ptr<Piece> p
            = PieceFactory().CreateRook(Chess::Color::white,boost::shared_ptr<Square>());
          assert(p->CanDoMove(move));
        }
        {
          boost::shared_ptr<Piece> p
            = PieceFactory().CreateRook(Chess::Color::black,boost::shared_ptr<Square>());
          assert(p->CanDoMove(move));
        }
        {
          boost::shared_ptr<Piece> p
            = PieceFactory().CreateRook(Chess::Color::indeterminate,Move::ParseFrom(s));
          assert(p->CanDoMove(move));
        }
        {
          boost::shared_ptr<Piece> p
            = PieceFactory().CreateRook(Chess::Color::white,Move::ParseFrom(s));
          assert(p->CanDoMove(move));
        }
        {
          boost::shared_ptr<Piece> p
            = PieceFactory().CreateRook(Chess::Color::black,Move::ParseFrom(s));
          assert(p->CanDoMove(move));
        }
      }
    );
  }
  if (verbose) { TRACE("Test Rook for invalid moves"); }
  {
    const std::vector<std::string> v = Moves::GetInvalidRookMoves();
    std::for_each(v.begin(),v.end(),
      [](const std::string& s)
      {
        try
        {
          const boost::shared_ptr<const Move> move
            = MoveFactory().Create(s);
          assert(move);
          {
            boost::shared_ptr<Piece> p
              = PieceFactory().CreateRook(Chess::Color::indeterminate,boost::shared_ptr<Square>());
            if (p->CanDoMove(move)) { TRACE(s); }
            assert(!p->CanDoMove(move));
          }
          {
            boost::shared_ptr<Piece> p
              = PieceFactory().CreateRook(Chess::Color::indeterminate,Move::ParseFrom(s));
            assert(!p->CanDoMove(move));
          }
        }
        catch (std::exception& e)
        {
          //OK!
        }
      }
    );
  }
  #endif // FIX_ISSUE_240
}
#endif

 

 

 

 

 

./CppChess/chessplayer.h

 

#ifndef RIBI_CHESSPLAYER_H
#define RIBI_CHESSPLAYER_H

#include <string>
#include <vector>

namespace ribi {
namespace Chess {

///Player is a chess player
enum class Player { white, black };
std::string PlayerToStr(const Player player) noexcept;

} //~namespace Chess
} //~namespace ribi

#endif // RIBI_CHESSPLAYER_H

 

 

 

 

 

./CppChess/chessplayer.cpp

 


#include <cassert>
#include <stdexcept>

#include "chessplayer.h"

std::string ribi::Chess::PlayerToStr(const Player player) noexcept
{
  switch (player)
  {
    case Player::black: return "black";
    case Player::white: return "white";
  }
  assert(!"Unknown Player in PlayerToStr");
  throw std::logic_error("Unknown Player in PlayerToStr");
}

 

 

 

 

 

./CppChess/chessrank.h

 

#ifndef RIBI_CHESSRANK_H
#define RIBI_CHESSRANK_H

#include <string>
#include <vector>

namespace ribi {
namespace Chess {

///Rank is the y coordinat on the Board
struct Rank
{
  ///Create a Rank from a single-character std::string
  ///Use std::string instead of char to prevent implicit typecasts
  explicit Rank(const std::string& rank);

  ///Create a Rank from its y coordinat
  explicit Rank(const int y);

  ///Obtain the version of this class
  static std::string GetVersion();

  ///Obtain the version history of this class
  static std::vector<std::string> GetVersionHistory();

  ///Test this class
  static void Test() noexcept;

  ///Convert the Rank to its y coordinat on the Board, for example 0 for square h1
  int ToInt() const;

  ///Convert the Rank to its single-character string, for example "1" for square h1
  const std::string& ToStr() const;

  //Increment rank, e.g. from '1' to'2'
  //Rank& operator++();

  //Decrement rank, e.g. from '2' to'1'
  //Rank& operator--();

  private:
  ///The Rank as a single-character std::string, for example "1"
  ///Use std::string instead of char to prevent implicit typecasts
  const std::string m_rank;
};

bool operator==(const Rank& lhs, const Rank& rhs);

} //~namespace Chess
} //~namespace ribi

#endif // RIBI_CHESSRANK_H

 

 

 

 

 

./CppChess/chessrank.cpp

 

#include "chessrank.h"

#include <algorithm>
#include <cassert>
#include <stdexcept>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include <boost/lexical_cast.hpp>

#include "testtimer.h"
#include "trace.h"
#pragma GCC diagnostic pop

ribi::Chess::Rank::Rank(const std::string& y)
  : m_rank(y)
{
  #ifndef NDEBUG
  Test();
  #endif
  if (m_rank.size() != 1)
  {
    throw std::logic_error("A chess ranks consists of a single-chacter std::string with values from 1 to and including 8");
  }
  try
  {
    boost::lexical_cast<int>(y);
  }
  catch (boost::bad_lexical_cast& e)
  {
    throw std::logic_error("A chess ranks consists of a value from 1 to and including 8");
  }
  const int i = boost::lexical_cast<int>(y);

  if (i < 1 || i > 8)
  {
    throw std::logic_error("Chess ranks go from 1 to and including 8");
  }
  assert(boost::lexical_cast<int>(m_rank) >= 1);
  assert(boost::lexical_cast<int>(m_rank) <= 8);
}

ribi::Chess::Rank::Rank(const int y)
  : m_rank(boost::lexical_cast<std::string>(y + 1))
{
  #ifndef NDEBUG
  Test();
  #endif
  if (y < 0 || y > 7)
  {
    std::stringstream s;
    s << __func__ << ": Chessboard y coordinats go from 0 to and including 7, "
      << "y value supplied was " << y;
    throw std::logic_error(s.str());
  }
}

std::string ribi::Chess::Rank::GetVersion()
{
  return "1.0";
}

std::vector<std::string> ribi::Chess::Rank::GetVersionHistory()
{
  std::vector<std::string> v;
  v.push_back("YYYY-MM-DD: version X.Y: [description]");
  v.push_back("2012-01-25: version 1.0: initial version");
  return v;
}

void ribi::Chess::Rank::Test() noexcept
{
  {
    static bool is_tested = false;
    if (is_tested) return;
    is_tested = true;
  }
  const TestTimer test_timer(__func__,__FILE__,1.0);
  const bool verbose{false};
    {
      if (verbose) { TRACE("Test Chess::Rank"); }

      if (verbose) { TRACE("Test valid Ranks from std::string"); }
      {
        const std::vector<std::string> v = {"1","2","3","4","5","6","7","8"};
        std::for_each(v.begin(),v.end(),[](const std::string& s) { Rank tmp(s); } );
      }
      if (verbose) { TRACE("Test valid Ranks from int"); }
      {
        const std::vector<int> v = {0,1,2,3,4,5,6,7};
        std::for_each(v.begin(),v.end(),[](const int& i) { Rank tmp(i); } );
      }
      if (verbose) { TRACE("Test invalid Ranks from std::string"); }
      {
        const std::vector<std::string> v = {"0","9","a","h"," ","A","I","aa","1a","a1","11" };
        std::for_each(v.begin(),v.end(),
          [](const std::string& s)
          {
            try
            {
              Rank tmp(s);
              TRACE(s);
              assert(!"Should not get here");
            }
            catch (std::exception& e)
            {
              //OK!
            }
          }
        );
      }
      if (verbose) { TRACE("Test invalid Ranks from int"); }
      {
        const std::vector<int> v = {-1,8,10,11,100,111};
        std::for_each(v.begin(),v.end(),
          [](const int& i)
          {
            try
            {
              Rank tmp(i);
              TRACE(i);
              assert(!"Should not get here");
            }
            catch (std::exception& e)
            {
              //OK!
            }
          }
        );
      }
      if (verbose) { TRACE("Test individual ranks intimately"); }
      {
        Rank r("1");
        assert(r.ToStr() == "1");
        assert(r.ToInt() == 0);
      }
      {
        Rank r("8");
        assert(r.ToStr() == "8");
        assert(r.ToInt() == 7);
      }
      {
        Rank r(0);
        assert(r.ToStr() == "1");
        assert(r.ToInt() == 0);
      }
      {
        Rank r(7);
        assert(r.ToStr() == "8");
        assert(r.ToInt() == 7);
      }
    }
}

int ribi::Chess::Rank::ToInt() const
{
  assert(boost::lexical_cast<int>(m_rank) >= 1);
  assert(boost::lexical_cast<int>(m_rank) <= 8);
  return boost::lexical_cast<int>(m_rank) - 1;
}

const std::string& ribi::Chess::Rank::ToStr() const
{
  return m_rank;
}

bool ribi::Chess::operator==(const Chess::Rank& lhs, const Chess::Rank& rhs)
{
  return lhs.ToStr() == rhs.ToStr();
}

 

 

 

 

 

./CppChess/chessscore.h

 

#ifndef RIBI_CHESSSCORE_H
#define RIBI_CHESSSCORE_H

#include <iosfwd>
#include <string>
#include <vector>

namespace ribi {
namespace Chess {

///Score contains the score that ends a chess match
struct Score
{
  Score(const std::string& s);

  ///Obtain the version of this class
  static std::string GetVersion();

  ///Obtain the version history of this class
  static std::vector<std::string> GetVersionHistory();

  bool IsBlackWinner() const { return m_is_black_winner; }
  bool IsDraw() const { return m_is_draw; }
  bool IsWhiteWinner() const { return m_is_white_winner; }

  #ifndef NDEBUG
  ///Test if Score is working correctly
  static void Test() noexcept;
  #endif

  ///Convert a Score to string
  std::string ToStr() const;

  private:

  const bool m_is_black_winner;
  const bool m_is_draw;
  const bool m_is_white_winner;
};

std::ostream& operator<<(std::ostream& os, const Score& s);
bool operator==(const Score& lhs, const Score& rhs);
bool operator!=(const Score& lhs, const Score& rhs);

} //~namespace Chess
} //~namespace ribi

#endif // RIBI_CHESSSCORE_H

 

 

 

 

 

./CppChess/chessscore.cpp

 

#include "chessscore.h"

#include <iosfwd>
#include <stdexcept>

#include <algorithm>
#include <cassert>
#include <string>
#include <stdexcept>
#include <vector>
#include "trace.h"
#include "testtimer.h"


ribi::Chess::Score::Score(const std::string& s)
  : m_is_black_winner(s == "0-1"),
    m_is_draw(s == "1/2-1/2"),
    m_is_white_winner(s == "1-0")
{
  #ifndef NDEBUG
  Test();
  #endif
  if ( !m_is_black_winner
    && !m_is_draw
    && !m_is_white_winner)
  {
    throw std::logic_error("ribi::Chess::Score::Score exception: invalid score");
  }
}

std::string ribi::Chess::Score::GetVersion()
{
  return "1.0";
}

std::vector<std::string> ribi::Chess::Score::GetVersionHistory()
{
  std::vector<std::string> v;
  v.push_back("YYYY-MM-DD: version X.Y: [description]");
  v.push_back("2012-01-25: version 1.0: initial version");
  return v;
}

#ifndef NDEBUG
void ribi::Chess::Score::Test() noexcept
{
  {
    static bool is_tested = false;
    if (is_tested) return;
    is_tested = true;
  }
  const TestTimer test_timer(__func__,__FILE__,1.0);
  const bool verbose{false};
    {
      if (verbose) { TRACE("Test Chess::Score"); }
      //Test valid scores being valid
      {
        const std::vector<std::string> v = { "0-1", "1/2-1/2", "1-0" } ;
        std::for_each(v.begin(),v.end(),
          [](const std::string& s)
          {
            try
            {
              Chess::Score tmp(s);
            }
            catch (std::exception& e)
            {
              TRACE(s);
              assert("Should not get here");
            }
          }
        );
      }
      //Test invalid scores being invalid
      {
        const std::vector<std::string> v = { "1-1", "1/2-1", "1-1/2", "0-0", "a3", "a2 a3", "0-0-0", "Qd4", "Qd4 e5" } ;
        std::for_each(v.begin(),v.end(),
          [](const std::string& s)
          {
            try
            {
              Chess::Score tmp(s);
              TRACE(s)
              assert("Should not get here");
            }
            catch (std::exception& e)
            {
              //Okay: invalid Score is determined being invalid
            }
          }
        );
      }
    }
}
#endif

std::string ribi::Chess::Score::ToStr() const
{
  if (m_is_black_winner) return "0-1";
  if (m_is_draw) return "1/2-1/2";
  if (m_is_white_winner) return "1-0";
  assert(!"Should not get here");
  throw std::logic_error("Cannot create score");
}

std::ostream& ribi::Chess::operator<<(std::ostream& os, const Score& s)
{
  os << s.ToStr();
  return os;
}

bool ribi::Chess::operator==(const Score& lhs, const Score& rhs)
{
  return
       lhs.IsBlackWinner() == rhs.IsBlackWinner()
    && lhs.IsDraw()        == rhs.IsDraw()
    && lhs.IsWhiteWinner() == rhs.IsWhiteWinner();
}

bool ribi::Chess::operator!=(const Score& lhs, const Score& rhs)
{
  return !(lhs==rhs);
}

 

 

 

 

 

./CppChess/chesssquare.h

 

#ifndef RIBI_CHESSSQUARE_H
#define RIBI_CHESSSQUARE_H

#include <iosfwd>
#include <string>
#include <boost/checked_delete.hpp>
#include "chesscolor.h"
#include "chessfile.h"
#include "chessrank.h"
#include "chessfwd.h"

namespace ribi {
namespace Chess {

///Square is the square on a Board, for example 'a1'
///ToInt can be used to derive the coordinat of the square on a chessboard
struct Square
{
  ///Obtain a Square from its notational form
  ///Note that s is checked for validity after contruction
  //Square(const char * const s);

  ///Conclude the color of the square
  Chess::Color GetColor() const;

  ///Obtain the File (X direction) of the Square
  const Chess::File& GetFile() const { return m_file; }

  ///Obtain the Rank (Y direction) of the Square
  const Chess::Rank& GetRank() const { return m_rank; }

  ///Obtain the version of this class
  static std::string GetVersion();

  ///Obtain the version history of this class
  static std::vector<std::string> GetVersionHistory();

  ///Test the correct working of Square
  #ifndef NDEBUG
  static void Test() noexcept;
  #endif

  ///Convert the Square to a string
  std::string ToStr() const noexcept;

  private:
  ///Obtain a Square from its coordinats
  explicit Square(const Chess::File& x, const Chess::Rank& y);

  ///Obtain a Square from its notational form
  explicit Square(const std::string& s);

  ///the file or x-coordinat of the square, a2 has m_file of 0
  const Chess::File m_file; //X

  ///the rank or y-coordinat of the square, a2 has m_file of 1
  const Chess::Rank m_rank; //Y

  ~Square() {}
  friend void boost::checked_delete<>(Square *);
  friend class SquareFactory;
};

std::ostream& operator<<(std::ostream& os, const Chess::Square& s) noexcept;
bool operator==(const Chess::Square& lhs, const Chess::Square& rhs) noexcept;
bool operator!=(const Chess::Square& lhs, const Chess::Square& rhs) noexcept;

} //~namespace Chess
} //~namespace ribi

#endif // RIBI_CHESSSQUARE_H

 

 

 

 

 

./CppChess/chesssquare.cpp

 

#include <algorithm>
#include <cassert>
#include <iostream>
#include <vector>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#include <boost/lexical_cast.hpp>

#include "chesssquare.h"
#include "testtimer.h"
#include "trace.h"
#pragma GCC diagnostic pop

ribi::Chess::Square::Square(const Chess::File& x, const Chess::Rank& y)
  : m_file(x), m_rank(y)
{
  #ifndef NDEBUG
  Test();
  #endif
}

ribi::Chess::Square::Square(const std::string &s)
  : m_file(Chess::File(boost::lexical_cast<std::string>(s.at(0)))),
    m_rank(Chess::Rank(boost::lexical_cast<std::string>(s.at(1))))
{
  #ifndef NDEBUG
  Test();
  #endif
  if (s.empty()) throw std::logic_error("An empty string cannot be converted to a chess square");
  if (s.size() != 2)
  {
    throw std::logic_error("A string to be converted to a chess square must consist of exactly two characters");
  }
}

//ribi::Chess::Square::Square(const char * const s)
//  : m_x(Chess::File(s[0]),
//    m_y(Chess::Rank(boost::lexical_cast<int>(s[1])))
//{
//  assert(s);
//  assert(std::strlen(s) == 2);
//}

ribi::Chess::Color ribi::Chess::Square::GetColor() const
{
  return ((this->GetFile().ToInt() + this->GetRank().ToInt()) % 2 == 1 ? Color::white : Color::black);
}

std::string ribi::Chess::Square::GetVersion()
{
  return "1.0";
}

std::vector<std::string> ribi::Chess::Square::GetVersionHistory()
{
  return {
    "2012-01-25: version 1.0: initial version"
  };
}

#ifndef NDEBUG
void ribi::Chess::Square::Test() noexcept
{
  {
    static bool is_tested = false;
    if (is_tested) return;
    is_tested = true;
  }
  {
    Chess::File::Test();
    Chess::Rank::Test();
  }
  const TestTimer test_timer(__func__,__FILE__,1.0);
  const bool verbose{false};
  {
    Chess::Square s("a1");
    Chess::Square t("a1");
    Chess::Square u(t);
    Chess::Square v("a2");
    assert(s == t);
    assert(t == u);
    assert(s != v);
    assert(u != v);
  }

  {
    if (verbose) { TRACE("Test a1"); }
    Chess::Square s("a1");
    assert(s.GetFile().ToStr() == "a");
    assert(s.GetRank().ToStr() == "1");
    assert(s.GetFile().ToInt() == 0);
    assert(s.GetRank().ToInt() == 0);
    assert(s.GetColor() == Color::black);
  }
  {
    if (verbose) { TRACE("Test b1"); }
    Chess::Square s("b1");
    assert(s.GetFile().ToStr() == "b");
    assert(s.GetRank().ToStr() == "1");
    assert(s.GetFile().ToInt() == 1);
    assert(s.GetRank().ToInt() == 0);
    assert(s.GetColor() == Color::white);
  }
  {
    if (verbose) { TRACE("Test a2"); }
    Chess::Square s("a2");
    assert(s.GetFile().ToStr() == "a");
    assert(s.GetRank() == Chess::Rank("2"));
    assert(s.GetFile().ToInt() == 0);
    assert(s.GetRank().ToInt() == 1);
    assert(s.GetColor() == Color::white);
  }
  {
    if (verbose) { TRACE("Test d1"); }
    Chess::Square s("d1");
    assert(s.GetColor() == Color::white);
  }
  {
    if (verbose) { TRACE("Test d8"); }
    Chess::Square s("d8");
    assert(s.GetColor() == Color::black);
  }
  {
    if (verbose) { TRACE("Test g8"); }
    Chess::Square s("g8");
    assert(s.GetFile().ToStr() == "g");
    assert(s.GetRank() == Rank("8"));
    assert(s.GetFile().ToInt() == 6);
    assert(s.GetRank().ToInt() == 7);
  }
  {
    if (verbose) { TRACE("Test known-to-be-valid squares"); }
    const std::vector<std::string> v =
    {
      "a1", "a8", "h1", "h8", "d4"
    };
    std::for_each(v.begin(),v.end(),
      [](const std::string& s)
      {
        try
        {
          Chess::Square x(s);
        }
        catch (std::exception& e)
        {
          TRACE(s);
          TRACE(e.what());
          assert("Should not get here");
        }
      }
    );
  }

  {
    if (verbose) { TRACE("Test known-to-be-invalid squares"); }
    const std::vector<std::string> v =
    {
      "A1", "a9", "H8", "h9", "i1", "a", "A", "1", "9", "a10", "h10", "aa1", "a1a", "11", "aa"
    };
    std::for_each(v.begin(),v.end(),
      [](const std::string& s)
      {
        bool ok = false;
        try
        {
          Chess::Square x(s);
        }
        catch (std::exception& e)
        {
          //Ok!
          ok = true;
        }
        if (!ok)
        {
          TRACE(s);
          assert("Should not get here");
        }
      }
    );
  }
}
#endif

std::string ribi::Chess::Square::ToStr() const noexcept
{
  std::string s
    = boost::lexical_cast<std::string>(GetFile().ToStr())
    + boost::lexical_cast<std::string>(GetRank().ToStr());
  return s;
}

std::ostream& ribi::Chess::operator<<(std::ostream& os, const Square& s) noexcept
{
  os << s.ToStr();
  return os;
}

bool ribi::Chess::operator==(const Square& lhs, const Square& rhs) noexcept
{
  return lhs.GetFile() == rhs.GetFile()
    && lhs.GetRank() == rhs.GetRank();
}

bool ribi::Chess::operator!=(const Square& lhs, const Square& rhs) noexcept
{
  return !(lhs == rhs);
}

 

 

 

 

 

./CppChess/chesssquarefactory.h

 

#ifndef RIBI_CHESSSQUAREFACTORY_H
#define RIBI_CHESSSQUAREFACTORY_H

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#include <boost/shared_ptr.hpp>

#include "chessfwd.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace Chess {

struct SquareFactory
{
  SquareFactory() noexcept;

  const boost::shared_ptr<Square> Create(
    const Chess::File& x,
    const Chess::Rank& y
  ) const noexcept;

  ///Obtain a Square from its notational form
  const boost::shared_ptr<Square> Create(
    const std::string& s
  ) const noexcept;

  ///Obtain the from Square from a move, that is, the first two non-piece characters
  const boost::shared_ptr<Square> CreateFromMove(
    const std::string& s
  ) const noexcept;

  boost::shared_ptr<Square> DeepCopy(const boost::shared_ptr<const Square> s) const noexcept;

  private:
  #ifndef NDEBUG
  static void Test() noexcept;
  #endif
};

} //~namespace Chess
} //~namespace ribi

#endif // RIBI_CHESSSQUAREFACTORY_H

 

 

 

 

 

./CppChess/chesssquarefactory.cpp

 

#include "chesssquarefactory.h"

#include <cassert>

#include "chesssquare.h"
#include "trace.h"
#include "testtimer.h"

ribi::Chess::SquareFactory::SquareFactory() noexcept
{
  #ifndef NDEBUG
  Test();
  #endif
}

const boost::shared_ptr<ribi::Chess::Square> ribi::Chess::SquareFactory::Create(
  const File& x,
  const Rank& y
) const noexcept
{
  const boost::shared_ptr<Square> s {
    new Square(x,y)
  };
  assert(s);
  return s;
}

const boost::shared_ptr<ribi::Chess::Square> ribi::Chess::SquareFactory::Create(
  const std::string& text) const noexcept
{
  try
  {
    const boost::shared_ptr<Square> s {
      new Square(text)
    };
    assert(s);
    return s;
  }
  catch (std::exception&)
  {
    boost::shared_ptr<Square> s;
    assert(!s);
    return s;
  }
}

const boost::shared_ptr<ribi::Chess::Square> ribi::Chess::SquareFactory::CreateFromMove(
  const std::string& text) const noexcept
{
  if (text.size() < 2)
  {
    boost::shared_ptr<Square> s;
    assert(!s);
    return s;
  }
  try
  {
    const boost::shared_ptr<Square> s {
      new Square(text.substr(0,2))
    };
    assert(s);
    return s;
  }
  catch (std::exception&)
  {
    //Ok
  }
  if (text.size() < 3)
  {
    boost::shared_ptr<Square> s;
    assert(!s);
    return s;
  }
  try
  {
    const boost::shared_ptr<Square> s {
      new Square(text.substr(1,2))
    };
    assert(s);
    return s;
  }
  catch (std::exception&)
  {
    boost::shared_ptr<Square> s;
    assert(!s);
    return s;
  }
}

boost::shared_ptr<ribi::Chess::Square> ribi::Chess::SquareFactory::DeepCopy(
  const boost::shared_ptr<const Square> s) const noexcept
{
  const boost::shared_ptr<ribi::Chess::Square> t {
    SquareFactory::Create(s->ToStr())
  };
  assert(t);
  assert(*s == *t && "Must be a copy");
  assert(s != t && "Must be a deep copy");
  return t;
}

#ifndef NDEBUG
void ribi::Chess::SquareFactory::Test() noexcept
{
  {
    static bool is_tested = false;
    if (is_tested) return;
    is_tested = true;
  }
  {
    Square("a1");
  }
  const TestTimer test_timer(__func__,__FILE__,1.0);
  //const bool verbose{false};
  const SquareFactory s;
  assert(s.Create("a3"));
  assert(!s.Create("Na3"));
  assert(!s.Create("O-O"));
  assert(s.CreateFromMove("Na3"));
  assert(s.CreateFromMove("a3"));
  assert(!s.CreateFromMove("O-O"));
}
#endif

 

 

 

 

 

./CppChess/chesssquareselector.h

 

#ifndef RIBI_CHESSSQUARESELECTOR_H
#define RIBI_CHESSSQUARESELECTOR_H

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#include <boost/scoped_ptr.hpp>
#include <boost/signals2.hpp>

#include "chesscolor.h"
#include "chessfwd.h"
//#include "chesssquare.h"

#pragma GCC diagnostic pop

namespace ribi {
namespace Chess {

///SquareSelector is the selector of a Chess::BoardWidget
///It consists of an ever-present cursor and a possibly selected square
struct SquareSelector
{
  SquareSelector();

  ///Respond to a click on a certain square
  void Click(
    const boost::shared_ptr<const Square> square,
    const bool can_select_square);

  ///Select the square the cursor is on
  void DoSelect();

  ///The initially selected Square
  static boost::shared_ptr<Square> GetInitialSquare() noexcept;

  ///Obtain the version of this class
  static std::string GetVersion() noexcept;

  ///Obtain the version history of this class
  static std::vector<std::string> GetVersionHistory() noexcept;

  ///Obtain the location of the cursor
  const boost::shared_ptr<const Square> GetCursor() const noexcept { return m_cursor; }

  ///Obtain the location of the cursor
  const boost::shared_ptr<const Square> GetSelected() const noexcept;

  ///Try to move the cursor down
  void MoveDown() noexcept;

  ///Try to move the cursor to the left
  void MoveLeft() noexcept;

  ///Try to move the cursor to the right
  void MoveRight() noexcept;

  ///Try to move the cursor up
  void MoveUp() noexcept;

  ///Convert the SquareSelector to a std::string
  std::string ToStr() const noexcept;

  ///Respond to a change in size
  mutable boost::signals2::signal<void ()> m_signal_changed;

  static const Chess::Color m_cursor_color = Color::green;
  static const Chess::Color m_selected_color = Color::red;
  static const Chess::Color m_moves_color = Color::blue;

  private:
  ~SquareSelector() {}

  ///The Square the cursor is.
  ///There will always be a cursor somewhere
  boost::shared_ptr<const Square> m_cursor;

  ///The selected Square, if any
  boost::shared_ptr<const Square> m_selected;

  friend void boost::checked_delete<>(SquareSelector* x);
};

} //~namespace Chess
} //~namespace ribi

#endif // RIBI_CHESSSQUARESELECTOR_H

 

 

 

 

 

./CppChess/chesssquareselector.cpp

 


#include <cassert>
#include <memory>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#include <boost/lexical_cast.hpp>

#include "chessboard.h"
#include "chessfile.h"
#include "chessmove.h"
#include "chesspiece.h"
#include "chesssquare.h"
#include "chesssquarefactory.h"
#include "chesssquareselector.h"
#include "chessmove.h"
#include "chesswidget.h"
#include "trace.h"
#pragma GCC diagnostic pop

ribi::Chess::SquareSelector::SquareSelector()
  : m_signal_changed{},
    m_cursor(GetInitialSquare()),
    m_selected{}
{
  assert(m_cursor);
}

void ribi::Chess::SquareSelector::Click(
  const boost::shared_ptr<const Square> square,
  const bool can_select_square)
{
  assert(m_cursor);

  //No square selected: set cursor and selector on selected piece
  if (!m_selected)
  {
    m_cursor = square;
    if (can_select_square)
    {
      m_selected = square;
    }
    else
    {
      const boost::shared_ptr<const Square> no_selection;
      m_selected = no_selection;
    }
    m_signal_changed();
  }
  else
  {
    //A square is already selected

    //The selected piece is unselected: set cursor on unselected square, set selector to null
    if (*m_cursor == *m_selected)
    {
      m_cursor = square;
      const boost::shared_ptr<const Square> no_selection;
      m_selected = no_selection;
      m_signal_changed();
    }
    else
    {
      //Another square is selected: keep selector on selected piece
      //Don't care if move is valid:
      //- if move is valid,   piece   is moved and selector is removed
      //- if move is invalid, nothing is moved and selector is removed
      m_cursor = square;
      const boost::shared_ptr<const Square> no_selection;
      m_selected = no_selection;
    }
  }
  assert(m_cursor);
}

void ribi::Chess::SquareSelector::DoSelect()
{
  assert(m_cursor);

  //No square selected
  if (!m_selected)
  {
    m_selected.reset(new Square(*m_cursor));
    m_signal_changed();
  }
  else
  {
    //A square is already selected

    //The selected piece is unselected
    if (*m_cursor == *m_selected)
    {
      const boost::shared_ptr<const Square> no_selection;
      m_selected = no_selection;
      m_signal_changed();
    }
    else
    {
      //Another square is selected
      m_selected.reset(new Square(*m_cursor));
    }
  }
}

boost::shared_ptr<ribi::Chess::Square> ribi::Chess::SquareSelector::GetInitialSquare() noexcept
{
  const std::string s { "c3" };
  return SquareFactory().Create(s);
}

std::string ribi::Chess::SquareSelector::GetVersion() noexcept
{
  return "1.0";
}

const boost::shared_ptr<const ribi::Chess::Square> ribi::Chess::SquareSelector::GetSelected() const noexcept
{
  return m_selected;
}

std::vector<std::string> ribi::Chess::SquareSelector::GetVersionHistory() noexcept
{
  return {
    "2012-01-25: version 1.0: initial version"
  };
}

void ribi::Chess::SquareSelector::MoveDown() noexcept
{
  assert(m_cursor);
  if (m_cursor->GetRank().ToInt() != 7)
  {
    const boost::shared_ptr<const Square> square {
      SquareFactory().Create(
        File(m_cursor->GetFile().ToInt() + 0),
        Rank(m_cursor->GetRank().ToInt() + 1)
      )
    };
    m_cursor = square;

    this->m_signal_changed();
  }
}

void ribi::Chess::SquareSelector::MoveLeft() noexcept
{
  assert(m_cursor);
  if (m_cursor->GetFile().ToInt() != 0)
  {
    const boost::shared_ptr<const Square> square {
      SquareFactory().Create(
        File(m_cursor->GetFile().ToInt() - 1),
        Rank(m_cursor->GetRank().ToInt() + 0)
      )
    };
    m_cursor = square;
    this->m_signal_changed();
  }
}

void ribi::Chess::SquareSelector::MoveRight() noexcept
{
  assert(m_cursor);
  if (m_cursor->GetFile().ToInt() != 7)
  {
    const boost::shared_ptr<const Square> square {
      SquareFactory().Create(
        File(m_cursor->GetFile().ToInt() + 1),
        Rank(m_cursor->GetRank().ToInt() + 0)
      )
    };
    m_cursor = square;
    this->m_signal_changed();
  }
}


void ribi::Chess::SquareSelector::MoveUp() noexcept
{
  assert(m_cursor);
  if (m_cursor->GetRank().ToInt() != 0)
  {
    const boost::shared_ptr<const Square> square {
      SquareFactory().Create(
        File(m_cursor->GetFile().ToInt() + 0),
        Rank(m_cursor->GetRank().ToInt() - 1)
      )
    };
    m_cursor = square;
    this->m_signal_changed();
  }
}

std::string ribi::Chess::SquareSelector::ToStr() const noexcept
{
  assert(m_cursor);
  std::string s = "Cursor: " + m_cursor->ToStr();
  if (m_selected)
  {
    s += ", selected: " + m_selected->ToStr();
  }
  return s;
}

 

 

 

 

 

./CppChess/chesswidget.h

 

#ifndef RIBI_CHESSWIDGET_H
#define RIBI_CHESSWIDGET_H

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#include <boost/checked_delete.hpp>
#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>

#include "chessfwd.h"
#include "widget.h"
#pragma GCC diagnostic pop

namespace ribi {
namespace Chess {

///Chess::ChessWidget is a Widget to interact with a Chess class:
///Where the Chess::Board is very picky about valid moves,
///the Chess::ChessWidget enables simple interaction with it
///Note the name, which is to prevent conflict with the Widget class
struct ChessWidget : public ribi::Widget
{
  enum class Key { up, down, left, right, select };

  ///Emit this signal when the chessboard changes
  mutable boost::signals2::signal<void ()> m_signal_graphic_changed;

  ChessWidget(const Rect& geometry);

  virtual ~ChessWidget() noexcept;

  ///Can do a move?
  virtual bool CanDoMove(
    const boost::shared_ptr<const Square> from,
    const boost::shared_ptr<const Square> to) const noexcept = 0;

  ///Respond to a click
  ///Note: originally, this member function was called Click, but it conflicted with Click(const Square&) :-(
  void ClickPixel(const int x, const int y);

  ///Do a move
  virtual void DoMove(
    const boost::shared_ptr<const Square> from,
    const boost::shared_ptr<const Square> to) = 0;

  ///Obtain the SquareSelector
  boost::scoped_ptr<Chess::SquareSelector>& GetSelector() { return m_selector; }

  ///Obtain the SquareSelector
  const boost::scoped_ptr<Chess::SquareSelector>& GetSelector() const { return m_selector; }

  ///Obtain the version of this class
  static std::string GetVersion();

  ///Obtain the version history of this class
  static std::vector<std::string> GetVersionHistory();

  ///Respond to a key being pressed
  void PressKey(const Chess::ChessWidget::Key key);

  ///Test this class
  static void Test() noexcept;

  ///The Selector (a cursor and possibly a selected square)
  boost::scoped_ptr<Chess::SquareSelector> m_selector;

  ///Respond to a click, transformed click coordinats to a square
  virtual void Click(const boost::shared_ptr<const Chess::Square> square) = 0;

  ///OnChanged is called when the BoardWidget is changed and needs a repaint.
  ///BoardWidget requests for a repaint by emitting m_signal_board_changed
  void OnChanged() const;

  friend void boost::checked_delete<>(ChessWidget* x);
  friend class boost::detail::sp_ms_deleter<      ChessWidget>;
  friend class boost::detail::sp_ms_deleter<const ChessWidget>;

};

} //~namespace Chess
} //~namespace ribi

#endif // RIBI_CHESSWIDGET_H

 

 

 

 

 

./CppChess/chesswidget.cpp

 

#include "chesswidget.h"

#include <cassert>

#include "chessboard.h"
#include "chesspiece.h"
#include "chessgame.h"
#include "chesssquare.h"
#include "chesssquarefactory.h"
#include "chesssquareselector.h"
#include "geometry.h"
#include "trace.h"
#include "testtimer.h"

ribi::Chess::ChessWidget::ChessWidget(const Rect& geometry)
  : m_signal_graphic_changed{},
    m_selector{new SquareSelector}
{
  #ifndef NDEBUG
  ribi::Chess::ChessWidget::Test();
  #endif

  m_selector->m_signal_changed.connect(
    boost::bind(
      &ribi::Chess::ChessWidget::OnChanged,
      this
    )
  );

  this->SetGeometry(geometry);
}

ribi::Chess::ChessWidget::~ChessWidget() noexcept
{
  //All done automatically
}

void ribi::Chess::ChessWidget::ClickPixel(const int x,const int y)
{
  try
  {
    const boost::shared_ptr<Square> square {
      SquareFactory().Create(
        File(8 * x / Geometry().GetWidth( GetGeometry())),
        Rank(8 * y / Geometry().GetHeight(GetGeometry()))
      )
    };
    assert(square);
    this->Click(square);
  }
  catch (std::exception& e)
  {
    //No problem
  }
}

std::string ribi::Chess::ChessWidget::GetVersion()
{
  return "1.0";
}

std::vector<std::string> ribi::Chess::ChessWidget::GetVersionHistory()
{
  return {
    "2012-01-25: version 1.0: initial version"
  };
}

void ribi::Chess::ChessWidget::OnChanged() const
{
  m_signal_graphic_changed();
}

void ribi::Chess::ChessWidget::PressKey(const ChessWidget::Key key)
{
  switch (key)
  {
    case Key::up    : m_selector->MoveUp(); break;
    case Key::right : m_selector->MoveRight(); break;
    case Key::down  : m_selector->MoveDown(); break;
    case Key::left  : m_selector->MoveLeft(); break;
    case Key::select: this->Click(m_selector->GetCursor()); break;
    default: assert(!"Should not get here");
  }
}

void ribi::Chess::ChessWidget::Test() noexcept
{
  //Testing Chess::Widget exactly once
  {
    static bool is_tested = false;
    if (is_tested) return;
    is_tested = true;
  }
  const TestTimer test_timer(__func__,__FILE__,1.0);
  {
    boost::shared_ptr<Widget > w(new Widget);
    w->SetGeometry(Geometry().CreateRect(0.0,0.0,100.0,100.0));
  }
  //Nothing to test

}

 

 

 

 

 

Go back to Richel Bilderbeek's C++ page.

Go back to Richel Bilderbeek's homepage.

 

Valid XHTML 1.0 Strict

This page has been created by the tool CodeToHtml