猜相同的数字

时间:2013-12-18 23:15:37

标签: c++

在一本关于游戏编程的书中,我有以下练习。

  

用户会想到一个数字,然后程序会尝试猜测它,用户会提供反馈。

我解决这个问题的方法只是允许CPU在高和低之间选择一个随机数(基于以前的猜测)而不是快速查找数字(猜测高低之间的中间数字) )。所以它可以工作,但是有一个错误,即CPU不止一次地猜出相同的数字。我哪里出错了,如何解决?

    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');

欢迎所有其他改进建议。

2 个答案:

答案 0 :(得分: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,high) 这将忽略之前选择的计算机编号。

希望它有所帮助。 :)

答案 1 :(得分:0)

我认为其他人会帮助你了解程序的逻辑,所以我会帮助你完成你的结构;也就是说,你如何逻辑地概述了该计划以及我认为你可以做得更好的方式。请注意,我实际上并没有在这里运行任何代码 - 我目前没有这样做的环境。

我开始通过自动格式化代码并将其从do-while循环迁移到简单的while循环。另外,我将变量声明更接近于它们的使用位置。在现实世界中,一些编码标准禁止最后一步,但我觉得它提高了程序的可读性,并且它可以帮助你理解我的逻辑。

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'视为用户永远不会输入的值。因此,如果option1或option2为小写,则程序将不再正常运行。有很多方法可以解决这个问题,例如在getAnswer函数的开头验证option1和option2 isupper(c),尽管我还没有这样做。

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

太棒了,我们的代码看起来更清晰,但是我们仍然没有将代码分解成逻辑部分,所以让我们尝试这样做。请注意,我已将部分控制台输出移至外部while循环之外,并将“是您的猜测”更改为“是您的数字”。以前,如果用户声明他们想要再玩一次,他们就必须在那之后按回车,这很烦人!

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

就这一切而言,如果有什么令人困惑的话,请随时提问。