# Three-player number-guessing game

This is a sample exercise tutorial that would be used to test understanding of how simple classes communicate/message and are designed.

Tester class

public class GuessingGameTester {

public static void main(String[] args){
//create a new game
GuessingGame g1 = new GuessingGame();

//call the start method
g1.startGame();

}
}


Player class

public class GuessingGamePlayer {

boolean areTheyRight = false;

//player random guess
int getPlayerGuess(){
return (int) (Math.random()* 20);
}
}


Game class

public class GuessingGame {

private int numberToGuess;
private boolean keepPlaying;
private int round;

//constructor
GuessingGame(){
//create a random number for players to guess
numberToGuess = (int) (Math.random() * 20);//cast to int
keepPlaying = true;
round = 1;
}

void startGame(){

//create 3 players to play
GuessingGamePlayer p1 = new GuessingGamePlayer();
GuessingGamePlayer p2 = new GuessingGamePlayer();
GuessingGamePlayer p3 = new GuessingGamePlayer();

System.out.println("The number to guess is : " + numberToGuess);

//giving 100 attemps for the computer to guess the correct number
while(keepPlaying && round <= 100){

//get their guess
int p1guess = p1.getPlayerGuess();
int p2guess = p2.getPlayerGuess();
int p3guess = p3.getPlayerGuess();

System.out.println("round " + round);
System.out.println("p1 guessed: " + p1guess);
System.out.println("p2 guessed: " + p2guess);
System.out.println("p3 guessed: " + p3guess);

System.out.println("\n");

if(p1guess == numberToGuess){
p1.areTheyRight = true;
keepPlaying = false;
}else if(p2guess == numberToGuess){
p2.areTheyRight = true;
keepPlaying = false;
}else if(p3guess == numberToGuess){
p3.areTheyRight = true;
keepPlaying = false;
}

round ++;
}//end while

//game over - echo who guessed the correct num and the round
System.out.println("\n");
if(p1.areTheyRight){
System.out.println("p1 guessed the correct number during round " + round);
}else if(p2.areTheyRight){
System.out.println("p2 guessed the correct number during round " + round);
}else{
System.out.println("p3 guessed the correct number during round " + round);
}

}//end startGame
}

• So is this for a tutorial you're writing and you want to make sure new programmers should understand it? – Kevin Nov 7 '11 at 18:04
• Or this a cleverly worded homework problem :) (kidding) – Autodidact Nov 10 '11 at 5:24

I'd add only a couple of minor things.

The comments are more trouble than they're worth. I understand it's a tutorial, but if they're going to be in there, they should do more--right now they don't add value. Since it's a learning exercise, use those comments to teach them something, including terminology.

// Create a new GuessingGame instance to represent the current game.
// Begin playing by calling the startGame() method.


But I'd leave them out altogether, and have the corresponding text/lecture do the describing; you will achieve more by writing or talking about them outside of the code.

Secondly, I'd consider keeping the players in an array or a list. If not now, then in "part two". This simplifies the code conceptually, because you can directly represent "for each player, check their guess" in code. If not in "part one", then I'd at least move the guess-getting into another method--you only need to return a boolean, the players hold whether or not it's a right guess.

(IMO the player shouldn't maintain that state, rather the game should.)

Next, I'd refactor more; the startGame does more than starts the game. Either refactor, or rename. Right now, startGame starts, plays, and ends the game. By refactoring, the code becomes more story-like, at the cost of more methods. But good methods should be tightly focused and easy to reason about.

On a more theoretical level, the end conditions as implemented makes a certain assumption about the nature of the game. Asking if anyone can spot a potential "gotcha" with the current implementation might be a good "extra credit" problem.

In real life, what would happen if two players both guessed correctly? In the current implementation, the players are always checked in numerical order. In real life, a typical game would be either who guessed the fastest (which I supposed the player order could be said to represent), or multiple players could win, or...?

To put that into "real life" terms, let's say the guesses are access control votes, or search result weightings, etc. In those cases, a tie does matter. So instead of having a single winner, there would be a collection of "winners". How to decide if there should be a single winner, or a group, depends on the nature of the game.

Lastly, I'd make some of the things more configurable, although perhaps with reasonable defaults. This also mirrors real life a bit more accurately, and I tend towards adding a bit of complexity early, since it can be ignored.

Some of my suggestions are more appropriate for a "second round" implementation, while some make sense for what you have now. Pick and choose, or ignore them all :) I've appended everything in a single blob.

public class GuessingGameTester {

public static void main(String[] args){
GuessingGame game = new GuessingGame();
game.startGame();
}

}

public class GuessingGamePlayer {

private int playerNumber;

public GuessingGamePlayer(int playerNumber) {
this.playerNumber = playerNumber;
}

int getGuess(){
return new Random().nextInt(GuessingGame.MAX_GUESSING_NUMBER) + 1;
}

@Override
public String toString() {
return "Player " + playerNumber;
}

}

public class GuessingGame {

private int numberToGuess;
private int roundsToPlay;
private int numberOfPlayers;
private List<GuessingGamePlayer> players;

public static int MAX_GUESSING_NUMBER = 20;

public GuessingGame() {
init(100, 3);
}

public GuessingGame(int roundsToPlay, int numberOfPlayers) {
init(roundsToPlay, numberOfPlayers);
}

public void init(int numberOfRounds, int numberOfPlayers) {
this.roundsToPlay = numberOfRounds;
this.numberOfPlayers = numberOfPlayers;

numberToGuess = new Random().nextInt(MAX_GUESSING_NUMBER) + 1;

initPlayers();
}

public void initPlayers() {
players = new ArrayList<GuessingGamePlayer>();
for (int i = 0; i < numberOfPlayers; i++) {
}
}

public void startGame() {
int currentRound = 0;
GuessingGamePlayer correctGuesser = null;
System.out.println("The number to guess is: " + numberToGuess);

while((correctGuesser == null) && (currentRound <= roundsToPlay)) {
++currentRound;
System.out.println("\nRound " + currentRound);

for (GuessingGamePlayer player : players) {
int playerGuess = player.getGuess();
System.out.println("  " + player + " guessed " + playerGuess);
if (playerGuess == numberToGuess) {
correctGuesser = player;
}
}
}

System.out.println();

if (correctGuesser == null) {
System.out.println("Nobody guessed the right number!");
} else {
System.out.println(correctGuesser + " guessed the number in round " + currentRound);
}
}

}

• thanks for thoughtful articulation. Most of your recommendations will be used in the next version. A lot of what you suggest, has not been presented yet, so I cant use in this example. – jamesTheProgrammer Nov 8 '11 at 14:56
• specifically, at this point, I have not yet presented imports, constructors, lists, arrays, parameters/arguments. The primary goal of the tutorial is to demo simple class construction with a hopefully interesting example. I do like how you made it configurable and refactored the startGame() method. – jamesTheProgrammer Nov 8 '11 at 15:54
• @jamesTheProgrammer Well, you already have a constructor, so it's too late ;) – Dave Newton Nov 8 '11 at 15:57
• guilty...I'll try to sneak that one by – jamesTheProgrammer Nov 8 '11 at 19:20
• @jamesTheProgrammer "Pay no attention to this code for now" usually works. Just try explaining what public static void main(String[] args) means :/ I just hold off and say "assume magic for now; we'll get there." – Dave Newton Nov 8 '11 at 19:22

A couple observations:

1. If none of them guess the number before the number of rounds runs out, you will print that p3 guessed in round 101.
2. If more than one guessed correctly in the last round, you'll only credit one of them.
3. I see no reason to keep instance variables, especially for keepPlaying, it will prevent the game from being played properly if started a second time unless no one guessed the first game.
4. At the end you print 2 blank lines (3 newlines: one with "p3 guessed...", one because of the "\n", and one because that last is a println, not a print or printf. I think that's a bit excessive.

Perhaps you could use instance variables to set the maximum number instead of 20 (as a magic number), and pass the number of rounds to play as an argument to the startGame method. You could even, once you get more advanced, change it to pass in the players as an array, and then add in subclasses with different methods of guessing. You could also return the number/index of the winner.

Ive updated the classes based on feedback. Some of the good feedback can't be used in this example, because the content has not been presented. Here is the revised code: block.

public class GuessingGameTester {

public static void main(String[] args){
//create a new game object
GuessingGame game = new GuessingGame();
//call the startGame method on the game object
game.startGame();
}
}

public class GuessingGamePlayer {

GuessingGamePlayer(){};
boolean areTheyRight = false;

//player random guess
int getPlayerGuess(){
return (int) (Math.random()* 15);
}
}

public class GuessingGame {

private int numberToGuess;
private boolean keepPlaying;
private int round;

//create 3 player objects
private GuessingGamePlayer p1 = new GuessingGamePlayer();
private GuessingGamePlayer p2 = new GuessingGamePlayer();
private GuessingGamePlayer p3 = new GuessingGamePlayer();

private int player1Guess;
private int player2Guess;
private int player3Guess;

//constructor
GuessingGame(){
//return the players random guess
numberToGuess = (int) (Math.random() * 15);//cast to int, random function returns double
round = 1;
}

void startGame(){
keepPlaying = true;
System.out.println("The number to guess is : " + numberToGuess);
displayGuesses();
displayGameEndingInfo();
}//end startGame

void displayGuesses(){
// 20 attemps for the computer to guess the correct number
while(keepPlaying && round <= 20){

getPlayerGuesses();

System.out.println("Round " + round);
System.out.println("Player 1 guessed: " + player1Guess);
System.out.println("Player 2 guessed: " + player2Guess);
System.out.println("Player 3 guessed: " + player3Guess);

System.out.println("\n");

if(player1Guess == numberToGuess){
p1.areTheyRight = true;
keepPlaying = false;
break;
}else if(player2Guess == numberToGuess){
p2.areTheyRight = true;
keepPlaying = false;
break;
}else if(player3Guess == numberToGuess){
p3.areTheyRight = true;
keepPlaying = false;
break;
}

round ++;
}//end while
}//end displayGuesses

void getPlayerGuesses(){
//get the guess from each player object and assign to pxguess variable
player1Guess = p1.getPlayerGuess();
player2Guess = p2.getPlayerGuess();
player3Guess = p3.getPlayerGuess();
}

void displayGameEndingInfo(){
//game over - echo who guessed the correct num and the round
System.out.println("\n");
if(p1.areTheyRight){
System.out.println("p1 guessed the correct number during round " + round);
}else if(p2.areTheyRight){
System.out.println("p2 guessed the correct number during round " + round);
}else{
System.out.println("p3 guessed the correct number during round " + round);
}
}//end displayGameEndingInfo

}//end class GuessingGame