/home/wpollock1/public_html/restricted/Java1/GuessingGame.java

// GuessingGame.java - A program that allows the user to guess a
// random number from 1 to 10.  It uses the class java.util.Random to
// generate the numbers, and uses a swing simple GUI input method
// to read in the user value.  The user is told if the guess is too low
// or too high.
//
// Written 9/2014 by Wayne Pollock, Tampa Florida USA.
// Updated 10/2019 by WP to use regular expressions to validate input.
// (Original version used a try-catch block surrounding Integer.parseInt.)

import java.util.Random;
import javax.swing.JOptionPane;

class GuessingGame {
   private final static int MAX_RANGE = 10;  // Values are in [1..MAX_RANGE]
   private final static int MAX_ATTEMPTS = 4;

   public static void main ( String [] args ) {
      int rc = 0;  // Return code from "Do you want to play again?" dialog.
      Random randomNumberGenerator = new Random();

      // Play the game at least once, then repeat as long as the user wants:
      do {
         // Generate a random integer in the range 1 through MAX_RANGE:
         int numberToGuess = randomNumberGenerator.nextInt( MAX_RANGE ) + 1;

         // Play a game.  Set message to display in dialog (if they won
         // or lost):
         String message;
         if ( playGame( numberToGuess ) )
            message = "You won, Well done!";
         else
            message = "You lost (number was " + numberToGuess + ").";
         message += "\nWould you like to play again?";

         // Display won/lost dialog, with question:
            rc = JOptionPane.showConfirmDialog( null, message,
               "Choose one", JOptionPane.YES_NO_OPTION );

      } while ( rc == JOptionPane.YES_OPTION );
   }

   /** The user must guess numberToGuess in four tries.  Note the number
    *  to guess is passed in from main; this is because main must show
    *  the number if they don't guess it.
    *  @param numberToGuess A positive integer in the range 1..MAX_RANGE
    *  @return true if the user wins, false if they lose
    */
   private static boolean playGame ( int numberToGuess ) {
      int attempts = 0;  // The number of attempts made so far.
      String message = "What is your guess (1-" + MAX_RANGE + ")?";

      // A for loop doesn't work well here; if the user's input is
      // invalid, the number of attempts shouldn't increase.  So this
      // really is a sentinel type loop:  Go until the user get it, or has
      // four failed attempts.

      while ( attempts < MAX_ATTEMPTS ) {
         // Read in user input.  This input dialog shows the number of
         // guesses left in the title bar.  It also includes a cancel button:

         String input = JOptionPane.showInputDialog( null, message,
            (MAX_ATTEMPTS - attempts) + " Guesses left",
            JOptionPane.QUESTION_MESSAGE );

         // If the user hits cancel, abort the program:
         if ( input == null )
            System.exit( 0 );

         // Validate user's input as an integer, then convert:
         if ( input.matches("\\d+") ) {
            int guess = Integer.parseInt( input );
            if ( guess < 1 || guess > MAX_RANGE ) {
               message = "Guess is out of range!";
            } else {
               // Set the message to show it the user's guess is high or low:
               if ( compareTo(guess, numberToGuess) < 0 )
                  message = "Too low!";
               else if ( compareTo(guess, numberToGuess) > 0 )
                  message = "Too high!";
               else
                  return true;  // They guessed it!

               ++attempts;
            }
         } else {
            // Set message, and don't count this as an attempt:
            message = "Invalid choice!  You must enter a number.";
         }
         message += "  What is your guess (1-" + MAX_RANGE + ")?";
      }

      return false;  // They lost!
   }

   /** Return negative, 0, or positive for guess <, ==, or > numberToGuess:
    *  Note this doesn't check for guesses outside the range of 1..MAX_RANGE.
    *  A general compareTo for int or long must account for underflow, so you
    *  need either two if-statements, or this:
    *    return (x < y)   ? -1
    *         : ((x == y) ?  0
    *         : 1);
    *  @param guess The player's guess.
    *  @param numberToGuess The correct answer.
    *  @return <0 if guess is low, >0 if guess is high, or 0 if guess is correct
    */
   private static int compareTo ( int guess, int numberToGuess ) {
      return guess - numberToGuess;
   }
}