Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用C+的通用Alpha-Beta搜索+;_C++_Algorithm - Fatal编程技术网

C++ 使用C+的通用Alpha-Beta搜索+;

C++ 使用C+的通用Alpha-Beta搜索+;,c++,algorithm,C++,Algorithm,我正在尝试设计一个函数模板来搜索最佳移动 对于任何游戏-当然,此函数模板的用户必须实现 一些特定于游戏的功能。我想做的是概括 带有函数模板的alpha beta搜索算法 此函数模板的声明如下所示: template<class GameState, class Move, class EndGame, class Evaluate, class GetMoves, class MakeMove) int alphaBetaMax(GameState g, int alph

我正在尝试设计一个函数模板来搜索最佳移动 对于任何游戏-当然,此函数模板的用户必须实现 一些特定于游戏的功能。我想做的是概括 带有函数模板的alpha beta搜索算法

此函数模板的声明如下所示:

template<class GameState, class Move,
         class EndGame, class Evaluate, class GetMoves, class MakeMove)
int alphaBetaMax(GameState g, int alpha, int beta, int depthleft);

template天真的问题:游戏状态评估和“游戏已结束”决策不应该是gamestate类中的附加方法(您编写了成员),从而不占用额外的每个实例内存吗?就我个人而言,我会这样写:

int alphaBetaMax(GameState *g, Move *move, EndGame *endgame, 
    Evaluate *evaluate, GetMoves* getmoves, MakeMove* makemove, 
    int alpha, int beta, int depthleft);
你可以称之为:

GameState gs;
alphaBetaMax(&gs, new ChessMove(), new ChessEndGame(), new ChessEvaluate(),
    new ChessGetMoves(), new ChessMakeMove(), a, b, 40);
函数本身会删除除gamestate之外的所有指针(我假设这就是函数返回结果的地方,其他的都是临时的?)


现在做这一切更好的方法是只通过一个可以做任何事情的类,因为“makemove”,“getmove”,“evaluate”,它们都是相同逻辑的一部分。没有理由制作5个不同的类,C++允许你在一个类中重写多个虚拟函数。

你可以定义一个抽象的界面,比如游戏特性,并且每个游戏都有专门的游戏特性实现:

template<typename Game>
class game_traits {
  ...
};

class Chess {
  ...
};

template<>
class game_traits<Chess> {
  static bool endGame(Chess game);
  ...
};

template <typename Game, typename traits = game_traits<Game> >
int alphaBetaMax(Game game, int alpha, int beta, int depthleft) {
  ended = traits::endGame(game);
  ...
}
模板
班级游戏特点{
...
};
国际象棋{
...
};
模板
班级游戏特点{
静态布尔终局(国际象棋);
...
};
模板
int alphaBetaMax(游戏游戏,int alpha,int beta,int depthleft){
结束=特征::结束游戏(游戏);
...
}
C++标准库中的字符特征如何使用。

或者,您可以使它们成为游戏类的方法,这里不需要从某个抽象类继承,因为您将它作为模板参数提供。当模板函数尝试访问时,例如game.has_ended(),可能会出现一个不太透明的编译错误,而此时不存在这样的方法。这种机制在标准模板库中也被大量使用

顺便说一句,有一个新的功能计划在此;概念:

auto concept GameType<typename Game>
{
  bool has_ended(Game&);
  ...
};

template<typename Game> requires GameType<Game>
int alphaBetaMax(Game game, int alpha, int beta, int depthleft) {
  bool ended = game.has_ended();
  ...
}
自动概念游戏类型
{
布尔结束了(比赛&);
...
};
模板需要游戏类型
int alphaBetaMax(游戏游戏,int alpha,int beta,int depthleft){
bool end=游戏结束了吗;
...
}

不幸的是,概念被推迟到了标准的未来版本,并且还不会出现在c++0x:(

据我所知,我将对一些内容进行汇总:

  • GameState、EndGame、GetMoves、Evaluate-使用单一特征类型GameStateTraits包装
  • MakeMove是独立算法的职责,因此GameMovePolicy
我有意将特征和策略区分为单独的类型。正如Boost所解释的,特征通常携带类型信息,即类型属性的描述。这种想法非常适合携带静态信息,即游戏状态。策略提供行为-MakeMove是游戏动态行为算法的一部分

template<typename GameStateTraits, typename GameMovePolicy>
int alphaBetaMax(GameStateTraits const& state, int alpha, int beta, int depthleft);
模板
int alphaBetaMax(GameStateTraits const&state、int alpha、int beta、int depthleft);

向类中添加方法不会使该类的对象变大。这些方法为整个类存储一次,并由对任何实例的调用使用。因此,向GameState类中添加函数不会导致算法需要更多内存

然后,函数模板将只需要单个参数
GameState
,而作为该参数使用的类将需要实现正确的方法

更灵活的方法是在算法中简单地使用自由函数:

template<class GameState>
int alphaBetaMax(GameState g, int alpha, int beta, int depthleft) {
   if (endGame(g)) {
     return 1;
   }
   std::vector<Move> moves = getMoves(g);
   // ...   
}
通过这种方式,您可以使任何GameState对象适应您的算法,而无需对这些对象使用特殊方法。为了避免这些新函数污染全局命名空间,您可以将它们放入它们自己的命名空间或traits类中


因此,基本上您可以省略其他模板参数,只要在实例化模板后定义了正确名称和类型的函数。

太多了?为什么它是一个模板?这正是使用模板时需要注意的那种“用无限的锤子敲钉子”。尤其是像AI一样,大多数问题都是难以处理的,性能是至关重要的。

我被一个需要六个不同类的模板函数所吓坏,但是我对这个SO 1的答案很好奇。):我不知道C++的深度,但是我认为一个类的附加部分需要一些内存。例如,Tic-Tac-Toe游戏的游戏状态只能由一个int表示。不,一旦您决定拥有一个真正的类(即Tic-Tac-Toe除外),其他方法就不会有任何实例内存开销。非虚方法被编译成函数调用。虚拟方法是在方法表中引用的,这是事实,但是类只有一个这样的表。所有实例都只使用指向它的指针。我的目的是设计一种类似stl算法的通用方法。但是,也许通用方法(6个模板参数)的缺点让我想到了一个抽象的GameState基类。感谢抽象接口(game_traits)的提示,我必须了解它以及stl如何使用这个概念。如果我在一个名称空间中给函数getMoves、endGame,alhpaBetaMax必须知道这个名称空间?为了清楚起见:Move必须是一个模板参数(它是特定于游戏的),因为您只将GameState声明为模板参数。到目前为止,我还不知道traits的概念,多亏了大家的提示。关于名称空间:想法是将这些函数放在
alphabeta
名称空间中,让算法使用这个名称空间中的函数。另外,在为新游戏状态类型实现新功能时,将它们放入
alphabeta
命名空间中。这样,所有特定于此算法的辅助函数都是conf
struct MyGameState {};

bool endGame(const MyGameState &st) {
  return false;
}

std::vector<Move> getMoves(const MyGameState &st) {
  // ...
}

void tst() {
  MyGameState s;
  alphaBetaMax(s, 1, 1, 1); // uses the new functions
}