Одна и та же программка в 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 просмотров]