2013-12-18 6 views
1

В книге об игровом программировании у меня есть следующее упражнение.Угадай тот же номер

Пользователь думает о числе, а затем программа пытается угадать его, при этом пользователь дает обратную связь.

Мой метод решения этого вопроса позволяет процессору выбирать случайное число между высоким и низким (основанное на предыдущих предположениях) вместо быстрого способа узнать номер (угадать число на полпути между высокий и низкий). Таким образом, он работает, но есть ошибка в том, что процессор угадывает одно и то же число более одного раза. Где я ошибся и как это исправить?

enum statuses {NEUTRAL, HIGH, LOW}; 
      int status = NEUTRAL; 
      int cpuguess, high = 100, low = 1; 
      char winner, highorlow, playAgain; 

      do { 

       cout << "Guess My Number" << endl << endl; 

       cout << "Press Enter to Play !" << endl; 
       cin.ignore(); 
       cin.get(); 

       do { 
        cpuguess = getGuess(status, high, low); 

        cout << "Is your guess " << cpuguess << " ?" << endl; 
        cout << "(y/n)"; 
        cin >> winner; 
        winner = toupper(winner); 

        if(winner == 'N') 
        { 
        WrongInputHL: 
         cout << "Too HIGH or Too LOW ? O_O" << endl; 
         cout << "(h/l)"; 
         cin >> highorlow; 
         highorlow = toupper(highorlow); 
         if(highorlow == 'H') 
         { 
          status = HIGH; 
          high = cpuguess; 
         } 
         else if(highorlow == 'L') 
         { 
          status = LOW; 
          low = cpuguess; 
         } 
         else 
         { 
          goto WrongInputHL; 
         } 
        } 
       } while (winner == 'N'); 

       cout << "I won ! :D" << endl << endl; 

       cout << "Do you want to play again ?" << endl; 
       cout << "(y/n)" << endl; 
       cin >> playAgain; 
       playAgain = toupper(playAgain); 
      }while(playAgain == 'Y'); 

Все другие рекомендации по улучшению также приветствуются.

+6

Вам нужно включить функцию 'getGuess', чтобы нам не было догадываться. – Matt

+1

Re 'Любые другие советы в целях улучшения, приветствуются слишком lol.': Я бы посоветовал вам отклониться от использования goto, пока вы не приобретете больше опыта (они, как правило, недовольны, и многие утверждают, что вы должны никогда не используйте их вообще) - они часто (хотя и не всегда, имо) являются индикатором того, что вы неправильно структурировали свою программу и что ваша логика может быть изложена лучше и понятнее. – Warty

+0

omg gotos .... записать его –

ответ

1

Проблема, кажется, в этом разделе

   { 
       WrongInputHL: 
        cout << "Too HIGH or Too LOW ? O_O" << endl; 
        cout << "(h/l)"; 
        cin >> highorlow; 
        highorlow = toupper(highorlow); 
        if(highorlow == 'H') 
        { 
         status = HIGH; 
         high = cpuguess; 
        } 
        else if(highorlow == 'L') 
        { 
         status = LOW; 
         low = cpuguess; 
        } 

Похоже на основе вашего алгоритма двоичного поиска, однако, обратите внимание, как вы установили высокие и низкие концы там. Высокий конец может быть повторен, поскольку он потенциально может быть выбран.

Попробуйте это:

   WrongInputHL: 
        cout << "Too HIGH or Too LOW ? O_O" << endl; 
        cout << "(h/l)"; 
        cin >> highorlow; 
        highorlow = toupper(highorlow); 
        if(highorlow == 'H') 
        { 
         status = HIGH; 
         high = cpuguess-1; 
        } 
        else if(highorlow == 'L') 
        { 
         status = LOW; 
         low = cpuguess+1; 
        } 

Таким образом, если число слишком велико, новый диапазон становится (низкий, cpuguess-1) Хотя если это слишком низко она становится (cpuguess + 1, высокий) Это будет игнорировать номер компьютера, который был выбран ранее.

Надеюсь, это поможет. :)

0

Я полагаю, что другие помогут вам с логикой вашей программы, поэтому я поможем вам с вашей структурой; то есть, как вы логически изложили программу и как я думаю, что вы могли бы сделать лучше. Обратите внимание: я на самом деле не запускаю какой-либо код здесь - у меня нет среды, чтобы сделать это в данный момент.

Я начал с автоматического форматирования вашего кода и переноса его из циклов do-while в простые while-loops. Кроме того, я переместил объявления переменных ближе к тому, где они используются. В реальном мире некоторые стандарты кодирования запрещают последний шаг, но я чувствую, что он улучшает читаемость вашей программы и помогает понять мою логику.

enum statuses { NEUTRAL, HIGH, LOW }; 
int status = NEUTRAL; 
char input; 
int cpuguess, high = 100, low = 1; 
bool playing = true; // use booleans to represent true/false state, rather than characters 
while (playing) { // "playing" closer to declaration = arguably easier to read & find purpose 
    cout << "Guess My Number" << endl << endl; 
    cout << "Press Enter to Play !" << endl; 
    cin.ignore(); 
    cin.get(); 

    bool gameWon = false; 
    while (!gameWon) { 
     cpuguess = getGuess(status, high, low); 

     cout << "Is your guess " << cpuguess << " ?" << endl; 
     cout << "(y/n)"; 
     cin >> input; 
     gameWon = toupper(input) == 'Y'; 

     if (!gameWon) 
     { 
     status = NEUTRAL; 
     while (status == NEUTRAL) { 
      cout << "Too HIGH or Too LOW ? O_O" << endl; 
      cout << "(h/l)"; 
      cin >> input; 
      input = toupper(input); 
      if (input == 'H') { 
       status = HIGH; 
       high = cpuguess; 
      } else if (input == 'L') { 
       status = LOW; 
       low = cpuguess; 
      } 
     } 
     } 
    } 

    cout << "I won ! :D" << endl << endl; 
    cout << "Do you want to play again ?" << endl; 
    cout << "(y/n)" << endl; 
    cin >> input; 
    playing = toupper(input) == 'Y'; 
} 

-

В вашей программе, вы часто хотите, чтобы пользователь, чтобы дать один из двух ответов. Фактически, мы видим код, аналогичный

cout << "Is your guess " << cpuguess << " ?" << endl; 
cout << "(y/n)"; 
cin >> input; 
gameWon = toupper(input) == 'Y'; 

Три раза! Возможно, мы могли бы ввести новую функцию, скажем, getAnswer, которая задает вопрос и два возможных ответа (например: «y» и «n») и возвращает ответ пользователя? Кроме того, я решил быть последовательным при печати верхних регистров параметров Y/N и считал «\ 0» значением, которое пользователь никогда не будет вводить. В результате программа больше не будет корректно работать, если опция 1 или вариант 2 имеют строчные значения. Есть много способов справиться с этим, например, проверить, что option1 и option2 isupper (c) в начале вашей функции getAnswer, хотя я этого не делал.

char getAnswer(const char * question, const char option1, const char option2); 

void main() { // or whatever entry-point signature you've used 
    enum statuses { NEUTRAL, HIGH, LOW }; 
    int status = NEUTRAL; 
    char input; 
    int cpuguess, high = 100, low = 1; 
    bool playing = true; // use booleans to represent true/false state, rather than characters 
    while (playing) { // "playing" closer to declaration = arguably easier to read & find purpose 
     cout << "Guess My Number" << endl << endl; 
     cout << "Press Enter to Play !" << endl; 
     cin.ignore(); 
     cin.get(); 

     bool gameWon = false; 
     while (!gameWon) { 
     cpuguess = getGuess(status, high, low); 

     stringstream ss; 
     ss << "Is your guess " << cpuguess << " ?"; 
     gameWon = getAnswer(ss.c_str(), 'Y', 'N') == 'Y'; 

     if (!gameWon) { 
      status = getAnswer("Too HIGH or Too LOW ? O_O", 'H', 'L') == 'H' ? HIGH : LOW; 
      if (status == HIGH) 
       high = cpuguess; 
      else 
       low = cpuguess; 
     } 
     } 

     cout << "I won ! :D" << endl << endl; 
     playing = getAnswer("Do you want to play again?", 'Y', 'N') == 'Y'; 
    } 
} 

char getAnswer(const char * question, const char option1, const char option2) { 
    char response = '\0'; 
    while (response != option1 && response != option2) { 
     cout << question << endl; 
     cout << "(" << option1 << "/" << option2 << ")" << endl; 
     cin >> response; 
     response = toupper(response); 
    } 
    return response; 
} 

Awesome, наш код выглядит намного ровнее от только что, но мы до сих пор не нарушили наш код на логические части, так что давайте попробуем сделать это. Обратите внимание, что я переместил часть вашего вывода на консоль вне внешнего цикла while и изменил «ваша догадка» на «ваш номер». Раньше, если бы пользователь заявлял, что хочет играть снова, им придется нажать enter после того, что было досадно!

enum class GuessStatus { NEUTRAL, HIGH, LOW }; // I elected to use c++11's 'enum class' 

// these are called forward declarations 
void runIntroduction(); 
void playGame(); 

// I elected to use const char * and const char here. They weren't necessary, though. 
char getAnswer(const char * question, const char option1, const char option2); 

void main() { // or whatever entry-point signature you've used 
    runIntroduction(); 

    bool playing = true; // use booleans to represent true/false state, rather than characters 
    while (playing) { // "playing" closer to declaration = arguably easier to read & find purpose 
     playGame(); 
     playing = getAnswer("Do you want to play again?", 'Y', 'N') == 'Y'; 
    } 
} 

void runIntroduction() { 
    cout << "Guess My Number" << endl << endl; 
    cout << "Press Enter to Play !" << endl; 
    cin.ignore(); 
    cin.get(); 
} 

void playGame() { 
    int guessHigh = 100, guessLow = 1; 
    GuessStatus status = GuessStatus::NEUTRAL; // I'd suggest having GuessState::INITIAL = NEUTRAL to improve readability. Either that, or throwing in a comment to describe why you use NEUTRAL. 
    bool gameWon = false; 
    while (!gameWon) { 
     int cpuguess = getGuess(status, high, low); 

     stringstream ss; 
     ss << "Is your number " << cpuguess << " ?"; 
     gameWon = getAnswer(ss.c_str(), 'Y', 'N') == 'Y'; 

     if (!gameWon) { 
     status = getAnswer("Too HIGH or Too LOW ? O_O", 'H', 'L') == 'H' ? GameStatus::HIGH : GameStatus::LOW; 
     if (status == GameStatus::HIGH) 
      high = cpuguess; 
     else // status == GameStatus::LOW 
      low = cpuguess; 
     } 
    } 
    cout << "I won ! :D" << endl << endl; 
} 

char getAnswer(const char * question, const char option1, const char option2) { 
    char response = '\0'; 
    while (response != option1 && response != option2) { 
     cout << question << endl; 
     cout << "(" << option1 << "/" << option2 << ")" << endl; 
     cin >> response; 
     response = toupper(response); 
    } 
    return response; 
} 

Это все, не стесняйтесь задавать вопросы, если что-то вводит в заблуждение.

+0

Наконец, я должен отметить, что часто считается неправильной практикой использовать 'using namespace std; ', поскольку он загрязняет глобальное пространство имен (как, в частности, увеличивает шансы наличия сигнатур сигнатур конфликта). Многие разработчики вместо этого набирают «std :: cout», «std :: endl» и «std :: cin». – Warty

+0

Я использовал для ввода std :: cout, но после моего первого класса на C++ он сказал мне не использовать его. Но я верю, что читаю где-нибудь, что это лучше. Благодарю вас за ответ, он действительно очистил что-то. Я потерялся, хотя со стороны play = getAnswer («Вы хотите снова сыграть?», «Y», «N») == 'Y'; где игра представляет собой значение bool, если функция возвращает только символ, как бы он знал, чтобы закончить цикл? Мне жаль, что я не знаю, как сделать редактирование текста еще на этом сайте. lol – ericjets

+0

Проверьте часть '=='. Функция получает ответ и устанавливает «воспроизведение», независимо от того, равен или нет ответ «Y». Если ответ «Y», игра будет равна true ('' Y '==' Y''). В противном случае для воспроизведения установлено значение false ('' Y '! =' N''). Когда вы достигнете нижней части цикла while, ваша программа проверяет условие в 'while (condition)', чтобы определить, будет ли он запускать другую итерацию своего тела. – Warty

Смежные вопросы