Estoy diseñando un pequeño juego para mi propia diversión y para el entrenamiento. La verdadera identidad del juego es bastante irrelevante para mi pregunta real, supongo que es el juego Mastermind (que en realidad es :)Diseño común para consola y GUI
Mi verdadero objetivo aquí es tener una interfaz IPlayer
que se utilizará para cualquier jugador: computadora o humano, consola o gui, local o de red. También tengo la intención de tener un GameController, que se ocupará solo de dos IPlayer
s.
la interfaz iPlayer sería algo como esto:
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's guess
virtual Result AnswerToOpponentsGuess(Combination const&) = 0;
};
La clase GameController haría algo como esto:
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.
}
Mediante este diseño, estoy dispuesto a hacer la clase GameController inmutable, que Es decir, incluyo las reglas del juego justo en él, y nada más, así que como el juego en sí está establecido, esta clase no debería cambiar. Para un juego de consola, este diseño funcionaría perfectamente. Tendría HumanPlayer
, que en su método MakeAGuess
leería un Combination
de la entrada estándar, y una CPUPlayer
, lo que generaría alguna manera al azar que etc.
Ahora aquí está mi problema: La interfaz IPlayer
, junto con la clase GameController
, son sincrónicos en su naturaleza. No puedo imaginar cómo implementaría la variante de GUI del juego con el mismo GameController
cuando el método MakeAGuess
de GUIHumanPlayer
tendría que esperar, por ejemplo, algunos movimientos y clics del mouse. Por supuesto, podría lanzar un nuevo hilo que esperaría la entrada del usuario, mientras que el hilo principal se bloquearía, para imitar el IO sincrónico, pero de alguna manera esta idea me repugna. O, como alternativa, podría diseñar tanto el controlador como el reproductor para que sean asíncronos. En este caso, para un juego de consola, tendría que imitar la asincronía, que parece más fácil que la primera versión.
¿Podría comentar sobre mi diseño y mis inquietudes sobre elegir un diseño sincrónico o asincrónico? Además, siento que pongo más responsabilidad en la clase de jugador que en la clase GameController. Etc, etc.
Muchas gracias de antemano.
P.S. No me gusta el título de mi pregunta. Se sienten libres para editarlo :)
Me gusta el título :-) –
Quité la etiqueta C#, ya que no hay C# en cualquier lugar cerca de esta pregunta. – Puppy
Dado que el idioma es irrelevante, espero obtener también la opinión de los expertos de C# –