Я ожидал, что цикл do-while будет заканчиваться каждый раз, когда я набираю «n», но это происходит только через раз. Никаких закономерностей в этом я не заметил. Я также пытаюсь закончить цикл, если количество точек равно 0 или меньше, но это тоже не работает.
Я пробовал это много раз, но не могу понять, где ошибка. Просто нужна помощь, пожалуйста, и спасибо.
Вот проблема:
Вот мой код:
package highlow;
import java.util.Scanner;
public class Highlow {
public static void Rules() {
System.out.println("RULES:");
System.out.println("Numbers 1-6 are low ");
System.out.println("Numbers 8-13");
System.out.println("Number 7 is neither high or low\n\n");
}
public static void main(String[] args) {
int number;
int gambleAmount;
int prediction;
int correctRange;
int winnings;
int points;
int numberOfGuesses = 0;
String repeat;
Scanner input = new Scanner(System.in);
points = 1000;
System.out.print("High Low Game\n\n");
Rules();
do {
number = (int) (13 * Math.random() + 1);
if (number > 7) {
correctRange = 1;
}
else if (number < 7) {
correctRange = 0;
}
else {
correctRange = -1;
}
numberOfGuesses += 1;
System.out.println("You have " + points + " points");
do {
System.out.println("Please insert a valid number of points");
System.out.print("How many points would you like to gamble: ");
gambleAmount = input.nextInt();
} while (gambleAmount > points);
System.out.print("Predict [1=high, 0=low]: ");
prediction = input.nextInt();
if (prediction == correctRange) {
winnings = gambleAmount * 2;
points = points + winnings;
System.out.println("The number was " + number);
System.out.print("You win!\n\n");
}
else {
points = points - gambleAmount;
System.out.println("The number was " + number);
System.out.print("You lose\n\n");
}
System.out.print("Would you like to play again ('n' for no and 'y' for yes): ");
repeat = input.next();
} while (repeat.equals("n") || points != 0);
System.out.print("You had " + numberOfGuesses + " guesses");
}
}
'n' for no
repeat.equals("NO")
- Думаю, это вызовет проблемы.
Итак, у вас есть логическая головоломка, которая в основном сводится к false || true
(!repeat.equals("n") || points > 0
), в данном случае она будет равняться true
, так что ваш цикл do-while
продолжится. Если вместо этого вы измените его на false && true
, он будет равен false
, и цикл завершится ... и да, моя голова все еще кружится, когда я пытаюсь это описать.
@MadProgrammer Only nextLine
имеет проблему с оборванными разделителями токенов. Любой другой метод пропускает разделители, пока не найдет допустимый токен.
@Tom nextLine
прочитает всю строку текста до токена новой строки, удалив ее в процессе - по моему опыту nextXxx
, похоже, вызывает проблемы с выходом из этого и вызывает пропуск следующих next
утверждений ... но я стараюсь избегать работать с Scanner
таким образом и вместо этого склоняться к чтению строки из ввода, а затем использовать отдельный рабочий процесс синтаксического анализа, который просто игнорирует все эти связанные проблемы - но это я
@MadProgrammer Ни «next», ни «nextInt», ни «nextFloat» (или любой другой метод, отличный от nextLine
) не будут пропущены. Вы правы, что они не читают разделитель после токена, но им это и не нужно, так как они все равно пропускают такие разделители. Их поведение довольно стабильно и надежно. Проблема в nextLine
. Он не следует обычному поведению класса Scanner, который пропускает разделители, пока не найдет допустимый токен. Он читается только до следующего разрыва строки, даже если прочитанное содержимое представляет собой просто пустую строку. Но да, читать построчно и конвертировать "вручную" тоже нормально.
@Tom «Он читается только до следующего разрыва строки, даже если прочитанное содержимое представляет собой просто пустую строку» - конечно, но если вы сделаете два вызова nextLine
, второй не будет пропущен, а мы получаем так много " почему мой следующий ввод пропускается" вопросы 🙄 - которые можно решить, просто поставив nextLine
после next
, чтобы удалить оборванный символ новой строки
@MadProgrammer Да, это правильно. Я просто хотел указать, что ваш первый комментарий частично верен (проблемы есть не у каждого nextxxx
, только у nextLine
) и что «заставлять пропускать следующие next
утверждения» также неверно. Некоторых эта проблема может сбить с толку, поэтому вводящая в заблуждение/неверная информация усугубит ситуацию.
@Tom Да, по наблюдениям, nextInt
, за которым следует nextLine
, заставляет nextLine
возвращать пустую String
, что приводит к выводу, что nextInt
оставляет оборванную новую строку, поэтому я всегда знаю, что просто очищаю буфер 😜. Я не думаю, что Scanner
достаточно хорошо учат новых разработчиков (или таких старых, как я, которые выросли без него)
Цикл do-while повторяется, если утверждение while
истинно.
Рассмотрим ваш цикл:
do {
...
} while(repeat.equals("n") || points!=0)
Вы действительно хотите продолжать играть, когда repeat
равно n
или points
не равно нулю?
Как указано в комментариях (и другом ответе), ваша проблема заключается в условии [внешнего] цикла do-while
в методе main
класса Highlow
. Это условие нужно изменить. Во-первых, вы должны проверить, больше ли баллов больше нуля, поскольку пользователь не может рисковать баллами, если у него их нет. Если у пользователя есть баллы, то проверьте, является ли ответ «y», т.е. пользователь хочет играть снова. Желательно также игнорировать регистр введенного ответа, т.е. играть снова, если пользователь ввел «Y» или «y». Другими словами, вы повторяете цикл, если у пользователя больше нуля баллов и он ответил «y». Если у пользователя ноль баллов или если он не ответил «y», выйти из цикла. Обратите внимание, что это означает, что вы должны инициализировать repeat
значением «y».
Приведенный ниже код представляет собой код из вашего вопроса с исправлениями, описанными выше, а также другими изменениями, которые подробно описаны после кода.
package highlow;
import java.util.InputMismatchException;
import java.util.Random;
import java.util.Scanner;
public class Highlow {
private static final int FACTOR = 2;
private static final int HI = 1;
private static final int INIT = 2;
private static final int LO = 0;
private static final int LOSER = 7;
private static final int LOWER = 1;
private static final int UPPER = 13;
public static void rules() {
System.out.println("RULES:");
System.out.println("Numbers 1-6 are low ");
System.out.println("Numbers 8-13");
System.out.println("Number 7 is neither high or low\n\n");
}
public static void main(String[] args) {
int number;
int gambleAmount;
int prediction = INIT;
int correctRange;
int winnings;
int points = 1000;;
int numberOfGuesses = 0;
String repeat = "y";
Scanner input = new Scanner(System.in);
System.out.print("High Low Game\n\n");
rules();
Random rand = new Random();
do {
number = rand.nextInt(LOWER, UPPER + 1); // (int) (13 * Math.random() + 1);
if (number > LOSER) {
correctRange = 1;
}
else if (number < LOSER) {
correctRange = 0;
}
else {
correctRange = -1;
}
System.out.println("You have " + points + " points");
System.out.printf("Enter points to risk [1 - %d]: ", points);
try {
gambleAmount = input.nextInt();
if (gambleAmount <= 0 || gambleAmount > points) {
System.out.println("Invalid value. Please re-enter.");
continue;
}
}
catch (InputMismatchException x) {
System.out.println("You did not enter a number. Please re-enter.");
input.nextLine();
continue;
}
do {
System.out.print("Predict [1=high, 0=low]: ");
try {
prediction = input.nextInt();
if (prediction < LO || prediction > HI) {
System.out.println("Invalid prediction. Please re-enter.");
continue;
}
}
catch (InputMismatchException x) {
System.out.println("You did not enter a number. Please re-enter.");
input.nextLine();
continue;
}
} while (prediction < LO || prediction > HI);
numberOfGuesses += 1;
if (prediction == correctRange) {
winnings = gambleAmount * FACTOR;
points += winnings;
System.out.println("The number was " + number);
System.out.print("You win!\n\n");
}
else {
points -= gambleAmount;
System.out.println("The number was " + number);
System.out.print("You lose.\n\n");
}
if (points > 0) {
System.out.print("Would you like to play again ('n' for no and 'y' for yes): ");
repeat = input.next();
}
} while (points > 0 && "y".equalsIgnoreCase(repeat));
String plural = numberOfGuesses == 1 ? "" : "es";
System.out.printf("You had %d guess%s.%n", numberOfGuesses, plural);
}
}
Хотя это и не указано в задаче, приведенный выше код проверяет правильность значений, введенных пользователем. Вызов метода nextInt выдаст InputMismatchException
, если он прочитает значение, которое не является допустимым целым числом. Обратите внимание, что блок catch
также вызывает nextLine
. Причина указана в комментариях к вопросу. Также см. Сканер пропускает nextLine() после использования next() или nextFoo()?
Нет необходимости во внутреннем цикле do-while
, чтобы просить пользователя ввести допустимое количество баллов для риска. Просто повторите внешний цикл, поскольку это напоминает пользователю, сколькими очками он может рискнуть.
Однако нет необходимости повторять весь цикл, если пользователь вводит неверный «прогноз». Отсюда внутренний цикл do-while
для получения прогноза пользователя.
Обратите внимание, что именно так, как я считаю, должна быть логика программы. Так поступать не правильнее и не менее правильно.
numberOfGuesses
следует увеличивать после того, как пользователь введет действительное количество баллов риска и правильный прогноз. Его не следует увеличивать сразу после входа во [внешний] цикл do-while
.
Если пользователь только что потерял все свои очки, то вы должны выйти из [внешнего] do-while
цикла, т.е. нет смысла спрашивать пользователя, хочет ли он играть снова, когда у него нет очков, которым можно было бы рисковать.
Хотя эта строка кода не вызывает проблем:
repeat = input.next();
рассмотрите вместо этого вызов метода nextLine
.
Посмотрите, что происходит, когда пользователь просто нажимает ENTER, то есть не вводит значение. (Кстати, то же самое относится и к методу nextInt
.)
Согласно соглашению об именах Java, имена методов должны начинаться со строчной буквы, поэтому я изменил метод Rules
на метод rules
.
Помните, что такие вещи, как
nextInt
иnext
, оставят в буфере висящий символ новой строки, а это означает, что в следующий раз, когда он попытается выполнитьnextXxx
, вместо этого вы получите этот символ. ИспользуйтеnextLine
и вручную анализируйте результат или используйте его, чтобы очистить символ новой строки.