如何跟踪已经在 C++ 的刽子手游戏中猜到的字母?

Posted

技术标签:

【中文标题】如何跟踪已经在 C++ 的刽子手游戏中猜到的字母?【英文标题】:How to keep track of letters already guessed in Hangman game for C++? 【发布时间】:2014-07-20 05:09:06 【问题描述】:

给我的这个任务是从我们的教科书中复制一个刽子手游戏,并将其修改为书中的具体说明。我花了很多时间试图研究这个问题,并找到我不断收到与我相同的错误消息的原因。在我所见的任何地方,所有尝试修改此代码的人都尝试过使用数组,并且和我一样幸运。我目前正在编写 Strings 的一章,并计划按照 String 中的说明执行我的大部分语句。

我需要在这段代码中修改的是:

    跟踪用户输入的所有字母 如果用户输入了已输入的字母,则向用户发送错误消息

我遇到的主要问题是,当我编译这段代码并输入我已经输入的同一个字母时,它会以以下消息终止:

在抛出 'std::out of range' 的实例后调用终止 what(): basic_string::substr

#include <iostream>
    #include <string>
    using namespace std;

    int main()
    

        //declare variables
        string origWord = " ";
        string letter = " ";
        char dashReplaced = 'N';
        char gameOver = 'N';
        int numIncorrect = 10;
        string displayWord = "-----";
        string usedLetter = " ";
        string letterNotGuessedYet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        int letterPlace = 0;

        //get original word
        do //begin loop
        
            cout << "Enter a 5-letter word in uppercase: ";
            getline(cin,origWord);

        while(origWord.length() != 5); //end do loop

        //clear the screen
        system("cls");

        //start guessing
        cout <<"Guess this word: " << displayWord << endl;

        while(gameOver =='N')
        
            cout << "Enter an uppercase letter: ";
            cin >> letter;

            //This provides the letterPlace value with the possition of the 
            //input letter by the user within letterNotGuessedYet
            letterPlace = letterNotGuessedYet.find(letter,0);

            //This statement determines if the letter input by the user is
            //still in the letterNotGuessYet string.
            if(letterNotGuessedYet.substr(letterPlace,1)== letter)
            
                letterNotGuessedYet.replace(letterPlace, 1, "*");
                //cout << endl << letterNotGuessedYet;           //This tests that a letter is being replaced with an * 
                               
            else
            
                cout << "The letter " << letter << " has already been used. Choose another letter." << endl << endl;        
            // end if


            //search for the letter in the original word
            for(int x = 0; x < 5; x++)
            
                //if the current character matches
                //the letter, replace the corresponding
                //dash in the displayWOrd variable and then
                //set the dashReplaced variable to 'Y'
                if (origWord.substr(x,1) == letter)
                
                    displayWord.replace(x, 1, letter);
                    dashReplaced = 'Y';
                //end if
            //end for

            //if a dash was replaced, check whether the
            //displayWord variable contains any dashes

            if (dashReplaced == 'Y')
            
                //if the displayWord variable does not
                //contain any dashes, the game is over
                if (displayWord.find("-",0) == -1)
                
                    gameOver = 'Y';
                    cout << endl << "Yes, the word is " << origWord << endl;
                    cout << "Great guessing!" << endl;
                

                else //otherwise, continue guessing
                
                    cout << endl<< "Guess this word: " << displayWord << endl;
                    dashReplaced = 'N';
                //end if

            
            else //processed when dashReplaced contains 'N'
            
                //minus 1 to the number of incorrect gueses left
                numIncorrect += 1;

                //if the number of incorrect guesses is 10,
                //the game is over
                if (numIncorrect == 10)
                
                    gameOver = 'Y';
                    cout << endl << "Sorry, the word is " << origWord << endl;

                //end if
            //end if
        //end while

        //system("pause");
        return 0;
    //end of main function

我认为我收到此错误的原因与以下代码有关:

        //This provides the letterPlace value with the possition of the 
        //input letter by the user within letterNotGuessedYet
        letterPlace = letterNotGuessedYet.find(letter,0);

        //This statement determines if the letter input by the user is
        //still in the letterNotGuessYet string.
        if(letterNotGuessedYet.substr(letterPlace,1)== letter)
        
            letterNotGuessedYet.replace(letterPlace, 1, "*");
            //cout << endl << letterNotGuessedYet;           //This tests that a letter is being replaced with an * 
                           
        else
        
            cout << "The letter " << letter << " has already been used. Choose another letter." << endl << endl;        
        // end if

感谢您为我提供的任何帮助。

【问题讨论】:

问题是使用std::string::find函数的返回值而不测试它。问题是使用 std::string::find 函数的返回值而不对其进行测试。如果未找到子字符串,则其return value 可以是特殊值npos。如果您在 substr 中使用该值,则它位于无效索引中,这会导致您看到的异常。 现在是学习调试的好时机。 SO 不是调试服务。你需要自己做这部分。启动您的调试器,指示它在异常抛出站点停止,检查您的变量,找出哪个是哪个数组的越界索引,找出导致这种情况的逻辑错误,修复,重复。如果您在启动和运行调试器以及做您想做的事情时遇到问题,请提出不同的问题。 感谢 NicholasM,该链接和您的解释帮助我了解了发生了什么。 【参考方案1】:

您收到错误的原因是因为您在测试之前使用了“letterPlace”值来查看它是否真的被发现。如果“string::find”没有找到任何东西,它将返回一个值“string::npos”。在尝试使用它之前,您需要测试该值的 letterPlace 变量。

letterPlace = letterNotGuessedYet.find(letter,0);

// Check to see if this letter is still in the "letterNotGuessedYet string
if(letterPlace != string::npos)

    // At this point the letter is in the letterNotGuessedYet string so let it go
    letterNotGuessedYet.replace(letterPlace, 1, "*");

else

    // The letter was not found which means it has already been guessed.
    // Show error to the user here
    cout << "The letter " << letter << " has already been used. Choose another letter." << endl << endl;

【讨论】:

以上是关于如何跟踪已经在 C++ 的刽子手游戏中猜到的字母?的主要内容,如果未能解决你的问题,请参考以下文章

刽子手游戏

刽子手代码卡在三个不同的问题上

如何防止猜数字游戏中的重复猜测?

如何将“-”更改为刽子手(C)的字母?

UVa 489,紫书P79,刽子手游戏

运行hangman(Java)的程序中的逻辑出错