上一篇主題 :: 下一篇主題 |
發表人 |
內容 |
yag Site Admin
註冊時間: 2007-05-02 文章: 689
2704.11 果凍幣
|
發表於: 2007-6-2, AM 10:43 星期六 文章主題: [C++][7]if、goto、隨機亂數、邏輯和關係運算子、算術運算子 |
|
|
if就是如果,很好理解的一個指令,它是判斷的基礎,人工智慧的入門。人活在世上就要判斷,像是如果下雨了,就要帶傘,如果累了,就要睡覺,如果餓了,就要吃飯。程式也要判斷,判斷就是程式跟人類互動的最基本方法,以下直接來看範例: 代碼: | #include <iostream>
#include <time.h>
using namespace std;
int main()
{
char yesno;
short choise = 0, computer = 0;
int win = 0, lose = 0, deuce = 0;
cout << "這是猜拳遊戲,請從剪刀、石頭、布中選擇其一," << endl
<< "規則是剪刀贏布,布贏石頭,石頭贏剪刀。" << endl;
system( "pause" );
system( "cls" );
srand( (unsigned)time( NULL ) );
Choose:
cout << "勝場:" << win << " 敗場:" << lose << " 平手:" << deuce << endl;
cout << "請輸入1~3:(1.剪刀 2.石頭 3.布)" << endl;
cin >> choise;
if( choise < 1 || choise > 3 )
goto Choose;
computer = rand() % 3 + 1;
if( choise == computer )
{
cout << "平手!" << endl;
deuce++;
goto Choose;
}
else if( (choise == 1 && computer == 3) || (choise == 2 && computer == 1) || (choise == 3 && computer == 2) )
{
cout << "你贏了!" << endl;
win++;
}
else
{
cout << "你輸了!" << endl;
lose++;
}
cout << "要繼續嗎?( y/n )" << endl;
cin >> yesno;
if( yesno != 'n' && yesno != 'N' )
{
system( "cls" );
goto Choose;
}
return 0;
} | 首先一開頭,這次多了一個#include <time.h>,這是為了讓我們可以使用time()函數,這個函數可以拿來當做srand()函數的種子參數,srand()函數的功能是選定隨機亂數表的一個起始點,而我們將time()函數傳入,也就是代表這個起始點會隨時間變化而不同,才不會每次執行程式時,都以同一個起始點進入,這樣才不會被人記住亂數的順序,而之後使用的rand()函數才是真正會回傳隨機亂數給我們的函數。額外提醒一下,srand()只需要在程式開頭的地方呼叫一次就行了,而rand()則是每次呼叫都會傳回一個不同的數字,呼叫次數不限。
接著看到int win = 0, lose = 0, deuce = 0;這行,我們除了宣告外,還同時給予了每個變數一個初始值:0,理論上來說,良好的程式寫作習慣,應該要在變數宣告的同時給予每個變數一個初始值,這樣才不會發生忘了給值就使用變數而出現不可預期錯誤的情況。
再來是system( "cls" );,這是清除cmd畫面的意思,程式執行過一次,應該很容易就可以理解。
Choose:是一個Tag,也就是標籤,它註明了goto指令應該回到的地方。goto是一個頗具有爭議性的指令,雖然在組合語言中,它是不可或許的,但是在較為高階的語言,如C++中,它卻被視為容易搞亂程式流程使程式碼閱讀不順暢的一個指令,尤其是程式一大,如果數千行,然後又有數十個Tag,光是想像那goto來goto去的流程,就會讓人眼花瞭亂,而且最重要的是,它並不是不可取代、必須使用的指令,我們後面會講到迴圈,只要擅用判斷跟迴圈,完全可以用另一種邏輯避免掉使用goto的可能性,但在某些情況下,goto的確也是有它的方便性,我是認為沒有必要使之為洪水猛獸,只要不濫用就行了。
現在看到我們的第一個if,if( choise < 1 || choise > 3 ),我想這應該不會太難理解,這行說的就是如果choise小於1或大於3,則怎樣怎樣…,那個怎樣怎樣…也就是下面那行的goto Choose;,當if之後只有一行敘述時,可以不用加上大刮號{},但當有兩行以上的敘述時,就必須用大刮號刮起來,像是範例中後面的幾個if,其下之敘述都有用大刮號刮起來,代表這是滿足了if條件後該做的事。
這邊要提個新手非常容易犯的錯誤,那就是把if( choise < 1 || choise > 3 )寫成if( choise < 1 || > 3 ),這樣是絕對不行的,雖然口語上會併在一起說成是如果choise小於1或大於3,但並不代表程式可以這樣寫,後面那個大於3前的choise一樣必須要寫出來才行。
既然已經看過if了,在此我就先把幾個邏輯運算子和關係運算子標示出來: 代碼: | 邏輯運算子:
|| 或者
&& 並且
! 否定
關係運算子:
== 相等
> 大於
< 小於
>= 大於等於
<= 小於等於
!= 不等於 | 應該很好理解才對,if( choise == computer )就是如果我出的拳跟電腦的一樣,而if( yesno != 'n' && yesno != 'N' )就是如果輸入的不是小寫的n並且也不是大寫的N,這邊要注意一下,又有個新手容易犯錯的地方,就是上面那句話,以口語一點的方式說出,我們一般會說為如果輸入的不是小寫的n或者大寫的N則怎樣怎樣…,這是因為我們把「大寫的N」前面的「也不是」口頭省略掉了,所以會出現用「或者」這個詞,也因此新手常常會寫成if( yesno != 'n' || yesno != 'N' ),這是絕對錯誤的,仔細想想就會知道,||是代表或者,可以唸做or,它的意思就是兩個條件中,滿足任一個條件則執行該做的事,如果在此用了||,那麼我輸入小寫的n時,它肯定不是大寫的N,所以我滿足了後面一個條件,而我輸入大寫的N時,它肯定不是小寫的n,所以我滿足了前面一個條件,因此不論如何,這個if肯定滿足,它就變成沒有用處的判斷了,只有當我同時等於n又等於N時,它之下的敘述才不會執行,但一個字顯然不可能同時等於兩個字。
接著我要介紹c++中的算術運算子,最基本的+加、-減、*乘應該沒有太大的問題,重點在/除以及%模數(除法中的餘數)。
在C++中,int num = 5 / 2;得出的num會是多少?答案是2。因為在C++中的整數除法,會直接去掉小數的部份,只得到整數,以下是範例: 代碼: | #include <iostream>
using namespace std;
int main()
{
int a = 5 / 2;
float b = 5 / 2;
float c = 5.0 / 2;
float d = 5 / 2.0;
float e = 5.0 / 2.0;
cout << a << endl << b << endl << c << endl << d << endl << e << endl;
system( "pause" );
return 0;
} | 執行後,a跟b會得到2,c、d、e會得到2.5,而只有a跟b的/可以換成%,得到的結果都是1,也就是5除以2會餘1的意思,至於為什麼b會得到2,那是因為在等號右邊是以整數在做運算的,得出2後,才會從int轉成float存入b中,所以b會得到2,這也是b可以把/改成%的原因,因為右邊是整數的運算。至於cde,因為右邊的算式中都有1個以上的浮點數(也就是小數,還記得吧?),所以整個算式中的數字都會先被轉成浮點數後才進行計算,也因此得到的答案會是2.5,這是c++的算術規則。
根據以上的說明,想必computer = rand() % 3 + 1;不會太難理解,rand()會得到一個亂數,將它除以3取餘數,任何數除以3肯定不是餘0、餘1就是餘2,後面再加個1,因此得到的數字肯定就是在1~3之間,那麼我們就得到了電腦打算出剪刀還是石頭或者布。
接著我們會看到一個新的運算子:deuce++;,這行程式碼會等同於deuce = deuce + 1;,也就是將其原本的值加上1再存回去,相對於++(遞增運算子),也有--(遞減運算子),想必不用介紹了,就是減個1罷了。
最後要說的是else,這是跟if配合的一個指令,不能單獨存在,一定要成為以下型式: 代碼: | if( ... )
{
...
}
else
{
...
} | 以白話來說就是「如果怎樣怎樣就如此如此,否則就那樣那樣」,else也就是否則的意思。
當然這個架構也可以無限延伸,變成像範例中的if…else if…else…,中間的else if可以有無限多個,其意義應該很清楚,就不多做解釋了。
到此,這個程式應該沒什麼不能理解的地方了,在此再提一個小地方,也就是if( yesno != 'n' && yesno != 'N' )中的'n'和'N'分別用兩個單引號' '刮了起來,這是代表它們是字元而不是某某變數名稱當然也不可能是數字,如果忘了加上這兩個單引號,那麼它就會是代表一個未曾宣告過的變數名稱,而如果用兩個雙引號" "刮起來,像:"n"(ps.這絕對不是4個單引號...請找到雙引號鍵),那麼代表了這是一個只有一個字元長度的字串,我們在後面會教到字串,在此先不提,只要記得字元必須用單引號刮起來就行了。
那麼最後我出個習題吧。
第一:誰能解釋一下if( (choise == 1 && computer == 3) || (choise == 2 && computer == 1) || (choise == 3 && computer == 2) )是什麼意思呢?
第二:範例中有段if…else if…else…,其中最後一個else事實上也可以改成else if,並不一定要以else結尾,而且以else結尾時,其意義有點被隱藏起來了,並不是一眼就可以了解那個else代表了什麼意思。那麼,請問最後一個else要改成怎樣的else if才是正確的呢?(也就是請把最後一個else潛在的意思明白的用else if表達出來)。
yag 在 2007-8-6, PM 1:56 星期一 作了第 2 次修改 |
|
回頂端 |
|
|
yag Site Admin
註冊時間: 2007-05-02 文章: 689
2704.11 果凍幣
|
發表於: 2007-6-2, PM 1:19 星期六 文章主題: |
|
|
我寫這篇居然花了3個半小時...
真是有夠久的= ="
本來範例想寫猜數字遊戲的,但寫到一半才發現,猜數字沒用到迴圈實在不好寫,哈哈,所以才改成了猜拳,至於猜數字,等講解到迴圈後再說吧。
話說我每篇教學中的範例要寫什麼都會想滿久的,因為希望只用目前已教到的東西,還要突顯出這篇正在教的東西,最重要的是,要能夠有趣一點...實在是滿傷腦筋的,如果光是隨便用新教到的東西寫幾個沒意義的範例,當然是很快,但這麼一來學起來就會滿乏味的,即使目前教到的東西不多,我也希望可以寫一些跟遊戲扯上邊的範例,利用有限的資源做無限的發想,這樣才有趣嘛,哈哈。
因此...進度慢是必然的,只好出些習題囉,哈哈。
只是不知道到底有沒有人在看...搞不好跟本沒人要做習題 |
|
回頂端 |
|
|
kage01 時常出沒的會員
註冊時間: 2007-05-22 文章: 32
2.00 果凍幣
|
發表於: 2007-6-3, PM 2:01 星期日 文章主題: |
|
|
來做習題
變數名稱應該用Choices?
一.if 玩家出剪刀且電腦出布 或者 玩家出石頭電腦出剪刀 或者玩家出布電腦出石頭
cout<<"你贏了!!"<endl;
二.
else if((choise == 1 && computer == 2) || (choise == 2 && computer == 3) || (choise == 3 && computer == 1))
{
cout<<"你輸了!!<<endl;
lose++;
}
BTW
當使用者輸入小數點進choices變數時 就進入無限迴圈了
資料型態雖然是short
但為什麼會進入無限迴圈呢. |
|
回頂端 |
|
|
yag Site Admin
註冊時間: 2007-05-02 文章: 689
2704.11 果凍幣
|
發表於: 2007-6-3, PM 2:51 星期日 文章主題: |
|
|
感謝你的賞光
嗯,我英文打錯了,哈哈,應該是choice,複數也行啦,不過看得懂就好
你兩題都答對了
可是什麼是BTW?
另外...你抓到的這個bug果然夠奇怪,我也不知道為什麼會進入無限迴圈@_@"
我目前檢查起來,是cin時,如果把「.」丟給choice,它就會進入無限迴圈...
我再查查看是什麼原因好了 |
|
回頂端 |
|
|
kage01 時常出沒的會員
註冊時間: 2007-05-22 文章: 32
2.00 果凍幣
|
發表於: 2007-6-3, PM 3:21 星期日 文章主題: |
|
|
哈哈
By the way啦
有時候懶用簡寫. |
|
回頂端 |
|
|
yag Site Admin
註冊時間: 2007-05-02 文章: 689
2704.11 果凍幣
|
發表於: 2007-6-3, PM 3:29 星期日 文章主題: |
|
|
喔喔,原來如此,對了,我查到為什麼會無限迴圈囉~
這是個滿好的問題,我另開一個主題說明好了,順便講講怎麼解決。
請看這:[疑難雜症]cin無限迴圈錯誤 |
|
回頂端 |
|
|
流水魚 稍嫌羞澀的路人
註冊時間: 2009-05-04 文章: 1
15.01 果凍幣
|
發表於: 2009-5-8, AM 12:50 星期五 文章主題: |
|
|
yag大大好
小弟我是剛學習C++的新手,才學習3天(之前有VB的小小基礎),看到大大的文章,受益良多,但是疑問也頗多~"~,希望大大能幫忙解答
問題如下
關於您寫的第7篇文章"[7]if、goto、隨機亂數、邏輯和關係運算子、算術運算子"此篇文章中有1個猜拳遊戲,遊戲中利用數字來猜拳,但是每當輸入錯誤,就會迴旋,雖然大大在"[C++疑難雜症]cin無限迴圈錯誤"此篇文章中有教如何修復,但是小弟我扔然發現1個小問題,就是如果輸入"a1a2a3a1a2a3a1a2a3"這種類似英文卡數字交雜的,會造成該程式一次跳非常多場比賽,想請教大大,能否讓玩家數入的數字上限只有1位數
小弟誠心發問 希望大大幫忙
由於小弟我才來此網站3天,許多文章皆未閱讀,所以如果之前有人發過文,請見諒,並且麻煩大大貼個網址給小弟,謝謝 |
|
回頂端 |
|
|
yag Site Admin
註冊時間: 2007-05-02 文章: 689
2704.11 果凍幣
|
發表於: 2009-5-8, PM 12:10 星期五 文章主題: |
|
|
流水魚 寫到: | yag大大好
小弟我是剛學習C++的新手,才學習3天(之前有VB的小小基礎),看到大大的文章,受益良多,但是疑問也頗多~"~,希望大大能幫忙解答
問題如下
關於您寫的第7篇文章"[7]if、goto、隨機亂數、邏輯和關係運算子、算術運算子"此篇文章中有1個猜拳遊戲,遊戲中利用數字來猜拳,但是每當輸入錯誤,就會迴旋,雖然大大在"[C++疑難雜症]cin無限迴圈錯誤"此篇文章中有教如何修復,但是小弟我扔然發現1個小問題,就是如果輸入"a1a2a3a1a2a3a1a2a3"這種類似英文卡數字交雜的,會造成該程式一次跳非常多場比賽,想請教大大,能否讓玩家數入的數字上限只有1位數
小弟誠心發問 希望大大幫忙
由於小弟我才來此網站3天,許多文章皆未閱讀,所以如果之前有人發過文,請見諒,並且麻煩大大貼個網址給小弟,謝謝 |
嗯,抱歉,昨晚回信給你之後我就跑去睡了@_@"
沒想到你回應得那麼快。
總之,我們先來看看下面這份程式碼吧:
代碼: | #include <iostream>
#include <time.h>
#include <conio.h> // 必要 for getch()
using namespace std;
int main()
{
char yesno = '\0';
char Choise = '\0';
short choise = 0, computer = 0;
int win = 0, lose = 0, deuce = 0;
bool bGoodInput = false;
cout << "這是猜拳遊戲,請從剪刀、石頭、布中選擇其一," << endl
<< "規則是剪刀贏布,布贏石頭,石頭贏剪刀。" << endl;
system( "pause" );
system( "cls" );
srand( (unsigned)time( NULL ) );
Choose:
cout << "勝場:" << win << " 敗場:" << lose << " 平手:" << deuce << endl;
cout << "請輸入1~3:(1.剪刀 2.石頭 3.布)" << endl;
// 判斷輸入是否合法
while( !bGoodInput )
{
Choise = getch();
if( isdigit( Choise ) )
{
choise = atoi( &Choise );
if( choise >= 1 && choise <= 3 )
{
bGoodInput = true;
cout << choise << endl;
}
}
}
bGoodInput = false;
computer = rand() % 3 + 1;
if( choise == computer )
{
cout << "平手!" << endl;
deuce++;
goto Choose;
}
else if( (choise == 1 && computer == 3) || (choise == 2 && computer == 1) || (choise == 3 && computer == 2) )
{
cout << "你贏了!" << endl;
win++;
}
else
{
cout << "你輸了!" << endl;
lose++;
}
cout << "要繼續嗎?( y/n )" << endl;
// 判斷輸入是否合法
while( !bGoodInput )
{
yesno = getch();
if( yesno == 'y' || yesno == 'y' )
{
system( "cls" );
goto Choose;
}
else if( yesno == 'n' || yesno == 'N' )
bGoodInput = true;
}
return 0;
} |
你可以先copy下來run一次看看
先了解一下它的功能
我是把它做成只有輸入1或2或3時才會有反應,其他鍵都不會有反應
另外跟以前不同的是,輸入1或2或3之後不需要按enter,它會直接執行下去
後面詢問y或n的也是同樣的道理
要做到這樣,首先我們必須先#include <conio.h>
接著我們才能呼叫getch()函式
上面這段程式碼我主要變動的只有兩個「判斷輸入是否合法」的區塊
首先我用bGoodInput布林變數來判斷輸入是否合法了
接著Choise = getch();這行是用來取得單一字元
getch()事實上是c語言的函式,不過c++是完全相容c語言的,所以我們也可以拿來用
它的功能是讀取一個字元,並且不會將這個字元顯示在螢幕上
輸入字元時,只要按下了按鍵,它就會立刻回傳,不需要按enter來確定
那麼,我們現在把讀進來的字元存在了Choise字元變數裡
然後if( isdigit( Choise ) )會判斷這個字元是否是數字
如果不是的話,代表輸入是不合法的,直接跳過,然後重複迴圈,又回到getch那行等著接收字元
如果是的話,我們再往下看choise = atoi( &Choise );
atoi會把字元或字串轉成數字,注意兩個choise、Choise的開頭c大小寫不同,一個是int型態,一個是char型態
現在我們得到了一個數字choise,再看看它是否在1到3之間
不是的話,代表輸入還是不合法,又重複迴圈
是的話,代表輸入合法了,把bGoodInput布林變數改成true以跳出迴圈,並且把我們接收到的字元輸出,這行是為了讓使用者知道他自己是輸入了什麼
等跳出迴圈後,很重要的一點就是要把bGoodInput布林變數再次設為false,這樣下次再進入判斷是否合法的迴圈時它才能起作用,不然直接就跳掉了,連等待輸入的機會都沒有
大致就是這樣,下面那個區塊也是類似的邏輯,我想你可以看得懂的
而下面的區塊在跳出迴圈後,之所以沒有把bGoodInput布林變數設為false,當然是因為程式已經要結束了,設不設都沒差了 |
|
回頂端 |
|
|
冰葉 稍嫌羞澀的路人
註冊時間: 2009-05-23 文章: 2
11.90 果凍幣
|
發表於: 2009-5-24, PM 9:53 星期日 文章主題: |
|
|
yag 寫到: | 我寫這篇居然花了3個半小時...
真是有夠久的= ="
本來範例想寫猜數字遊戲的,但寫到一半才發現,猜數字沒用到迴圈實在不好寫,哈哈,所以才改成了猜拳,至於猜數字,等講解到迴圈後再說吧。
話說我每篇教學中的範例要寫什麼都會想滿久的,因為希望只用目前已教到的東西,還要突顯出這篇正在教的東西,最重要的是,要能夠有趣一點...實在是滿傷腦筋的,如果光是隨便用新教到的東西寫幾個沒意義的範例,當然是很快,但這麼一來學起來就會滿乏味的,即使目前教到的東西不多,我也希望可以寫一些跟遊戲扯上邊的範例,利用有限的資源做無限的發想,這樣才有趣嘛,哈哈。
因此...進度慢是必然的,只好出些習題囉,哈哈。
只是不知道到底有沒有人在看...搞不好跟本沒人要做習題 |
放心....我有努力在看.....謝謝大大的努力...
那不會白費的 |
|
回頂端 |
|
|
chongren 偶而上來逛逛的過客
註冊時間: 2009-07-27 文章: 14 來自: 台北 152.02 果凍幣
|
發表於: 2009-9-16, PM 12:37 星期三 文章主題: |
|
|
請問這程式的按鍵部分在哪呢?! _________________ 爬文?
爬文這種舉動不適合我這種腦殘 |
|
回頂端 |
|
|
yag Site Admin
註冊時間: 2007-05-02 文章: 689
2704.11 果凍幣
|
發表於: 2009-9-22, PM 12:28 星期二 文章主題: |
|
|
chongren 寫到: | 請問這程式的按鍵部分在哪呢?! |
有cin的部份就會等待你的輸入
你可以找個compiler自行編譯並run一次看看 |
|
回頂端 |
|
|
mimisa01 偶而上來逛逛的過客
註冊時間: 2009-11-05 文章: 7
146.17 果凍幣
|
發表於: 2009-11-5, AM 1:54 星期四 文章主題: Re: [C++][7]if、goto、隨機亂數、邏輯和關係運算子、算術運算子 |
|
|
代碼: |
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
main(){
srand(time(NULL)); //這段是參考貴站的其他文章,我本來不會QQ
int i;
int j=0,code;
code = rand();這段也是參考貴站的其他文章,我本來也是不會QQ
printf ("猜數字遊戲1 - 10000 ,離開打99999\n");
for( ; ; ){
printf ("猜數字1 - 10000:");
scanf ("%d",&i);
if(i==code){
printf ("答對!!不過沒有獎品!!See You~\n");
printf ("總共答題%d次",++j);
break;
}
else if(i==99999){
printf ("See You Good Bye!!");
break;
}
else if(i<code){
printf("%d < code\n",i);
printf ("答題第%d次\n",++j);
}
else if(i>code){
printf ("%d > code\n",i);
printf ("答題第%d次\n",++j);
}
}
system ("pause");
}
|
您好~我是個新手,想請教
如果想把隨機的時間亂數設定在9999之內,不知道該如何設定.謝謝~
小弟的思考方向應該是在srand(time(NULL));
或是code = rand();這裡加東西對不對@@?
感謝指教 _________________ 一步一腳印 |
|
回頂端 |
|
|
hk8100_00 偶而上來逛逛的過客
註冊時間: 2009-06-27 文章: 10
255.69 果凍幣
|
發表於: 2009-11-5, PM 6:01 星期四 文章主題: |
|
|
本人是學C++的
將random number在9999以下
10-9999
代碼: | int rn=rand()%10+9999; |
我都不是很明隨機數,請高手們指教 !! |
|
回頂端 |
|
|
mimisa01 偶而上來逛逛的過客
註冊時間: 2009-11-05 文章: 7
146.17 果凍幣
|
發表於: 2009-11-5, PM 9:09 星期四 文章主題: |
|
|
hk8100_00 寫到: | 本人是學C++的
將random number在9999以下
10-9999
代碼: | int rn=rand()%10+9999; |
我都不是很明隨機數,請高手們指教 !! |
感謝教學^^ _________________ 一步一腳印 |
|
回頂端 |
|
|
yag Site Admin
註冊時間: 2007-05-02 文章: 689
2704.11 果凍幣
|
發表於: 2009-11-7, PM 12:34 星期六 文章主題: |
|
|
rand() % 9999 → 0~9998
rand() % 10000 → 0~9999
rand() % 9999 + 1 → 1~9999
rand() % 10 → 0~9
rand() % 10 + 9999 → 9999~10008
rand() % 9990 → 0~9989
rand() % 9990 + 10 → 10~9999
rand() % n → 0~n-1
rand() % n + m → m~m+n-1
hk8100_00說的有些地方有誤,以上是正解 |
|
回頂端 |
|
|
|