БлогNot. Одна и та же программка в MVC и MVP

Одна и та же программка в MVC и MVP

Кроме модели MVC, еcть ещё и подход MVP, впрочем, во многом производный от исходного. Доступных несложных листингов, иллюстрирующих сходство и различие MVC и MVP, я как-то не видел. Попробуем выложить такой код для простой игры с числами.

Ну и плюс люблю я всякие игры с числами, здесь уже есть 15, 24, 2048 и т.д., пусть ещё и "21" будет, только не в смысле "21 очко" :) Сама игра довольно примитивна, её правила можно описать так:

Игра для двух игроков, ход делается выбором числа 1, 2 или 3, которое добавляется к текущей сумме выбранных игроками чисел. В начале сумма равна нулю.

Игра выиграна тем, чьё выбранное число приводит к достижению нужной общей суммы, в нашем случае, значения 21.

Ниже показаны 2 листинга игры в MVC- и MVP-подходах. Они проверялись в консоли текущей версии Visual Studio 2019.

// MVC
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <iomanip>
#include <limits>

using namespace std;

class Model {
public:
 static const int GOAL = 21;
 static const int NUMBER_OF_PLAYERS = 2;
 static const int MIN_MOVE = 1;
 static const int MAX_MOVE = 3;
 int bestMove();
 bool update(const char* player, int move);
 bool isGameBegin();
 bool isGameOver();
protected:
 friend class View;
 View* view = nullptr;
 const char* player = nullptr;
 int oldTotal = 0;
 int newTotal = 0;
 int lastMove = 0;
};

class View {
protected:
 Model* model;
public:
 View(Model* model);
 void init(const char* player);
 void update();
};

class Controller {
protected:
 Model* model;
 View* view;
public:
 Controller(Model* model, View* view);
 int input();
 void clear();
 void run();
};

int Model::bestMove() {
 int move = MIN_MOVE;
 for (int i = MIN_MOVE; i <= MAX_MOVE; i++)
  if ((newTotal + i - 1) % (MAX_MOVE + 1) == 0)
   move = i;
 for (int i = MIN_MOVE; i <= MAX_MOVE; i++)
  if (newTotal + i == GOAL)
   move = i;
 return move;
}

bool Model::update(const char* player, int move) {
 if (move >= MIN_MOVE && move <= MAX_MOVE && newTotal + move <= GOAL) {
  this->player = player;
  oldTotal = newTotal;
  newTotal = oldTotal + move;
  lastMove = move;
  view->update();
  return true;
 }
 else return false;
}

bool Model::isGameBegin() {
 return oldTotal == 0;
}

bool Model::isGameOver() {
 return newTotal == GOAL;
}

View::View(Model* model) {
 this->model = model;
 model->view = this;
}

void View::init(const char* player) {
 if (model->newTotal == 0)
  cout << "----NEW GAME----" << endl << endl
  << "The running total is currently zero." << endl
  << "The first move is " << player << " move." << endl << endl;
}

void View::update() {
 cout << setw(8) << model->player << ": " << model->newTotal << " = "
  << model->oldTotal << " + " << model->lastMove << endl << endl;
 if (model->isGameOver())
  cout << endl << "The winner is " << model->player << "." << endl << endl;
}


Controller::Controller(Model* model, View* view) {
 this->model = model;
 this->view = view;
}

void Controller::run() {
 if (rand() % Model::NUMBER_OF_PLAYERS == 0) {
  view->init("AI");
  model->update("AI", model->bestMove());
 }
 else view->init("human");
 while (!model->isGameOver()) {
  while (!model->update("human", input())) clear();
  model->update("AI", model->bestMove());
 }
}

int Controller::input() {
 int value;
 cout << "Enter a valid number to play (or enter 0 to exit game): ";
 cin >> value;
 cout << endl;
 if (!cin.fail()) {
  if (value == 0) exit(EXIT_SUCCESS);
  else return value;
 }
 else return model->MIN_MOVE - 1;
}

void Controller::clear() {
 cout << "Your answer is not a valid choice." << endl;
 cin.clear();
 cin.ignore((streamsize)numeric_limits<int>::max, '\n');
}

int main() {
 srand(time(NULL));
 cout <<
  "21 Game" << endl << endl <<
  "21 is a two player game, the game is played by choosing a number" << endl << 
  "1, 2, or 3 to be added to the running total.  The game is won by" << endl << 
  "the player whose chosen number causes the running total to reach" << endl << 
  "exactly 21. The running total starts at zero." << endl;
 while (true) {
  Model* model = new Model();
  View* view = new View(model);
  Controller* controler = new  Controller(model, view);
  controler->run();
  delete controler;
  delete model;
  delete view;
 }
 return EXIT_SUCCESS;
}

Дальше прикреплён код MVP, в нём контроллеров больше - у каждого из игроков Human и AI имеется свой, а также есть Presenter, собственно, запускающий всё это хозяйство.

// MVP
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <iomanip>
#include <limits>

using namespace std;

class Model {
protected:
 int oldTotal;
 int newTotal;
 int lastMove;
public:
 static const int GOAL = 21;
 static const int NUMBER_OF_PLAYERS = 2;
 Model() {
  newTotal = 0;
  oldTotal = 0;
  lastMove = 0;
 }
 void update(int move) {
  oldTotal = newTotal;
  newTotal = oldTotal + move;
  lastMove = move;
 }
 int getOldTotal() { return oldTotal; }
 int getNewTotal() { return newTotal; }
 int getLastMove() { return lastMove; }
 bool isEndGame() { return newTotal == GOAL; }
};

class View {
public:
 void update(string comment, Model* model) {
  cout << setw(8) << comment << ": " << model->getNewTotal() << " = " << model->getOldTotal()
   << " + " << model->getLastMove() << endl << endl;
 }
 void newGame(string player) {
  cout << "----NEW GAME----" << endl << endl
   << "The running total is currently zero." << endl << endl
   << "The first move is " << player << " move." << endl << endl;
 }
 void endGame(string name) {
  cout << endl << "The winner is " << name << "." << endl << endl << endl;
 }
};

class Controller {
public:
 virtual string getName() = 0;
 virtual int getMove(Model* model) = 0;
};

class AI : public Controller {
public:
 string getName() { return "AI"; }
 int getMove(Model* model) {
  int n = model->getNewTotal();
  for (int i = 1; i <= 3; i++)
   if (n + i == Model::GOAL) return i;
  for (int i = 1; i <= 3; i++)
   if ((n + i - 1) % 4 == 0) return i;
  return 1 + rand() % 3;
 }
};

class Human : public Controller {
public:
 string getName() { return "human"; }
 int getMove(Model* model) {
  int n = model->getNewTotal();
  int value;
  while (true) {
   if (n == Model::GOAL - 1)
    cout << "enter 1 to play (or enter 0 to exit game): ";
   else if (n == Model::GOAL - 2)
    cout << "enter 1 or 2 to play (or enter 0 to exit game): ";
   else
    cout << "enter 1 or 2 or 3 to play (or enter 0 to exit game): ";
   cin >> value;
   if (!cin.fail()) {
    if (value == 0) exit(0);
    else if (value >= 1 && value <= 3 && n + value <= Model::GOAL) {
     cout << endl;
     return value;
    }
   }
   cout << "Your answer is not a valid choice." << endl;
   cin.clear();
   cin.ignore((streamsize)numeric_limits<int>::max, '\n');
  }
 }
};

class Presenter {
protected:
 Model* model;
 View* view;
 Controller** controllers;
public:
 Presenter(Model* model, View* view, Controller** controllers) {
  this->model = model;
  this->view = view;
  this->controllers = controllers;
 }

 void run() {
  int player = rand() % Model::NUMBER_OF_PLAYERS;
  view->newGame(controllers[player]->getName());
  while (true) {
   Controller* controller = controllers[player];
   model->update(controller->getMove(model));
   view->update(controller->getName(), model);
   if (model->isEndGame()) {
    view->endGame(controllers[player]->getName());
    break;
   }
   player = (player + 1) % Model::NUMBER_OF_PLAYERS;
  }
 }
};

int main() {
 srand(time(NULL));
 while (true) {
  Model* model = new Model();
  View* view = new View();
  Controller* controllers[Model::NUMBER_OF_PLAYERS];
  controllers[0] = new Human();
  for (int i = 1; i < Model::NUMBER_OF_PLAYERS; i++) controllers[i] = new AI();
  Presenter* presenter = new Presenter(model, view, controllers);
  presenter->run();
  delete model;
  delete view;
  delete controllers[0];
  delete controllers[1];
  delete presenter;
 }
 return EXIT_SUCCESS;
}

03.11.2020, 15:21 [1180 просмотров]


теги: программирование c++ игра random числа

К этой статье пока нет комментариев, Ваш будет первым