如果您希望所有游戏都继承自同一个 game_base 基类,那么您需要使用这些游戏的人不“知道”他们正在玩什么游戏。
我是什么意思?你问了
例如,如果 move 是 player 内部的一个函数,那么除了通过类型检查之外,该函数如何知道是按照井字游戏规则还是四连线规则移动?
让我问你这个问题 - 说你确实像你描述的那样解决了这个问题。现在你想添加一个新游戏(比如跳棋)。您是否需要更改player 才能知道如何玩跳棋?
如果是这样 - 那么你的游戏不应该使用继承(不应该全部继承自 game_base
为什么?因为基本上你是在说“我的player 课程必须内置所有游戏的所有可能性”。如果是这样,为什么有不同的游戏类?
作为解决方案,我会这样说:
- 如果人类玩家需要根据井字游戏或四连线移动,它会如何分类? GAME 类应该告诉它!不仅如此——假设玩家根本不了解这款游戏!告诉玩家当前的合法动作是什么!
一个例子:
class game_base{
// returns the number of players in this game.
// Doesn't change during play
virtual int num_players() = 0;
// returns the current player - the player whose turn it is now
virtual int curr_player() = 0;
// returns a string that describes (or draws) the current
// game state
virtual std::string draw_board()const = 0;
// returns all the possible legal moves the player can
// make this turn
virtual std::vector<std::string> curr_turn_possible_moves()const = 0;
// Plays the given move. Has to be one of the moves
// returned by curr_turn_possible_moves()
virtual void play(std::string move) = 0;
// returns the player who won the game, or -1 if the
// game is still ongoing
virtual int won() = 0;
};
看看如何使用这个游戏类,让同一个 player 类可以玩你曾经制作的所有游戏!
您甚至可以制作一个适用于所有游戏的“检查所有选项,直至 N 级深度”!
- 关于电脑玩家:您可以制作一个“通用”电脑玩家,尝试向前走 N 步以寻找获胜策略(您需要将选项添加到
virtual game_base *copy()const 当前游戏状态)。但实际上,您需要为每个游戏量身定制的电脑播放器(只玩该游戏)。
那么你是怎么做到的呢?更重要的是 - 你怎么知道每个游戏选择哪个电脑玩家?
所有计算机玩家都将继承自 computer_player_base 类(它可能只有一个函数 play 在给定游戏的情况下执行下一步)。诀窍是 - 如果您现在想为游戏添加新的计算机玩家(新游戏或现有游戏的另一个可能的计算机玩家),您需要一种“注册”该玩家的方法。你想要的东西看起来像:
std::vector<computer_player_base*> possible_computer_players(const game_base*game);
返回所有可能知道如何玩给定游戏的计算机玩家。最简单的方法是让计算机玩家类本身告诉你它是否可以玩给定的游戏。所以它看起来像这样:
class computer_player_base{
// return true if this class knows how to play this game
// implemented using dynamic_cast - something like this:
// return dynamic_cast<connect_4*>(game) != 0;
virtual bool can_play(game_base *game) = 0;
// plays the next turn of the game
virtual void play(game_base *game) = 0;
};
然后有一个可供选择的所有计算机播放器的全局列表,例如
std::vector<computer_player_base*> all_computer_players
您将填充每个计算机播放器中的一个,以及一个函数
std::vector<computer_player_base*> possible_computer_players(game_base *game)
{
std::vector<computer_player_base*> res;
for (auto p:all_computer_players)
if (p->can_play(game))
res.push_back(p);
return res;
}