The next step in building an MVC app is planning what goes in to your controller. Let's dive in!
How Do You Plan Out the Controller?
The controller is responsible for sequencing user interactions. Here's the game sequence:
Create the deck.
Enter player names.
Shuffle the cards.
Deal a card to each player.
Flip over the cards.
Evaluate the winner.
Display the winner.
Reconstitute the deck.
How does the controller know what’s been inputted?
The input command comes from the view. Remember that the view has two purposes: it presents the information to the user and requests any input from them.
Now we need to look at the step sequence above and find the interactions between the controller and view.
Start the Game
The first step of any interaction is to instantiate the model. The controller receives or builds the core game objects. These are the deck and an empty list of players.
It also needs to know about the view. The view should be created elsewhere and passed to the controller, rather than having the controller make its own.
Why are we passing the view into the controller, instead of just letting the controller make it?
Well, if you were to create a mobile version of this application, it would need a completely different user interface (view). You'd then have to modify the controller. In MVC, each of the model, view, and controller should be replaceable without touching the other components.
Entering Player Names
For every player who puts their name in the view, the controller should create a Player object and add it to its list of players (in the model).
Indicating Name Entry Is Complete
The controller also needs to know when all players have been added so it can start dealing cards etc.
The controller shuffles the deck, and then for each player, it removes the top card from the deck to put into that player’s hand (all in the model).
The controller flips over each player’s card and then evaluates the winner.
The cards are taken back from the player and put back into the deck. The game can then restart from the dealing stage.
How Do You Implement the Controller?
The controller should have methods corresponding to the different stages of the game. They can use any model objects, request information from the user via the view, and present information to the view.
Let's create these methods together! First, download this file: card-game-p2-ch6-d1.py. Then follow along with the screencast video below:
Let's look at what we've built:
Starting the game: the constructor of GameController expects to be given a deck and a view, and instantiates a list of player objects.
Entering player names: the
add_playermethod collects these from the view.
Indicating name entry is complete: the
runmethod interprets the input None as meaning that there are no more players.
Dealing cards: is handled by the
start_gamemethod, as it's the first thing that happens at the beginning of the game.
Revealing cards: the
runmethod waits for a signal from the user, then flips over the cards and calls the
rebuild_deckcollects all the cards from the players, puts them back in the deck, and then takes the game state back to the start of Step 4.
How Do You Implement the View?
Remember that the view is both the user interface and the event generator. Our controller call the view’s methods both to present information and collect information from the user.
Also, the view shouldn’t know anything about what’s in the model, as this would make it harder to modify or replace.
For this reason, the view’s
prompt_for_new_player method returns a string rather than a Player object. Our view doesn’t know how to make a Player object!
The same thing goes for the playing card. The controller should pass it the rank and suit to display, rather than the entire PlayingCard.
So what would the View class look like? Let’s build it together!
Let's look at what we added:
Entering player names: the view sends the entered string to the controller, which creates a Player object and adds it to the model.
Revealing cards: the view provides a way for the user to get the cards flipped over and the game evaluated.
Start game: the view provides a way for the user to indicate whether they would like to play a new game or to quit the application.
Our implementation is straightforward. It just shows the player names, the cards dealt, and results on the command line. But, since we've separated this functionality, we could easily replace the mechanism with a GUI implementation, or even speakers and a microphone!
All that’s left is for the calling code to create the Deck, View, and Controller, and run the application - let’s see it all working together.
The controller is responsible for sequencing a use case and validates events sent by the view.
The view is responsible for presenting the model and sequence information and gathering input from the user.
The controller's responsibilities are determined by looking at the steps of the application. The view's responsibilities are determined by what the controller needs to show to the user.
We now have a functioning application that follows the MVC approach. In the next part, you'll learn the SOLID design principles and how to use them to strengthen our application.