程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 【C++探索之旅】第一部分第十一課:小游戲,猜單詞

【C++探索之旅】第一部分第十一課:小游戲,猜單詞

編輯:關於C++

\

內容簡介

1、第一部分第十一課:小游戲,猜單詞

2、第一部分第十二課預告:指針一出,誰與爭鋒


小練習

上一課《【C++探索之旅】第一部分第十課:文件讀寫,海闊憑魚躍》中我們學習了讀寫文件的知識。

第一部分的課程也快接近尾聲了,下一課我們會學習很重要的指針的知識。之後,我們就進入第二部分:面向對象編程了。哈哈哈,激動不?

目前為止,我們也學了不少內容:編譯基本原理,IDE,變量,函數,條件語句,循環語句,引用,數組,文件讀寫,等等。你應該為自己感到自豪。

俗語說得好:實踐是最好的老師。我們學了那麼多知識點,卻還沒有綜合地來應用一下,怎麼行呢?

這一課我們就用一個小游戲來鍛煉吧。

游戲規則很簡單:我們輸入一個單詞,然後把單詞裡的字母打亂,顯示給用戶看,讓用戶猜這個單詞是什麼。


准備工作和建議

這個小游戲看似簡單,但對於初學者的話還是有點難度的,因為需要用到我們前幾課的一些知識點,例如:

變量

string(字符串)

函數

控制流程,條件語句

數組

如果有知識點生疏了,可以在編寫這個游戲前回去復習。

[猜數字]游戲的主旨

我們要寫的小游戲的流程是這樣:

玩家1輸入一個單詞

程序將單詞打亂

玩家2嘗試從打亂的單詞猜出原始的單詞是什麼

下面是一個玩此游戲的一輪的例子:

輸入一個單詞
MYSTERY

原先的單詞是什麼?MSYRETY
RYTEMSY
猜錯了!

原先的單詞是什麼?MSYRETY
SERMYTY
猜錯了!

原先的單詞是什麼?MSYRETY
MYSTERY
猜對了!好棒!

分析以上流程:

在這一輪中,玩家1選擇輸入MYSTERY(英語"神秘,秘密"的意思)作為要猜的單詞給玩家2來猜。

程序將MYSTERY這個單詞的字母順序打亂,然後請玩家2來猜打亂前的原始單詞是什麼。

玩家2嘗試猜測,他猜了3次才猜中:

RYTEMSY:顯示"猜錯了!"

SERMYTY:還是沒猜對

MYSTERY:終於猜對了,祝賀!

 

當然了,在上面演示的一輪游戲的例子中,玩家2可以看到玩家1輸入的原始單詞,暫時先這樣。到這課最後的改進部分我們會說怎麼避免。當然了,聰慧如你也許早就想到好幾個辦法了。

 

開始前的一些建議

 

當我們讓一個初學編程的朋友放手一搏,第一次自己寫一個比較完整的程序時,是有難度的。

 

小編也是過來人,以前還沒入門編程時感受頗深:看書,照著書上例子敲代碼,好像都懂啊。可是一上手自己寫比較復雜的代碼,就愣住了,不知該從何下手。

 

"從哪裡開始寫呢?","我該做什麼呢?","我該用什麼呢?",等等,都是初學的症候。不過誰都得過了這一階段,才能體驗到美好的入門感覺。

 

因此,絕對不要對自己灰心!編程麼,就是用一種新的思路來解決問題,只要你經過了編程思想的錘煉,你會發現其他很多事情都會顯得簡單了。

 

不過,善良如小編,還是不希望你自己過於迷失。畢竟只要稍加提示,你的思路就會更開闊啦。當然了,也許不必提示,你已經把程序寫出來了吧。

 

找到頭緒

 

這個程序的編寫其實只有三步:

 

輸入原始單詞;

打亂單詞的字母順序;

做循環:請求玩家2輸入猜測的單詞。只要玩家2沒猜到單詞,循環就繼續進行。

 

其實以上的三個步驟是相對獨立的,因此,與其一開始就很頭大地想要一下子把整個程序寫出來,為什麼不把程序分成三個部分一點點寫出來呢?

 

列出代碼的大綱

 

一開始,肯定是先寫main函數啦,畢竟是程序的入口嘛。我們可以先把程序寫成這樣:

 

intmain()
{
//1:請求用戶輸入單詞

//2:打亂輸入的單詞

//3:請求用戶猜單詞

return0;
}

 

我們要做的,只是分別用代碼實現注釋裡的這三步而已。看吧,寫代碼之前先思考,然後做好規劃,對於寫出條理分明的代碼何等重要。

 

不過我建議大家先實現第1步,接著實現第3步,最後實現最難的第2步。

 

如何打亂單詞呢?

 

打亂單詞的這一步是最難的。需要學習一些基礎知識:

 

抽取隨機數

 

為了做到單詞的打亂是隨機的,我們需要隨機地抽取單詞中的字母,那怎麼達成這個目的呢?臣妾做不到啊。

 

不要緊,我們來學習隨機數的生成。

 

首先,須要引入兩個頭文件:ctime和cstdlib,因為我們要用到這兩個頭文件中的函數。

然後,我們需要調用函數srand(time(0))來初始化隨機數的"種子"(seed)。

然後,一旦"種子"准備好了,就可以用rand函數來生成隨機數了,例如:randomNb = rand() % 5; (5就限定了生成的隨機數是介於0到4之間)。

 

srand其實是seed random的縮寫,seed在英語中是“種子”的意思。

 

補充一些摘自百度百科的概念:

========================

 

【srand和rand配合使用產生偽隨機數序列。rand函數在產生隨機數前,需要系統提供的生成偽隨機數序列的種子,rand根據這個種子的值產生一系列隨機數。如果系統提供的種子沒有變化,每次調用rand函數生成的偽隨機數序列都是一樣的。srand(unsigned seed)通過參數seed改變系統提供的種子值,從而可以使得每次調用rand函數生成的偽隨機數序列不同,從而實現真正意義上的“隨機”。通常可以利用系統時間來改變系統的種子值,即srand(time(NULL)),可以為rand函數提供不同的種子值,進而產生不同的隨機數序列】

 

【所謂的“偽隨機數”指的並不是假的隨機數,這裡的“偽”是有規律的意思。其實絕對的隨機數只是一種理想狀態的隨機數,計算機只能生成相對的隨機數即偽隨機數。計算機生成的偽隨機數既是隨機的又是有規律的 —— 一部份遵守一定的規律,一部份則不遵守任何規律。比如“世上沒有兩片形狀完全相同的樹葉”,這正點到了事物的特性 —— 規律性;但是每種樹的葉子都有近似的形狀,這正是事物的共性 —— 規律性。從這個角度講,我們就可以接受這樣的事實了:計算機只能產生偽隨機數而不是絕對的隨機數。】

 

【通過time()函數來獲得計算機系統當前的日歷時間(Calendar Time),處理日期時間的函數都是以本函數的返回值為基礎進行運算。其原型為:time_t time(time_t * t); 如果你已經聲明了參數t,你可以從參數t返回現在的日歷時間,同時也可以通過返回值返回現在的日歷時間,即從一個時間點(例如:1970年1月1日0時0分0秒)到現在此時的秒數。如果參數為空(NULL或0),函數將只通過返回值返回現在的日歷時間。】

========================

 

如果我們在使用rand函數前沒有用srand函數制定seed的值,或者雖然用了srand函數,但是給它的參數是一個常量,比如srand(1),那麼每次程序運行rand產生的數字都是一樣的。只有用例如time()函數來給一個每次都不一樣的seed值,才能使得rand的返回值不一樣,才能做到“隨機”。

 

srand函數只需要在rand函數前面調用一次就夠了,也只能調用一次,之後你想要調用rand函數幾次都無所謂,但是每個程序中不能用兩次srand函數,切記。

 

下面演示一個程序,它會隨機生成一個整數,是介於0到4之間的:

 

#include
#include//必須的頭文件
#include//必須的頭文件

usingnamespacestd;

intmain()
{
intrandomNb(0);

srand(time(0));

randomNb=rand()%5;

return0;
}

 

隨機抽取單詞中的字母

 

隨機生成一個數字是很不錯啊,但是我們的程序是要隨機挑選單詞裡的一個字母呢!

 

那還不是一樣的原理。

 

我們要隨機抽取單詞中的字母,只要用下標就可以了。還記得之前的課裡提到string很類似數組嗎?因此,只要 數組名[下標] 的形式,下標隨機就可以了。例如secretWord[2]就是單詞的第三個字母。

 

一旦我們知道如何生成隨機數了,那麼只要規定生成的隨機數的范圍就可以啦,范圍就是:0~單詞中字母數減1

 

例如:

 

#include
#include
#include
#include

usingnamespacestd;

intmain()
{
stringsecretWord("MYSTERY");

srand(time(0));

intposition=rand()%secretWord.size();

cout<<"隨機抽取的字母是:"<

 

從字符串中刪除一個字符

 

那麼我們如何構建新的打亂的單詞呢?

 

我們可以用一個循環,從原始單詞中每次隨機抽取一個字符,然後添加到新的打亂的單詞中。

 

為了避免重復處理同一個字母,我們須要每次將抽取的字母從原始單詞中刪去。這樣,到最後,原始單詞的所有字母就會都"跑到"打亂的單詞中了。為了從字符串中刪除字符,我們可以使用erase這個方法:

 

secretWord.erase(4,1);//刪除原始單詞中的第五個字母

 

erase函數有兩個參數:

 

第一個參數表明從哪個字母開始刪除:上例中是4,就表明是從第五個元素開始刪除。畢竟數組是從0開始作為第一個下標的嘛。

第二個參數表明刪除幾個字符:上例中是1,因此只刪除從第五個字符開始的1個字符,也就是只刪除第五個字符。

 

創建函數

 

這一整個程序其實並沒有那麼復雜,不一定要創建新的函數。但是適時地使用函數絕對是好習慣。在我們的程序中,第二步的主要工作就可以交給一個自己創建的函數來做。

 

這樣,我們就可以在main函數中調用這個函數,如下:

 

mixedWord=mixLetters(secretWord);

 

我們將原始的單詞secretWord作為函數的參數傳遞給它,而函數的返回值則賦給打亂的單詞mixedWord。

 

好了,提示就到這裡了。

 

少年,放手一搏吧!

 


答案

 

相信你花了一些時間來思考,並且寫了程序。第一次你不一定都知道怎麼寫,但是沒關系,重點是思考和嘗試的過程。如果不思考直接來看答案,或嘗試了一下就放棄,那編程可是學不好的哦。

 

上面我們已經提過,此游戲的代碼可以分為三個部分來實現。第1步和第3步相對容易,只有第2步有些難度。

 

放上小編自己寫的版本。當然了,你可以寫得比我更好。我這個版本還是很基礎的。

 

翠花,上代碼:

=========================

#include
#include
#include
#include

usingnamespacestd;

//用於打亂單詞的函數
stringmixLetters(stringword)
{
    stringmixedWord;
    intposition(0);

    //只要還沒有抽完單詞裡的所有字母,就繼續while循環
    while(word.size()!=0)
    ?{
    ?    //在單詞中隨機選擇一個字母
    ?    position=rand()%word.size();
    ?    
    ?    //將此字母添加到新的單詞mixedWord中,也就是我們最後得到的打亂的單詞
    ?    mixedWord+=word[position];
    ?    
    ?    //將此字母從字符串中刪去
    ?    //為了不重復處理同一個字母
    ?    word.erase(position,1);
    }
    
    //返回打亂後的單詞
    returnmixedWord;
}

intmain()
{
    stringsecretWord,mixedWord,userEnteredWord;
    
    //初始化偽隨機數的種子
    srand(time(0));
    
    //1:請求玩家1輸入原始單詞
    cout<<"輸入一個單詞"<>secretWord;
    
    //2:用函數mixLetters將玩家1輸入的原始單詞打亂順序
    mixedWord=mixLetters(secretWord);
    
    //3:請求玩家2猜單詞
    do
    {
        cout<>userEnteredWord;
        
        if(userEnteredWord==secretWord)
        {
            cout<<"猜對了!好棒!"<

 

=========================

 

不要驚訝於此代碼的短小。也許只是你沒想到,看了代碼才發現,啊,原來這麼簡單,原來可以這麼寫。

 

下面對程序做分步解釋吧:

 

第一步:輸入單詞

 

這一步是最簡單的。cout來輸出一行提示消息。cin來獲取用戶輸入,存放到secretWord變量中。

 

第二步:打亂單詞

 

這一步是用一個函數mixLetters來實現的。

 

while(word.size()!=0)
{
    position=rand()%word.size();
    mixedWord+=word[position];
    word.erase(position,1);
}

 

每一次進入while循環體中,我們都隨機挑選單詞中的一個字母,然後將其放入新的打亂的單詞mixedWord中。最後將這個字母從原始的單詞中刪去。

 

一旦處理完原始單詞中所有的字母(也就是原始的單詞為空了),我們就跳出循環,函數會返回打亂後的單詞。

 

第三步:問用戶秘密單詞是什麼

 

這一步我們將使用一個do... while循環,以保證我們給用戶至少一次猜單詞的機會。

 

用cin來獲取用戶的輸入,然後與secretWord這個原始的單詞做比較,一旦兩者一致,則獲勝;否則就繼續循環。

 

}while(userEnteredWord!=secretWord);//只要沒猜對,就再進入while循環

 

每次都顯示一條消息:假如沒猜對,則顯示"猜錯了";假如猜到了,則顯示"猜對了!好棒!"

 


改進游戲

 

好了,我們的程序寫完了,不過始終可以改進。我們給出一些改進的建議:

 

在用戶1輸入單詞之後,想辦法"隱藏"單詞,不讓用戶2看到:可以使用加多個空行(endl);也可以有其他辦法。

使用戶可以一直玩:目前我們的游戲一輪就結束了。你可以在每一輪結束後顯示一行信息:"您還想繼續新一輪游戲嗎?(y/n)"。如果用戶輸入y,回車,則繼續新的一輪;如果用戶輸入n,回車,則退出游戲。

設置猜測次數上限:比如設置5次作為猜測的機會上限,那麼如果用戶5次沒猜中單詞的話,游戲也失敗。

計算玩家的平均分:每一輪的游戲所獲分數,可以設置比如1次就猜中的得10分,2次才猜中的9分,依次類推。然後把玩家所得總分除以所玩輪數,就是平均分啦

用一個文件儲存不少單詞,好像字典一樣,然後從中隨機選擇 : 這樣你就可以一個人玩了,不需要別人給你出題了。你的程序會從文件中隨機選中一個單詞,將其打亂,然後你自己來猜。下面是一個字典的例子:

 

FEATURE

MOTHER
ANSWER
CLOSE
GARAGE
DELETE
ENGINEER
ZERO
YESTERDAY
TOGETHER
JUICE
LAUGH

OFTEN
PEOPLE

KNOWLEDGE

 

當然,你可以自己填充英語單詞,或者去網上下載那種英文字典的txt文件,裡面有幾萬,幾十萬,甚至幾百萬個單詞,從中選擇的話就有猜單詞的樂趣和難度啦。

 

要讀取文件中的單詞,你可以用我們上一課學到的知識點:讀寫文件。

 

如果你自己還想到其他改進的點子,也可以去實現。你會發現通過這個游戲,自己進步了很多。

 

歡迎把改進後的游戲的代碼發給小編噢~


第一部分第十二課預告

今天的課就到這裡,一起加油吧!

下一課我們學習:指針一出,誰與爭鋒

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved