今天,我們要用C++來寫一個猜字母的游戲。不要擔心,做起來并不是那么難的。首先,我們必須了解一下游戲規則。
一:玩家每次只能猜一個字母;
二:玩家只能猜錯有限次,否則游戲失;
三:猜錯的字母將被記錄下來;
四:每次猜測后,游戲應顯示出當前猜出的殘缺單詞,以及當前猜錯的所有字母,和剩下的猜錯的機會;
五:假設玩家猜的字母在單詞中,單詞中所有的該字母將被視為已猜出,例如:如果原單詞是apple,我們猜出了p,則程序應顯示當前猜出的殘缺單詞為-pp--。
六:不得多次猜測同一個字母,因為這樣是浪費時間。
一:準備工作: 規則就是這么多,我們應該用C++代碼來實現它。首先,我們應考慮怎樣記錄單詞,其中包括原單詞、猜錯的字母、當前猜出的殘缺單詞。如果用傳統的C風格數組,這是很麻煩的,這用C風格字符串實現很困難。但C++為我們預先想到了這一切,C++中帶有一個功能強大的string類,它的聲明在頭文件string中。注意,cstring或string.h中只是包含了一些處理字符串的函數,不包括string類。要使用這個類,我們首先要知道它的構造函數,這樣才能創建string類對象。
構造函數 | 說明 | string(const char* s) | 將string對象初始化為字符串s | string(size_type n,char c) | 將對象初始化為有n個元素的對象,它們都是字符c | string(const string& str,size_type pos=0,size_type n=npos) | 將對象初始化為str中,從第pos個元素開始的n個元素。 |
其實,這個類的構造函數遠不止這些,但我們開發這個游戲只用得到這些(也許還用不上這么多)。我們還要了解一些關于string類的知識。它重載了所有的關系操作符、可以用+=操作符把字符串、string類對象、字符加到對象的末尾。比如,我們可以寫出這樣的代碼:string a="butter"; string b="fly"; a+=b;這是十分方便的。它還重載了[]操作符,使我們完全可以像常規數組一樣用它。對于string類,我們還要初步了解一下它的輸入選項。它有operator>>,所以我們可以用cin進行輸入,并且它與istream中的cin的使用規則是一樣的。值得注意的一點是,string類是一個比較智能的類,它能夠自動調整字符串的長度,這樣,我們就不用擔心浪費空間或者輸入字符串超出對象末尾了。而我們常用的getline()函數呢?這是一個成員函數,所以不能進行重載。解決的旆ㄊ牽瑂tring類帶有一個getline()的非成員函數,它接受兩個參數,第一個是istream類對象,第二個是string類對象,并且去掉了長度參數,原因已經說了。所以,假設temp是一個string類對象,我們應這樣對它使用getline():getline(cin,string);看起來有點不好看,但實用。
最后,要實現這個拼字游戲,我們必須在對象中查找字符。string類已經提供了這方面的函數了,請看下表(未完全列出)。
方法原型 | 說明 | size_type find(char ch,size_type pos=0)const; | 從字符串的pos位置開始,查找字符ch,若找到,返回第一個ch所在的索引, 否則,返回string::npos。 | size_type find(const string& str,size_type pos=0)const; | 從字符串的pos位置開始,查找字符串str,若找到,返回str的首字母所在的索引,否則,返回string::npos。 | size_type find (const char* s,size_type pos=0)const; | 從字符串的pos位置開始,查找字符串s,若找到,返回s的首字母所在的索引,否則,返回string::npos。 |
舉例說明,若temp是一個string對象,內容為"apple",則temp.find('p')將返回1,即第一個字符p對應的索引。
二:游戲源代碼: #include #include #include #include #include using namespace std; const int NUM = 26; const string wordlist[NUM] = {"alabama", "choice", "usually", "dangerous", "deer", "panda", "love", "health", "exciting", "interesting", "administrator", "professional", "manage", "nonce", "onset", "typeid", "quarter", "remote", "lovely", "car", "keeper", "valid", "where", "mean", "important", "last"};//供游戲的單詞庫
int main() { srand(time(0)); char play; cout << "Will you play a word game? "; cin >> play; play = tolower(play); while(play=='y') { string first(wordlist[rand()%NUM]);//隨機選擇單詞 int length=first.length(); string player(length,'-');//玩家猜測的單詞 string badguess;//猜錯的字母集合 int guesses=10;//猜錯的機會 char guess; cout<<"您有"<<guesses<<"次猜錯的機會。 "; cout<<"您的單詞:"<<player<<' '; while(guesses>0&&player!=first) { cout<<"請您猜吧!"; cin>>guess; if(badguess.find(guess)!=string::npos||player.find(guess)!=string::npos) { cout<<"對不起,這個字母您已經猜過了。"; continue; }//判斷是否已經猜過 int temp=first.find(guess); if(temp==string::npos) { cout<<"。〔洛e了。 "; guesses--; badguess+=guess; }//猜錯后的處理 else { player[temp]=guess; temp=first.find(guess,temp+1); while(temp!=string::npos)//繼續搜索該字符,看是否單詞中有多個該字符 { player[temp]=guess; temp=first.find(guess,temp+1); } } cout<<"您還剩下"<<guesses<<"次猜錯的機會。 "; cout<<"您當前猜出的單詞:"<<player<<' '; cout<<"您當前猜錯的字母集合:"<<badguess<<' '; } if(guesses==0) cout<<"對不起,您失敗了。 "; else cout<<"您真棒! "; cout<<"正確單詞為:"<<first<<' '; cout << "Will you play again? "; cin>>play; }
system("PAUSE"); return 0; } |
下面是運行結果:
Will you play a word game? y 您有10次猜錯的機會。 您的單詞:------------ 請您猜吧!a 您還剩下10次猜錯的機會。 您當前猜出的單詞:----------a- 您當前猜錯的字母集合: 請您猜吧!s 您還剩下10次猜錯的機會。 您當前猜出的單詞:-----ss---a- 您當前猜錯的字母集合: 請您猜吧!p 您還剩下10次猜錯的機會。 您當前猜出的單詞:p----ss---a- 您當前猜錯的字母集合: 請您猜吧!o 您還剩下10次猜錯的機會。 您當前猜出的單詞:p-o--ss-o-a- 您當前猜錯的字母集合: 請您猜吧!r 您還剩下10次猜錯的機會。 您當前猜出的單詞:pro--ss-o-a- 您當前猜錯的字母集合: 請您猜吧!f 您還剩下10次猜錯的機會。 您當前猜出的單詞:prof-ss-o-a- 您當前猜錯的字母集合: 請您猜吧!e 您還剩下10次猜錯的機會。 您當前猜出的單詞:profess-o-a- 您當前猜錯的字母集合: 請您猜吧!i 您還剩下10次猜錯的機會。 您當前猜出的單詞:professio-a- 您當前猜錯的字母集合: 請您猜吧!n 您還剩下10次猜錯的機會。 您當前猜出的單詞:professiona- 您當前猜錯的字母集合: 請您猜吧!l 您還剩下10次猜錯的機會。 您當前猜出的單詞:professional 您當前猜錯的字母集合: 您真棒! 正確單詞為:professional Will you play again? n 請按任意鍵繼續. . . 三:程序分析 程序的運行結果大家都看到了,符合該游戲的規則,隨機性也較強,這就是C++的強大。
我們判斷字母是否已經被猜過,是這樣做的:
if(badguess.find(guess)!=string::npos|| player.find(guess)!=string::npos) { cout<<"對不起,這個字母您已經猜過了。"; continue; }//判斷是否已經猜過 |
因為如果字母被猜過,那么它要么在玩家猜出的殘缺單詞中,要么處于錯誤字母集合中,我們用find函數在這兩處分別進行了搜索。
對于猜錯后的處理,我們又是這樣做的:
int temp=first.find(guess); if(temp==string::npos) { cout<<"!猜錯了。\n"; guesses--; badguess+=guess; }//猜錯后的處理 |
首先,我們查找這個字符是否在單詞中出現。如果沒有出現,find函數將返回string::npos。npos是一個常量,比string能存儲的最大元素數多1。如果沒有出現,我們先是將猜錯的機會減去一次,再用了這個代碼:badguess+=guess;將錯誤的字母加入badguess對象中。想想,這要用常規字符數組有多難?
最后,如果temp不是string::npos,那么我們就說玩家猜對了。但可能這個單詞中有多個這樣的字母,所以,我們這樣做了:
temp=first.find(guess,temp+1); while(temp!=string::npos)//繼續搜索該字符,看是否單詞中有多個該字符 { player[temp]=guess; temp=first.find(guess,temp+1); } |
這樣一來,逐步縮小區間,直到確認單詞中再無這個字符為止。大家從運行結果中也可以看到這一點:
您當前猜出的單詞:----------a- 您當前猜錯的字母集合: 請您猜吧!s 您還剩下10次猜錯的機會。 您當前猜出的單詞:-----ss---a-//將兩個“s”都顯示出來了 您當前猜錯的字母集合: 大家若有興趣,可以對這個程序進行擴充,比如加入難度選擇、最后給出對玩家的評價等。最后,希望大家能通過這個范例,更加熱愛C++!
|