Я разрабатываю небольшую игру для собственного удовольствия и тренировки. Реальная идентичность игры совершенно не имеет отношения к моему фактическому вопросу, предположим, что это Mastermind игра (на самом деле это:)
Моя реальная цель - иметь интерфейс IPlayer
, который будет использоваться для любого игрока: компьютер или человек, консоль или gui, локальная или сетевая. Я также намерен иметь GameController, который будет иметь дело только с двумя IPlayer
s.
интерфейс IPlayer будет выглядеть примерно так:
class IPlayer
{
public:
//dtor
virtual ~IPlayer()
{
}
//call this function before the game starts. In subclasses,
//the overriders can, for example, generate and store the combination.
virtual void PrepareForNewGame() = 0;
//make the current guess
virtual Combination MakeAGuess() = 0;
//return false if lie is detected.
virtual bool ProcessResult(Combination const &, Result const &) = 0;
//Answer to opponent guess
virtual Result AnswerToOpponentsGuess(Combination const&) = 0;
};
Класс GameController сделает следующее:
IPlayer* pPlayer1 = PlayerFactory::CreateHumanPlayer();
IPlayer* pPlayer1 = PlayerFactory::CreateCPUPlayer();
pPlayer1->PrepareForNewGame();
pPlayer2->PrepareForNewGame();
while(no_winner)
{
Guess g = pPlayer1->MakeAguess();
Result r = pPlayer2->AnswerToOpponentsGuess(g);
bool player2HasLied = ! pPlayer1->ProcessResult(g, r);
etc.
etc.
}
В этом дизайне я готов сделать класс GameController неизменным, то есть я нахожу в нем правильные правила игры, и ничего больше, поэтому, поскольку сама игра установлена, этот класс не должен меняться. Для консольной игры этот дизайн будет работать отлично. Я бы имел HumanPlayer
, который в своем методе MakeAGuess
читал бы Combination
со стандартного ввода и CPUPlayer
, который каким-то образом произвольно генерировал бы его и т.д.
Теперь вот моя проблема: интерфейс IPlayer
, а также класс GameController
являются синхронными по своей природе. Я не могу себе представить, как реализовать вариант GUI игры с тем же GameController
, когда методу MakeAGuess
GUIHumanPlayer
придется ждать, например, некоторых движений мыши и кликов. Конечно, я мог бы запустить новый поток, который будет ждать ввода пользователя, в то время как основной поток будет блокироваться, чтобы имитировать синхронный IO, но почему-то эта идея меня отвратительна. Или, альтернативно, я мог бы спроектировать как контроллер, так и плейер для асинхронности. В этом случае для консольной игры мне придется подражать асинхронности, которая кажется более простой, чем первая версия.
Не могли бы вы прокомментировать мой дизайн и мою озабоченность по поводу выбора синхронного или асинхронного дизайна? Кроме того, я чувствую, что больше ответственности отношусь к классу игроков, чем к классу GameController. Etc и т.д.
Спасибо вам заблаговременно.
P.S. Мне не нравится название моего вопроса. Не стесняйтесь редактировать его.