package com.martinandersson.lesson03.guessmynumber.solution;
import java.io.Console;
/**
* The {@code GuessMyNumber} class is the starting point for a cool game where
* the user can guess on a secret number and receive feedback whether the number
* was too low or too high, or if hen was right.
*
* @author Martin Andersson (webmaster at martinandersson.com)
*/
public class GuessMyNumber {
/**
* A constant for max amount of retries.
*/
private static final int MAX_RETRIES = 3,
MIN_RANGE = 0,
MAX_RANGE = 10;
public static void main(String[] ignored) {
Console c = requireConsole();
// 1. Initiate a secret number
SecretNumber secret = new SecretNumber(MIN_RANGE, MAX_RANGE);
for (int i = MAX_RETRIES; i > 0; --i) {
if (makeTry(c, secret) == true) { // <-- may be simplified to "if (makeTry(c, secret)) break;".
break;
}
}
c.writer().println("Game over :'(");
// 2. Play again?
if (playAgain(c) == true) {
main(null);
}
}
/**
* Will return the console, or crash if no console is attached to
* the running JVM.
*
* @return console, almost always
*
* @throws IllegalStateException if no console was found
*/
private static Console requireConsole() {
Console c = System.console();
if (c == null) {
throw new IllegalStateException("No console attached!");
}
return c;
}
/**
* Will run the game one time.<p>
*
* @param console used to get a human number
* @param secret used to make the guess
*
* @see #getHumanGuess1(Console)
*/
private static boolean makeTry(Console console, SecretNumber secret)
{
Console c = console; // <-- aliasing: make a copy of a reference, both "c" and "console" point to the same Console object
final int input = getHumanGuess1(c);
final int comparison = secret.guess(input);
if (comparison > 0) {
c.writer().println("Too high!");
}
else if (comparison < 0) {
c.writer().println("Too low!");
}
else {
c.writer().println("Right on spot!");
}
// Bad, looks ugly:
// if (comparison == 0) {
// return true;
// }
// else {
// return false;
// }
return comparison == 0;
}
/**
* Will fetch the human guess.<p>
*
* The value returned may be anything. A value will be returned, that
* is a promise. This method will never return without the human
* providing a proper value.
*
* @param console is used to retrieve the human value
*
* @return what the user typed
*/
private static int getHumanGuess1(Console console) {
Integer asInt = null;
while (asInt == null) {
String input = console.readLine("Please provide a guess: ");
try {
asInt = Integer.valueOf(input);
}
catch (NumberFormatException e) {
console.writer().println("Bad input, please try again!");
}
}
return asInt; // Same as: asInt.intValue();
}
/**
* Will fetch the human guess.<p>
*
* The value returned may be anything. A value will be returned, that
* is a promise. This method will never return without the human
* providing a proper value.
*
* @param console is used to retrieve the human value
*
* @return what the user typed
*
* @implNote
* Uses recursion instead of boxed Integer.
*/
private static int getHumanGuess2(Console console) {
try {
String input = console.readLine("Please provide a guess: ");
return Integer.parseInt(input);
}
catch (NumberFormatException e) {
console.writer().println("Bad input, please try again!");
return getHumanGuess2(console);
}
}
/**
* Returns {@code true} if human wants to restart the game, otherwise
* {@code false}.<p>
*
* This method will always return a {@code boolean}, it will never
* fail.
*
* @param console the console that we use for human input
* @return {@code true} if human wants to restart the game, otherwise
* {@code false}
*/
private static boolean playAgain(Console console) {
Boolean playAgain = null;
while (playAgain == null) {
String input = console.readLine("Want to play again (yes/no)? ");
// Remove whitespace before and after contents
// String trimmed = input.trim();
// But instead, me might want to remove all white space
String withoutWhitespace = input.replace(" ", "");
// Or:
// String withoutWhitespace = input.replaceAll(" ", "");
// String withoutWhitespace = input.replaceAll("\\s", "");
switch (withoutWhitespace.toLowerCase()) {
case "yes":
playAgain = true;
break;
case "no":
playAgain = false;
break;
default:
// The while loop will restart!
console.writer().println("Bad input, please respond like a normal human.");
break;
}
}
return playAgain;
}
}