yag Site Admin
註冊時間: 2007-05-02 文章: 689
2704.11 果凍幣
|
發表於: 2007-8-6, PM 1:53 星期一 文章主題: [C++][10*]習題解答 |
|
|
嗯...我回來了...
那麼,先來個習題解答吧
首先是初級的...很簡單,把
代碼: | else if( Move == "get coins" ) // 撿錢 |
改成
代碼: | else if( Move == "get coins" || Move == "g" ) // 撿錢 |
就行了
中級的,我是改成了如下:
代碼: | char death = NULL; // 判斷是否結束遊戲的旗標
Init( MapDesc );
while( 1 )
{
fflush( stdin ); // 消除下面cin >> death;時,使用者輸入的過多資訊
Desc( MapDesc, X, Y );
InputCmd( X, Y ); // 因為主角剛出現時要預設為無事狀態,所以先在迴圈外呼叫一次
while( status != 99 ) // 遊戲未結束前
{
Desc( MapDesc, X, Y ); // 顯示場景說明
CoinOrDingDing(); // 顯示出特殊情況說明
InputCmd( X, Y ); // 等待接收輸入
}
ASK:
cout << "你已經死了!三途之川的船在前方等著你,要上船嗎?(y/n)" << endl;
cin >> death;
if( death == 'y' || death == 'Y' )
{
cout << "擺渡人拉拉:你好!你好!" << endl;
cout << "擺渡人拉拉:抱抱!" << endl;
cout << "擺渡人拉拉:說.再.見!" << endl;
cout << "擺渡人拉拉:再見!" << endl;
system( "pause" );
break; // 跳離while(1),遊戲結束
}
else if( death == 'n' || death == 'N' )
{
cout << "Yag大神以巫師的神力使你原地復活!" << endl; // 原地復活,所以X跟Y不變
cout << "你心懷感激地將身上的金幣全部交出當成治療費。" << endl;
MyMoney = 0; // 將錢交出
system( "pause" );
system( "cls" );
status = 0; // 因為復活,將狀態改回正常狀態
}
else
goto ASK; // 隨便輸入就重新發問
}
return 0; |
你們會發現,我把CoinOrDingDing();給抽了出來,那是因為我為了寫高級習題,把一些函式做了修改的關係,底下會進行說明。
話說,我當初出高級習題時,沒有仔細想清楚就出題了,呵呵,所以真的有去思考的人,應該會覺得有些微的彆扭吧,因為程式的一些細微架構並不適合直接寫一個get函式。
比如說,地上隨機出現的money是個區域變數,由CoinOrDingDing();傳給InputCmd,要是又寫了個get函式,那麼勢必要再傳給get才能進行處理,但我當初出題時沒想到這點,所以並沒有把money當成參數之一。
不過如果把money當成參數之一,又會有其他問題,像是之後再擴展時,如果地上有屍體、有裝備的話呢?再一一增加參數一個一個傳?這恐怕不是什麼好方法。
何況如果地上有裝備的話,勢必要在地圖上增加一個掉落物的陣列來儲存目前地面上有的物品,不然只要一離開地圖再回來,物品就消失了,感覺會比較差,另外,如果有機會把它改成可連線的遊戲,那麼不記錄掉落物,就會造成別人丟在地上的東西你看不到的情形。
所以,雖然目前我還沒把掉落物陣列加進來,不過為了未來的擴展性,我將money改成了全域變數,也因此CoinOrDingDing不再需要傳參數出來,InputCmd也不再需要讀個money參數進來,所以CoinOrDingDing理所當然的就被抽出來了。
那麼,底下是寫get函式時主要變動到的部份:
代碼: | void get( string things = "coins" ); // 撿起東西,預設為撿金幣 |
代碼: | int moneyOnGround = 0; // 隨機出現在地上的金幣數量 |
上面兩個都是寫在main之前的宣告
代碼: | else if( Move.substr( 0, 4 ) == "get " ) // 撿東西
{
for( i = 4; i < Move.length(); i++ ) // 去掉前面的多餘空白
{
if( Move.substr( i, 1 ).compare( " " ) != 0 )
break;
}
if( i == Move.length() ) // 除了一堆空白外沒別的東西
get();
else
get( Move.substr( i, Move.find_last_not_of( " " ) - i + 1 ) ); // 去掉後面的多餘空白,傳入get()
Flag = true; // 因為撿東西並沒有離開場景,所以繼續迴圈
}
else if( Move.substr( 0, 2 ) == "g " ) // 撿東西
{
for( i = 2; i < Move.length(); i++ ) // 去掉前面的多餘空白
{
if( Move.substr( i, 1 ).compare( " " ) != 0 )
break;
}
if( i == Move.length() ) // 除了一堆空白外沒別的東西
get();
else
get( Move.substr( i, Move.find_last_not_of( " " ) - i + 1 ) ); // 去掉後面的多餘空白,傳入get()
Flag = true; // 因為撿東西並沒有離開場景,所以繼續迴圈
}
else if( Move == "get" || Move == "g" ) // 撿東西
{
get();
Flag = true; // 因為撿錢並沒有離開場景,所以繼續迴圈
} |
上面是InputCmd中處理的部份,大家可以看到我把它分成了三個if,這是為了讓g跟get具有同等效力,至於substr、compare、find_last_not_of之類的,是為了讓玩家的輸入格式可以自由一點,像是以往只接受:
"get coins"
改了初級的還接受:
"g"
現在的話,可以接受以下各種格式:
代碼: | "g "
"g coins "
"get "
"get"
"get coins "
"g coins"
"get coins" |
換句話說,開頭可以用g可以用get,而此指令跟撿起的目標物之間的空白會盡數忽略,撿起的目標物之後的空白也會盡數忽略,這在之前是辦不到的,之前只要多打了一個空白字元就會造成輸入錯誤。
那麼,來講講substr,這個函式可以取得目前字串的子字串,第一個參數是起始索引,第二個參數是要取得的長度,例:
"get coins" → substr( 0, 1 ) == "g"
"get coins" → substr( 2, 4 ) == "t co"
"get coins" → substr( 5, 7 ) == "oins"
應該可以了解到,索引是從0開始計算,而長度是從1開始計算,第三個例子中,雖然長度為7,但是字串已結束,所以只會抓到字串尾巴就停止。
至於length函式,當然是取得字串的長度,長度是由1開始計算,所以字串的最大索引會是length - 1,因為索引在C++中總是由0開始的。
接著的compare函式,會對字串做比較的動作,唯一的一個參數,就是做比較的目標字串,在程式中我這樣寫:
代碼: | Move.substr( i, 1 ).compare( " " ) |
就是從Move中取得一個字元長度的子字串,並將它跟空白字元做比較,如果兩者相同,會回傳一個數值為0,如果Move比空白字元"大",那會回傳一個正整數(在我的compile下,它是1),如果Move比空白字元"小",那會回傳一個負整數(在我的compile下,它是-1)。
那麼,字串怎麼分大小呢?以英文字母來說,大寫字母比較小,小寫字母比較大,然後從第一個字元開始比大小,如果第一個字元一樣,那就從第二個字元開始比,以下是一些例子:
"abc" > "ABC"
"abcd" > "abc"
"abc" > "aaa"
"h" > "abc"
"game" > "abcdefg"
"game" > "gal"
"gun" > "game"
最後是find_last_not_of函式,它的功能就是從字串的最尾巴開始往回找,找出第一個不屬於其唯一參數(字元集)的字元,然後回傳它的索引,接著後面的索引減掉前面的索引再加上一,就是我要的子字串的長度囉。
關於字元集,大家可能不太了解其意思,底下是個例子:
代碼: | string test = "What a nice day!!";
cout << test.find_last_not_of( "AaEeIiOoUu" ) << endl;
cout << test.find_last_of( "AaEeIiOoUu" ); |
這段程式碼的輸出會是:
16
13
"What a nice day!!"總共17個字,索引從0(W)到16(!),而"AaEeIiOoUu"就是我們的字元集,find_last_not_of,會從最後面找尋第一個不屬於這字元集的字元,那也就是第二個"!",所以回傳索引為16。
接著find_last_of應該不用多講解,跟find_last_not_of只差了個not,所以就是從後找尋第一個屬於其字元集的字元,也就是day當中的"a",因此其回傳索引為13。
這樣應該有了解了吧?習題解答就到此為止,下面是整個程式碼(cpp檔)的載點以及其執行檔(exe檔)的載點,希望對你們有用。
main.cpp(13KB)
example10-2.exe(288KB) |
|