The second and final type of Player
in our game will be one that allows the user to play the game and follow their own preferred strategy. Specifically, it will have the user input a rank to ask of the opponent every turn. In this part of the lab, we will implement a UserPlayer
that interacts with the user and is our second child class of AbtractPlayer
.
With a UserPlayer
you can compete with either a RandomPlayer
or another player!
Inside your GitHub repository, you will find a file called UserPlayer.java
. This is where we will implement the UserPlayer
class that inherits the shared functionality of the AbstractPlayer
and can participate in the GoFish
game. Open this file in Visual Studio Code to get started.
Once again, most of the functionality needed is already implemented in the AbstractPlayer
parent class. However, we do need to add one instance variable: a Scanner
object that allows us to repeatedly get new inputs from the user:
/** The {@link Scanner} to use to interact with the user. */
private Scanner scanner;
Note
The Scanner
needs to be an instance variable instead of recreated every time we interact with the user, otherwise we will not be able to repeatedly ask for inputs before closing the program.
As in Part 3, there are only two methods to implement: the UserPlayer
constructor and the decideRank
method that implements the strategy described above.
Once again, the UserPlayer
constructor should call the parent constructor to initialize all of the shared instance variables. It should also create the Scanner
used to interact with the user through System.in
(as in Lab 1 Part 2):
this.scanner = new Scanner(System.in);
The decideRank
method determines which rank to request from the opponent. This time, the rank should be chosen by the user. To aid them in their choice, this function should:
Card
s in the player’s current hand
so they know what their valid options are.NumberFormatException
), and (ii) it is one of the ranks in the player’s hand
(this is where the countCards
helper function suggested in Part 2 could be useful).Once again, we can test our implementation before running the full GoFish
game. We can again add a private static void main(String args[])
function to our UserPlayer
class and add code for testing new functionality:
UserPlayer
class to make sure that the new Scanner
instance variable is being correctly. This verifies the correctness of the constructors.UserPlayer
object with some known cards using the gainCards
method, then call the decideRank
method to verify that (i) it displays the correct options to the user, (ii) it validates the user’s input correctly, (iii) it keeps requesting inputs until a valid rank is provided, and (iv) it returns the user’s chosen rank.Once you’ve tested both of your RandomPlayer
and UserPlayer
classes, we are ready to play the game using the GoFish
class. You should first compile the GoFish.java
file, which will also make sure all of the other Java files needed for the game are compiled. The program in GoFish
expects two command line arguments when it is run: the types of player 1 and player 2, which should be either Random
or User
. For example, to play two RandomPlayer
AIs against one another, we would run the following in the terminal after compiling all of our code:
java GoFish Random Random
If you want to try your hand against the RandomPlayer
, you could instead run the following and act as Player 1:
java GoFish User Random
Finally, if you want to try to play against a friend, you could instead run the following:
java GoFish User User
where one of you acts as Player 1 and the other as Player 2.
Remember to save your progress periodically to GitHub using the add
, commit
, and push
commands with git.