My assignment is to write a program that lets the user play the game of Rock, Paper, Scissors against the computer.
Instructions:
The main method should have two nested loops, where the outer loop will allow the user to play the game as often as desired and the inner loop will play the game as long as there is a tie. Call the method isValidChoice() in a while loop in the userChoice() method to verify that the choice that user enters must be “rock”, “paper”, or “scissors”. If invalid string is input, isValidChoice()will return false and the program should ask for new input until the valid input is given.
Situation:
The program runs fine when the user enters a valid input. However once its not a valid input, there is a small problem.
Result:
Enter rock, paper, or scissors: rocky
Invalid input, enter rock, paper, or scissors: roc
Invalid input, enter rock, paper, or scissors: rock
The computer's choice was paper
The user's choice was rocky
Play again? (y/n)
As you can see, the program recognizes the invalid inputs. The user finally enter a valid input the third time. However, it displays user's first choice "rocky" which is invalid. Therefore the program can't display who wins.
Question
I need your help.
I want my program to run like this:
When the user enters multiple invalid inputs, but once
a valid input is entered, my program should still be able to display the user's valid input and display the winner.
import java.util.Scanner;
import java.util.Random;
public class RockPaperScissorsGame
{
public static void main (String[] args)
{
Scanner keyboard = new Scanner(System.in);
String computer, user;
char keepPlaying;
do
{
computer = computerChoice();
user = userChoice();
System.out.println("The computer's choice was " + computer);
System.out.println("The user's choice was " + user);
determineWinner(computer, user);
while (computer.equals(user))
{
computer = computerChoice();
user = userChoice();
System.out.println("The computer's choice was " + computer);
System.out.println("The user's choice was " + user);
determineWinner(computer, user);
}
System.out.println("\n" + "Play again? (y/n)");
keepPlaying = keyboard.nextLine().toLowerCase().charAt(0);
while ( keepPlaying != 'y' && keepPlaying != 'n' )
{
System.out.println("Invalid input, please enter (y/n)");
keepPlaying = keyboard.nextLine().toLowerCase().charAt(0);
}
} while (keepPlaying == 'y');
}
public static String computerChoice()
{
String[] choice = {"rock","paper","scissors"};
Random rand = new Random();
int computerChoice = rand.nextInt(3);
return choice[computerChoice];
}
public static String userChoice()
{
Scanner keyboard = new Scanner(System.in);
System.out.print("Enter rock, paper, or scissors: ");
String choice = keyboard.nextLine();
isValidChoice(choice);
return choice;
}
public static boolean isValidChoice (String choice)
{
Scanner keyboard = new Scanner(System.in);
while (!(choice.equalsIgnoreCase("rock")) && !(choice.equalsIgnoreCase("paper")) && !(choice.equalsIgnoreCase("scissors")))
{
System.out.print("Invalid input, enter rock, paper, or scissors: ");
choice = keyboard.nextLine();
}
return true;
}
public static void determineWinner(String computer, String user)
{
if (computer.equalsIgnoreCase("rock") && user.equalsIgnoreCase("paper"))
System.out.println("\n" + "Paper wraps rock.\nThe user wins!");
else if (computer.equalsIgnoreCase("rock") && user.equalsIgnoreCase("scissors"))
System.out.println("\n" + "Rock smashes scissors.\nThe computer wins!");
else if (computer.equalsIgnoreCase("paper") && user.equalsIgnoreCase("rock"))
System.out.println("\n" + "Paper wraps rock.\nThe computer wins!");
else if (computer.equalsIgnoreCase("paper") && user.equalsIgnoreCase("scissors"))
System.out.println("\n" + "Scissors cuts paper.\nThe user wins!");
else if (computer.equalsIgnoreCase("scissors") && user.equalsIgnoreCase("rock"))
System.out.println("\n" + "Rock smashes scissors.\nThe user wins!");
else if (computer.equalsIgnoreCase("scissors") && user.equalsIgnoreCase("paper"))
System.out.println("\n" + "Scissors cuts paper.\nThe computer wins!");
else if (computer.equalsIgnoreCase(user))
System.out.println("\n" + "The game is tied!\nGet ready to play again...");
}
}
This issue arises from the fact that Java is pass by value, not pass by reference.
In other words, rather than a reference of your parameter being passed to the method, a copy of the parameter is passed. Your method changes the copy but then once the method ends, the copy goes out of scope and is garbage collected.
When you pass choice
into isvalidChoice
, the reference to choice itself isn't passed. A copy of the string is made and then is passed. When you update the variable choice, it doesn't change the original string, it changes the copy that the System made. This answer explains how it works pretty well.
So what should you do?
Instead of looping in isValidChoice
have isValidChoice
return false if it isn't a valid input.
Your isValidChoice
should end up looking like this:
public static boolean isValidChoice(String choice) {
return (choice.equalsIgnoreCase("rock")) || (choice.equalsIgnoreCase("paper")) || (choice.equalsIgnoreCase("scissors"));
}
Then do something like this in userChoice
Scanner keyboard = new Scanner(System.in);
while(!isValidChoice(choice)) {
System.out.print("Invalid input, enter rock, paper, or scissors: ");
choice = keyboard.nextLine();
}