2015-04-19 16 views
5

Sto facendo un semplice programma di forbici con carta rock ma non sono sicuro di come garantire che l'utente inserisca solo una scelta valida. Devo essere in grado di rimproverarli se non scrivono alcun varroso di "rock", "carta" o "forbici" (la maiuscola non ha importanza) e poi "sì" o "no". Suggerimenti?Come posso garantire che l'utente inserisca una scelta valida?

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; 
} 

}

+3

Creare un ciclo che afferra continuamente l'input dell'utente fino a quando non immette qualcosa di valido. Una volta che l'utente ha inserito una risposta corretta, lascia il ciclo –

+0

@VinceEmigh come posso farlo funzionare a prescindere dalle lettere maiuscole, però? –

+0

Usa 'equalsIgnoreCase (String)' quando si confronta l'input dell'utente con le scelte valide –

risposta

3

Se dovessi giocare una sessione di Roshambo contro il computer, mi piacerebbe essere in grado di fare la mia selezione da solo digitando nella prima lettera di "Rock", "Paper" o "Scissors".

Utilizzando una ricca enum è una scelta naturale qui:

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(); 
    } 
} 

Avere maggior parte delle funzionalità in codice dichiarativo nel enum, il codice cliente diventerà molto più semplice. Lo enum gestisce anche la selezione casuale del computer (idea dalla risposta this).

while (true) { 

     Choice choice = null; 

     while (choice == null) { 
      System.out.println(Choice.promptText()); 
      choice = Choice.fromInput(scan.next()); 
     } 

     String computerChoice = Choice.getRandomChoice().displayName; 
// ... 

Si potrebbe anche incapsulare la maggior parte (se non tutti) della logica si ha nel metodo getGameOutcome, in Choice.

5

Tenere le scelte valide in un elenco, ciclo chiedendo l'input da parte dell'utente fino a quando non entra qualcosa di valido.

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)); 
+0

'toLowerCase()' crea un nuovo oggetto 'String'. Probabilmente la cosa migliore è solo confrontare usando 'equalsIgnoreCase' –

+0

@VinceEmigh' equalsIgnoreCase' usa 'regionMatches' che chiama' toUpperCase'. –

+0

@VinceEmigh Si noti che preferisco ancora 'equalsIgnoreCase' in quanto ha alcune ottimizzazioni come il controllo della lunghezza e il confronto con ref per carattere letterale. Tuttavia, nel mio esempio non uso nemmeno 'equals', ma invece controlla se la lista contiene la stringa. –

1

somesing come

if (!playerChoise.equalsIgnoreCase("paper") && ...) continue; 

Oppure è possibile memorizzare scelte valide nella lista come sopra indicato, e utilizzare ciclo foreach. Ma sarà più difficile, perché è necessario controllare tutte le varianti. Forse qualcosa del genere.

private boolean checkValid(String userChoise, String... variants) { 
    for (String s : variants) { 
     if (playerChoise.equalsIgnoreCase(s)) return true; 
    } 
    return false; 
} 

e chiamarlo per entrambi i casi:

if (!checkValid(userChoise, "rock", "papper", "scissors")) continue; 
Problemi correlati