From be0ddf9f283596d779e60de3870fa9b58f35c65b Mon Sep 17 00:00:00 2001 From: Paolo Capriotti Date: Wed, 25 Jul 2007 13:57:47 +0200 Subject: [PATCH] Moved ICS related API to the ICSAPI abstract class. Variants implement all ICS-related functions in a concrete subclass of ICSAPI, returned from the VariantInfo::icsAPI function. Variants using the template wrapper framework, should define a static const bool "hasICS" variable inside their VariantInfo structure, depending on whether they want to support ICS or not. The framework will create a ICSAPI subclass automagically when the variable is set to true. If the "hasICS" variable is set to true, then the variant position should have a constructor that takes the style12 data, and a PieceFactory specialization. --- src/CMakeLists.txt | 1 + src/entities/icsentity.cpp | 5 ++-- src/fwd.h | 2 ++ src/icsapi.h | 57 +++++++++++++++++++++++++++++++++++++++++++ src/icsapi.impl.h | 41 +++++++++++++++++++++++++++++++ src/icsconnection.cpp | 59 +++++++++++++++++++-------------------------- src/icsgamedata.cpp | 37 ++++++++++++++++++++++++++++ src/icsgamedata.h | 14 +++++++---- src/poolinfo.cpp | 13 ++++++++++ src/poolinfo.h | 4 +-- src/positioninfo.cpp | 26 ++++++++++++-------- src/positioninfo.h | 3 ++- src/tagua.h | 42 +++++++++++++++----------------- src/tagua_wrapped.h | 36 ++++++++++++++++----------- src/variants/chess.cpp | 1 + src/variants/chess.h | 1 + src/variants/crazyhouse.cpp | 2 ++ src/variants/shogi.cpp | 3 +++ 18 files changed, 256 insertions(+), 91 deletions(-) create mode 100644 src/icsapi.h create mode 100644 src/icsapi.impl.h create mode 100644 src/icsgamedata.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fa76a48..b688a9c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -89,6 +89,7 @@ set(tagua_SRC option_p.cpp themeinfo.cpp namedsprite.cpp + icsgamedata.cpp ) # remove spurious xpressive warnings diff --git a/src/entities/icsentity.cpp b/src/entities/icsentity.cpp index 4edc3c3..e30da5e 100644 --- a/src/entities/icsentity.cpp +++ b/src/entities/icsentity.cpp @@ -110,10 +110,11 @@ void ICSEntity::notifyStyle12(const PositionInfo& style12, bool is_starting) { } void ICSEntity::notifyPool(const PoolInfo& pi) { - if(pi.m_game_num != m_game_number) + if (pi.m_game_num != m_game_number) return; - if(m_game->containsIndex(pi.m_pos_index)) { + return; // BROKEN + if (m_game->containsIndex(pi.m_pos_index)) { AbstractPosition::Ptr p = m_game->position(pi.m_pos_index); //BROKEN //p->setPool(pi.m_pool); diff --git a/src/fwd.h b/src/fwd.h index d37b555..3f066af 100644 --- a/src/fwd.h +++ b/src/fwd.h @@ -15,8 +15,10 @@ typedef boost::shared_ptr MovePtr; typedef boost::shared_ptr PositionPtr; +typedef boost::shared_ptr PoolPtr; typedef boost::shared_ptr PiecePtr; typedef boost::shared_ptr AnimatorPtr; +typedef boost::shared_ptr ICSAPIPtr; typedef boost::shared_ptr VariantPtr; template class UnwrappedGraphicalAPI; diff --git a/src/icsapi.h b/src/icsapi.h new file mode 100644 index 0000000..0e9eb1a --- /dev/null +++ b/src/icsapi.h @@ -0,0 +1,57 @@ +/* + Copyright (c) 2007 Paolo Capriotti + (c) 2007 Maurizio Monge + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. +*/ + +#ifndef ICSAPI_H +#define ICSAPI_H + +#include "tagua.h" + +class ICSAPI { +public: + virtual ~ICSAPI() { } + + /** + * Create a position using the information of a style12 line. + * \param turn Current turn. + * \param wkCastle King-side castling is possible for white + * \param wqCastle Queen-side castling is possible for white + * \param bkCastle King-side castling is possible for black + * \param bqCastle Queen-side castling is possible for black + * \param ep En-passant square. + */ + virtual PositionPtr createChessboard( + int turn, + bool wkCastle, + bool wqCastle, + bool bkCastle, + bool bqCastle, + const Point& ep) = 0; + + + /** + * Create a new piece using the given description string. + * \param description A string representing the piece to be created. Its + * meaning is defined by the variant. + * \return A newly created piece. + */ + virtual AbstractPiece::Ptr createPiece(const QString& description) = 0; +}; + +// wrapper + +template +class WrappedICSAPI : public ICSAPI { +public: + virtual PositionPtr createChessboard(int, bool, bool, bool, bool, const Point&); + virtual PiecePtr createPiece(const QString& description); +}; + +#endif // ICSAPI_H + diff --git a/src/icsapi.impl.h b/src/icsapi.impl.h new file mode 100644 index 0000000..c343158 --- /dev/null +++ b/src/icsapi.impl.h @@ -0,0 +1,41 @@ +/* + Copyright (c) 2006 Paolo Capriotti + (c) 2006 Maurizio Monge + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. +*/ + +#ifndef ICSAPI_IMPL_H +#define ICSAPI_IMPL_H + +#include "tagua_wrapped.h" +#include "piecefactory.h" + +template +PositionPtr WrappedICSAPI::createChessboard( + int turn, + bool wkCastle, + bool wqCastle, + bool bkCastle, + bool bqCastle, + const Point& ep) { + return PositionPtr( + new WrappedPosition(typename Variant::Position( + static_cast(turn), + wkCastle, wqCastle, bkCastle, bqCastle, ep))); +} + + + +template +PiecePtr WrappedICSAPI::createPiece(const QString& description) { + return AbstractPiece::Ptr(new WrappedPiece( + PieceFactory::createPiece(description))); +} + + +#endif // ICSAPI_IMPL_H + diff --git a/src/icsconnection.cpp b/src/icsconnection.cpp index 5d8b720..8a4f994 100644 --- a/src/icsconnection.cpp +++ b/src/icsconnection.cpp @@ -12,8 +12,6 @@ #include #include -#include - #include "icsconnection.h" #include "poolinfo.h" #include "positioninfo.h" @@ -25,7 +23,6 @@ #include "variants/variants.h" using namespace boost; -using namespace boost::xpressive; QRegExp ICSConnection::pressReturn("^Press return to enter the server as \"\\S+\":"); @@ -244,8 +241,8 @@ void ICSConnection::process(QString str) { else { PoolInfo pool_info(m_games, str); if (pool_info.m_valid) { - if (!(m_games[pool_info.m_game_num].variant == "crazyhouse" - && pool_info.m_added_piece)) { + // BROKEN + if (!pool_info.m_added_piece) { if (shared_ptr listener = m_games[pool_info.m_game_num].listener.lock()) listener->notifyPool(pool_info); } @@ -279,7 +276,7 @@ void ICSConnection::process(QString str) { m_move_list_game_info->setGameNumber(m_move_list_game_num); //NOTE: here is where an unknown variant will be "upgraded" to the correct variant - m_games[m_move_list_game_num].variant = move_list_game.cap(2); + m_games[m_move_list_game_num].setType(move_list_game.cap(2)); } else if (test(move_list_terminator, str)) { //std::cout << "move list ign3: " << str << std::endl; @@ -306,24 +303,32 @@ void ICSConnection::process(QString str) { if (test(move_list_terminator, str)){ if (shared_ptr listener = m_games[m_move_list_game_num].listener.lock()) { AbstractPosition::Ptr p; - if(m_move_list_position_info) + if (m_move_list_position_info) p = m_move_list_position_info->position; else { - QString v = m_games.count(m_move_list_game_num) - ? m_games[m_move_list_game_num].variant : "unknown"; - p = Variant::variant(GameInfo::variantCode(v))->createPosition(); - p->setup(); + std::map::const_iterator gi = m_games.find(m_move_list_game_num); + if (gi == m_games.end()) { + ERROR("BUG: Received move list for unknown game " << m_move_list_game_num); + } + else { + VariantInfo* variant = gi->second.variant; + p = variant->createPosition(); + p->setup(); + } } - if (m_move_list_pool_info) { - //BROKEN - //p->setPool(m_move_list_pool_info->m_pool); + + if (p) { + if (m_move_list_pool_info) { + //BROKEN + //p->setPool(m_move_list_pool_info->m_pool); + } + + PGN pgn(m_move_list); + if (!pgn.valid()) + std::cout << "parse error on move list" << std::endl; + else + listener->notifyMoveList(m_move_list_game_num, p, pgn); } - - PGN pgn(m_move_list); - if (!pgn.valid()) - std::cout << "parse error on move list" << std::endl; - else - listener->notifyMoveList(m_move_list_game_num, p, pgn); } if (m_move_list_game_info) @@ -359,17 +364,3 @@ void ICSConnection::startup() { sendText("set style 12"); } -static void test() { - std::string hello("hello world!"); - - sregex rex = sregex::compile("(\\w+) (\\w+)!"); - smatch what; - - if (regex_match(hello, what, rex)) - { - std::cout << what[0] << '\n'; // whole match - std::cout << what[1] << '\n'; // first capture - std::cout << what[2] << '\n'; // second capture - } -} - diff --git a/src/icsgamedata.cpp b/src/icsgamedata.cpp new file mode 100644 index 0000000..006f49e --- /dev/null +++ b/src/icsgamedata.cpp @@ -0,0 +1,37 @@ +/* + Copyright (c) 2006-2007 Paolo Capriotti + (c) 2006-2007 Maurizio Monge + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. +*/ + +#include "icsgamedata.h" +#include "tagua.h" +#include "gameinfo.h" +#include "variants/variants.h" + +ICSGameData::ICSGameData() +: index(0) { + setType(""); +} + +ICSGameData::ICSGameData(int index, const QString& type) +: index(index) { + setType(type); +} + +void ICSGameData::setType(const QString& type) { + variant = Variant::variant(GameInfo::variantCode(type)); + if (!variant) { + ERROR("BUG: No variant corresponding to " << type); + } + else if (!(icsapi = variant->icsAPI())) { + // There's no ICSAPI in this variant. + // This means we cannot use it for ICS stuff, so we + // fall back to the dummy variant. + // TODO + } +} diff --git a/src/icsgamedata.h b/src/icsgamedata.h index 5f5b3fe..5b791a3 100644 --- a/src/icsgamedata.h +++ b/src/icsgamedata.h @@ -14,17 +14,21 @@ #include #include +#include "fwd.h" + class ICSListener; +class VariantInfo; struct ICSGameData { int index; - QString variant; + VariantInfo* variant; + ICSAPIPtr icsapi; boost::weak_ptr listener; - ICSGameData() - : index(0) { } - ICSGameData(int index, const QString& variant) - : index(index), variant(variant) { } + ICSGameData(); + ICSGameData(int index, const QString& type); + + void setType(const QString& var); }; #endif // ICSGAMEDATA_H diff --git a/src/poolinfo.cpp b/src/poolinfo.cpp index fdaf44b..e90d159 100644 --- a/src/poolinfo.cpp +++ b/src/poolinfo.cpp @@ -23,6 +23,19 @@ PoolInfo::PoolInfo(const std::map& games, const QString& str) : m_valid(false) , m_pos_index(-1) { +// if (s_pattern.indexIn(str) != 0) +// return; +// +// m_game_num = s_pattern.cap(1).toInt(); +// std::map::const_iterator gi = games.find(m_game_num); +// if (gi == games.end()) +// return; +// +// QString var = !gi->second.variant.isEmpty() ? gi->second.variant : QString("chess"); +// VariantInfo* variant = Variant::variant(GameInfo::variantCode(var)); +// m_pos_index = gi->second.index; +// +// m_pool = //BROKEN #if 0 if (s_pattern.indexIn(str) != 0) diff --git a/src/poolinfo.h b/src/poolinfo.h index ca6d1fc..33ed4f5 100644 --- a/src/poolinfo.h +++ b/src/poolinfo.h @@ -22,8 +22,8 @@ public: bool m_valid; int m_game_num; Index m_pos_index; - AbstractPool::Ptr m_pool[2]; - AbstractPiece::Ptr m_added_piece; + PoolPtr m_pool[2]; + PiecePtr m_added_piece; static QRegExp s_pattern; PoolInfo(const std::map& games, const QString& s); diff --git a/src/positioninfo.cpp b/src/positioninfo.cpp index 79bc97b..4451ec6 100644 --- a/src/positioninfo.cpp +++ b/src/positioninfo.cpp @@ -1,6 +1,6 @@ /* - Copyright (c) 2006 Paolo Capriotti - (c) 2006 Maurizio Monge + Copyright (c) 2006-2007 Paolo Capriotti + (c) 2006-2007 Maurizio Monge This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -12,6 +12,7 @@ #include "variants/chess.h" #include "variants/variants.h" #include "gameinfo.h" +#include "icsapi.h" using namespace boost; @@ -51,14 +52,14 @@ QRegExp PositionInfo::pattern( ); -PositionInfo::PositionRow::PositionRow(VariantInfo* variant, const QString& str) { +PositionInfo::PositionRow::PositionRow(const ICSAPIPtr& icsapi, const QString& str) { Q_ASSERT(str.length() == 8); row.resize(str.length()); for (int i = 0; i < str.length(); ++i) { QChar c = str[i]; - row[i] = variant->createPiece(c); + row[i] = icsapi->createPiece(c); } } @@ -77,17 +78,22 @@ PositionInfo::PositionInfo(const std::map& games, const QStrin return; } - VariantInfo* variant; valid = true; int gn = pattern.cap(CaptureIndexes::GameNumber).toInt(); std::map::const_iterator gi = games.find(gn); - QString var = (gi != games.end() && !gi->second.variant.isEmpty()) - ? gi->second.variant : QString("chess"); - variant = Variant::variant(GameInfo::variantCode(var)); + ICSAPIPtr icsapi; + + if (gi == games.end()) { + ERROR("Received style12 for unknown game " << gn); + icsapi = Variant::variant("Dummy")->icsAPI(); + } + else { + icsapi = gi->second.icsapi; + } std::vector rows; for (uint i = 0; i < 8; ++i) - rows.push_back(PositionRow(variant, pattern.cap(CaptureIndexes::ChessboardStart + i))); + rows.push_back(PositionRow(icsapi, pattern.cap(CaptureIndexes::ChessboardStart + i))); gameNumber = pattern.cap(CaptureIndexes::GameNumber).toInt(); moveIndex = pattern.cap(CaptureIndexes::MoveOrdinal).toInt(); @@ -106,7 +112,7 @@ PositionInfo::PositionInfo(const std::map& games, const QStrin bool bkCastle = pattern.cap(CaptureIndexes::BlackKingCastle).toInt() == 1; bool bqCastle = pattern.cap(CaptureIndexes::BlackQueenCastle).toInt() == 1; - position = variant->createChessboard(turn, wkCastle, wqCastle, bkCastle, bqCastle, enPassantSquare); + position = icsapi->createChessboard(turn, wkCastle, wqCastle, bkCastle, bqCastle, enPassantSquare); for (uint i = 0; i < 8; ++i) { for (uint j = 0; j < rows[i].row.size(); ++j) { position->set(Point(j,i), rows[i].row[j]); diff --git a/src/positioninfo.h b/src/positioninfo.h index 23f7abc..bd54a8c 100644 --- a/src/positioninfo.h +++ b/src/positioninfo.h @@ -18,6 +18,7 @@ #include "tagua.h" #include "icsgamedata.h" +#include "fwd.h" class PositionInfo { public: @@ -62,7 +63,7 @@ public: class PositionRow { public: std::vector row; - explicit PositionRow(VariantInfo* variant, const QString& str); + explicit PositionRow(const ICSAPIPtr& icsapi, const QString& str); }; static QRegExp pattern; diff --git a/src/tagua.h b/src/tagua.h index 5838652..804d449 100644 --- a/src/tagua.h +++ b/src/tagua.h @@ -11,9 +11,21 @@ #ifndef LOWLEVEL_H #define LOWLEVEL_H +#include +#include +#include +#include +#include "point.h" +#include "usermove.h" +#include "index.h" +#include "option.h" +#include "decoratedmove.h" +#include "interactiontype.h" +#include "turntest.h" +#include "fwd.h" class GraphicalAPI; - +class ICSAPI; /** * @file tagua.h @@ -46,19 +58,6 @@ class GraphicalAPI; * kept in variables of abstract types. */ -#include -#include -#include -#include -#include "point.h" -#include "usermove.h" -#include "index.h" -#include "option.h" -#include "decoratedmove.h" -#include "interactiontype.h" -#include "turntest.h" -#include "fwd.h" - /** * @brief A superclass for all the piece classes. @@ -353,7 +352,6 @@ public: virtual AbstractPosition::Ptr createPosition() = 0; virtual AbstractPosition::Ptr createCustomPosition(const OptList& l) = 0; virtual AbstractPosition::Ptr createPositionFromFEN(const QString& fen) = 0; - virtual AbstractPosition::Ptr createChessboard(int turn, bool, bool, bool, bool, const Point&) = 0; virtual void forallPieces(class PieceFunction&) = 0; virtual int moveListLayout() const = 0; virtual AbstractAnimator::Ptr createAnimator(GraphicalAPI* graphical_api) = 0; @@ -362,14 +360,6 @@ public: virtual AbstractMove::Ptr getVerboseMove(int turn, const class VerboseNotation&) const = 0; /** - * Create a new piece using the given description string. - * \param description A string representing the piece to be created. Its - * meaning is defined by the variant. - * \return A newly created piece. - */ - virtual AbstractPiece::Ptr createPiece(const QString& description) = 0; - - /** * \return if moves are done by just clicking */ virtual bool simpleMoves() = 0; @@ -389,6 +379,12 @@ public: * \return the (subvariant) options that can be specified for position creation, such as board size, etc */ virtual OptList positionOptions() const = 0; + + /** + * \return The ICS API for this variant, or a null pointer, if the variant does not support + * ICS (in that case a Dummy variant will be used). + */ + virtual ICSAPIPtr icsAPI() const = 0; }; #endif // LOWLEVEL_H diff --git a/src/tagua_wrapped.h b/src/tagua_wrapped.h index a1abcf4..1c18007 100644 --- a/src/tagua_wrapped.h +++ b/src/tagua_wrapped.h @@ -14,6 +14,7 @@ #include #include #include "common.h" +#include "icsapi.h" #include "tagua.h" #include "movefactory.h" #include "piecefactory.h" @@ -76,6 +77,24 @@ template class WrappedPosition; #define TYPECHECK(x,y) if (typeid(x) != typeid(y)) MISMATCH(x,y); else { } +/** + * Helper metafunction to create a null ICSAPI object + * if the variant does not support ICS. + */ +template +struct ReturnICSAPI { }; + +template +struct ReturnICSAPI { + static ICSAPI* apply() { + return new WrappedICSAPI(); + } +}; + +template +struct ReturnICSAPI { + static ICSAPI* apply() { return 0; } +}; template @@ -514,15 +533,6 @@ public: } else return AbstractPosition::Ptr(); } - - virtual AbstractPosition::Ptr createChessboard(int turn, - bool wk, bool wq, bool bk, bool bq, - const Point& ep) { - return AbstractPosition::Ptr( - new WrappedPosition(Position( - static_cast(turn), - wk, wq, bk, bq, ep))); - } virtual void forallPieces(class PieceFunction& f) { Variant::forallPieces(f); } @@ -549,11 +559,6 @@ public: return AbstractMove::Ptr(new WrappedMove(res)); } - virtual AbstractPiece::Ptr createPiece(const QString& description) { - return AbstractPiece::Ptr(new WrappedPiece( - PieceFactory::createPiece(description))); - } - virtual int type(const QString& str) { return Piece::getType(str); } @@ -572,6 +577,9 @@ public: virtual OptList positionOptions() const { return Variant::positionOptions(); } + virtual ICSAPIPtr icsAPI() const { + return ICSAPIPtr(ReturnICSAPI::apply()); + } }; #endif // HIGHLEVEL_H diff --git a/src/variants/chess.cpp b/src/variants/chess.cpp index 24ac31b..dd50e75 100644 --- a/src/variants/chess.cpp +++ b/src/variants/chess.cpp @@ -13,6 +13,7 @@ #include "variants/chess.h" #include "common.h" #include "tagua_wrapped.h" +#include "icsapi.impl.h" #include "moveserializer.impl.h" #include "xchess/animator.impl.h" #include "piecefunction.h" diff --git a/src/variants/chess.h b/src/variants/chess.h index a36d014..635be70 100644 --- a/src/variants/chess.h +++ b/src/variants/chess.h @@ -34,6 +34,7 @@ struct ChessVariant { typedef SimpleAnimator Animator; typedef NoPool Pool; + static const bool hasICS = true; static const bool m_simple_moves = false; static const char *m_name; static const char *m_theme_proxy; diff --git a/src/variants/crazyhouse.cpp b/src/variants/crazyhouse.cpp index ad5a1c9..22c3060 100644 --- a/src/variants/crazyhouse.cpp +++ b/src/variants/crazyhouse.cpp @@ -11,6 +11,7 @@ #include "crazyhouse_p.h" #include "crazyhouse.h" #include "tagua_wrapped.h" +#include "icsapi.impl.h" #include "xchess/dropanimator.impl.h" #include "animation.h" #include "animationfactory.h" @@ -25,6 +26,7 @@ public: typedef DropAnimatorMixin > Animator; + static const bool hasICS = true; static const bool m_simple_moves = false; static void forallPieces(PieceFunction& f); static int moveListLayout(){ return 0; } diff --git a/src/variants/shogi.cpp b/src/variants/shogi.cpp index 11ccd46..461f3ab 100644 --- a/src/variants/shogi.cpp +++ b/src/variants/shogi.cpp @@ -18,6 +18,7 @@ #include "interactiontype.h" #include "turntest.h" #include "tagua_wrapped.h" +#include "icsapi.impl.h" class ShogiPiece { public: @@ -607,6 +608,8 @@ public: typedef Position::Piece Piece; typedef DropAnimatorMixin Animator; typedef NoPool Pool; + + static const bool hasICS = false; static const bool m_simple_moves = false; static void forallPieces(PieceFunction& f); static int moveListLayout() { return 0; } -- 2.11.4.GIT