Reputation: 317
I'm making a simple rock paper scissors program but am unsure how to ensure that the user only enters a valid choice. I need to be able to reprompt them if they don't type some varriant of "rock", "paper", or "scissors" (capitalization doesn't matter) and later "yes" or "no". Suggestions?
import java.util.*;
public class RockPaperScissors {
private int wins = 0;
private int losses = 0;
private int ties = 0;
public static void main(String[] args) {
// TODO Auto-generated method stub
RockPaperScissors model = new RockPaperScissors();
Scanner scan = new Scanner(System.in);
while (true) {
System.out.println("Rock, Paper, Scissors... Pick one! (Type Rock, Paper, or Scissors)");
String playerChoice = scan.next();
String computerChoice = model.getRandomChoice();
System.out.println("You chose " + playerChoice + ".");
System.out.println("The computer chose " + computerChoice + ".");
RockPaperScissors.GameOutcome outcome = model.getGameOutcome(
playerChoice, computerChoice);
if (outcome == RockPaperScissors.GameOutcome.WIN) {
System.out.println("You won! Congratulations");
} else if (outcome == RockPaperScissors.GameOutcome.LOSE) {
System.out.println("You lose! Better luck next time!");
} else {
System.out.println("Tie!");
}
System.out.print("Do you want to play again? (Yes/No):");
String answer = scan.next();
if (answer.equalsIgnoreCase("no")) {
break;
}
}
System.out.println("Thanks for playing!");
System.out.println("Wins: " + model.getWins());
System.out.println("Losses: " + model.getLosses());
System.out.println("Ties: " + model.getTies());
scan.close();
}
public static enum GameOutcome {
WIN, LOSE, TIE;
}
public GameOutcome getGameOutcome(String userChoice, String computerChoice) {
if (userChoice.equalsIgnoreCase("Rock")) {
if (computerChoice.equalsIgnoreCase("Paper")) {
losses++;
return GameOutcome.LOSE;
} else if (computerChoice.equalsIgnoreCase("Scissors")) {
wins++;
return GameOutcome.WIN;
}
} else if (userChoice.equalsIgnoreCase("Paper")) {
if (computerChoice.equalsIgnoreCase("Scissors")) {
losses++;
return GameOutcome.LOSE;
} else if (computerChoice.equalsIgnoreCase("Rock")) {
wins++;
return GameOutcome.WIN;
}
} else if (userChoice.equalsIgnoreCase("Scissors")) {
if (computerChoice.equalsIgnoreCase("Rock")) {
losses++;
return GameOutcome.LOSE;
} else if (computerChoice.equalsIgnoreCase("Paper")) {
wins++;
return GameOutcome.WIN;
}
}
ties++;
return GameOutcome.TIE;
}
public String getRandomChoice() {
double d = Math.random();
if (d < .33) {
return "Rock";
} else if (d < .66) {
return "Paper";
} else {
return "Scissors";
}
}
public int getWins() {
return wins;
}
public int getLosses() {
return losses;
}
public int getTies() {
return ties;
}
}
Upvotes: 5
Views: 862
Reputation: 21004
Keep the valid choices in a list, loop asking the input from the user until he enter something valid.
List<String> validChoices = Arrays.asList("rock", "paper", "scissors");
Scanner sc = new Scanner(System.in);
String choice = null;
do
{
System.out.println("Enter a choice (rock|paper|scissors)");
choice = sc.next().toLowerCase();//Retrieve as lower case
}
while(!validChoices.contains(choice));
Upvotes: 5
Reputation: 7956
If I were to play a session of roshambo against the computer, I'd like to be able to make my selection by only typing in the first letter of "Rock" , "Paper" or "Scissors".
Using a rich enum
is a natural choice here:
private enum Choice {
ROCK ("Rock"),
PAPER ("Paper"),
SCISSORS ("Scissors");
private String displayName;
private static final List<Choice> VALUES =
Collections.unmodifiableList(Arrays.asList(values()));
private static final int SIZE = VALUES.size();
private static final Random RANDOM = new Random();
private Choice(String dn) {
displayName = dn;
}
/**
* Returns a random Choice.
*/
public static Choice getRandomChoice() {
return VALUES.get(RANDOM.nextInt(SIZE));
}
/**
* Returns a Choice that matches the input string. The input is considered a match if it starts with the same character
* as the displayname of a Choice. If no match is found, returns null.
*/
public static Choice fromInput(String input) {
if (input == null || input.length() == 0) {
return null;
}
for (Choice c : VALUES) {
if (Character.toLowerCase(c.displayName.charAt(0))
== Character.toLowerCase(input.charAt(0))) {
return c;
}
}
return null;
}
/**
* Returns the text to display to the user, asking for input to #fromInput().
*/
public static String promptText() {
StringBuilder sb = new StringBuilder();
for (Choice c : VALUES) {
if (sb.length() > 0) {
sb.append(", ");
}
sb.append(c.displayName).append(" (")
.append(c.displayName.charAt(0)).append(")");
}
sb.append(". Pick one!");
return sb.toString();
}
}
Having most of the functionality coded declaratively in the enum
, your client code will become much simpler. The enum
also handles the computer's random selection (idea from this answer).
while (true) {
Choice choice = null;
while (choice == null) {
System.out.println(Choice.promptText());
choice = Choice.fromInput(scan.next());
}
String computerChoice = Choice.getRandomChoice().displayName;
// ...
You could also encapsulate most (if not all) of the logic you have in the getGameOutcome
method, into Choice
.
Upvotes: 3
Reputation: 698
Somesing like
if (!playerChoise.equalsIgnoreCase("paper") && ...) continue;
Or you can store valid choises in list as shown above, and use foreach loop. But it will be more difficult, becouse you need to check all variants. Maybe something like.
private boolean checkValid(String userChoise, String... variants) {
for (String s : variants) {
if (playerChoise.equalsIgnoreCase(s)) return true;
}
return false;
}
And call it for both cases:
if (!checkValid(userChoise, "rock", "papper", "scissors")) continue;
Upvotes: 1