標籤:
一、背景
黃金點遊戲是一個數字小遊戲,其遊戲規則是:
N個同學(N通常大於10),每人寫一個0~100之間的有理數 (不包括0或100),交給裁判,裁判算出所有數位平均值,然後乘以0.618(所謂黃金分割常數),得到G值。提交的數字最靠近G(取絕對值)的同學得到N分,離G最遠的同學得到-2分,其他同學得0分。玩了幾天以後,大家發現了一些很有意思的現象,比如黃金點在逐漸地往下移動。
現在請大家根據這個遊戲規則,編一個可以多人一起玩的小遊戲程式,要求如下:
1、本作業屬於結對程式設計項目,必須由二人共同完成,並分別將本次作業過程發到部落格,同時將本次作業原始碼提交到codeing系統;
2、如果可能的話盡量以C/S或B/S方式實現,即利用伺服器接收和處理所有玩家提交的數字,並將結果反饋給各玩家,玩家可以通過用戶端提交的數字;
3、如果採用單機方式實現的話,需要為使用者提供便利的輸入介面;
4、該遊戲每次至少可以運行10輪以上,並能夠保留各輪比賽結果。
二、分析
這個小遊戲,你肯定會想, 如果大家隨機報數的話,
第一輪開始:可能是真正的隨機,0-100 的平均數是50, 50 * 0.618 = 31. 那我就來個 31。
第二輪開始:當大家漸漸明白了遊戲的BUG時候,但 他們肯定也想到選31附近,如果大家大家都選 31 附近的數, 那我得選 31*0.618 = 19;
第三輪以及之後的。。。。。。
但是這些人肯定也想到了這一點, 那我要選 19 * 0.618 = 12… 然後 12 * 0.618 = 8
。。。。。。。。
最後乾脆選越小的數,例如0.00000000001,這是個有理數。
0.00000000001是正確答案麼? 這取決於參與遊戲的所有成員。
當這個遊戲的人員都是程式員或者都是智商比較高的人員,遊戲的確會出現我們之前預測的一樣,G點的值在不斷的下降。
但是如果是一群知識為了開心的玩耍的小夥伴呢,那麼這個結果就會出現各種情況,結果不具有預見性,但是你仔細觀察會發現,G值的大小不是由少數人決定的,而是由大多數人決定的。最恐怖是反向逆行的遊戲者最後都“守約” 提交了大數,最終你的分數是負數,再來一輪,你也不是傻瓜,你也會使自己的數足夠的小,走出自己是-2分的局面。
黃金比例0.618,在生活中,學習都可以經常見到,黃金比例分割是指把一條線段分割為兩部分,使其中一部分與全長之比等於另一部分與這部分之比。其比值是一個無理數,取其前三位元字的近似值是0.618。所謂黃金分割,指的是把長為L的線段分為兩部分,使其中一部分對於全部之比,等於另一部分對於該部分之比。而計算黃金分割最簡單的方法,是計算斐波那契數列1,1,2,3,5,8,13,21,...後二數之比2/3,3/5,4/8,8/13,13/21,...近似值的。
三、易錯點
之前自己認為是整數,當自己輸入時有理數時候程式自動停止。當程式中出現中國人的名字的時候時候可以儲存,當map中沒有清空。。。。。。。。。
易出現的錯誤(1):是有理數,不是整數
原因及解決辦法:改變map<string,int>mp;--->map<string,double>mp;這個就是map非常靈活的地方,自己可以自己定義資料類型。
易出現的錯誤(2):當遊戲人數不變時,人員發生改變時,大家還是可以繼續玩
原因及解決辦法:每一次的求和,平均值,G值清空。
易出現的錯誤(3):當人員名字改變時,每一輪的遊戲開始都是新的開始
解決原因及辦法:自己的map每一次都沒有清空,使用的map中的函數clear(),語句是使用mp.clear()清空。
當第一輪中的人員和第二輪中的人員不一樣時,map中存了所欲哦
易錯點(4):每一輪的輸入可不可以不按照一定順序的輸入,但是map最終是以map字典序的輸出,
原因及解決辦法:map還有一個優點是自動對第一個欄位進行排序。所以在遊戲中可以可以當有的人還沒有想好交上什麼資料,可以跳過,不會影響到結果的。
大家選取的資料越來越小的時候,會出現G值的確會逐漸減小。
四、結對程式設計的照片(Ps:認真帥氣漂亮)
五、總結和評價
這一次結對程式設計,可以說不是自己的第一次結對程式設計,在ACM中經常就是一個編程,一個人複審,另外一個人提供思路,然後交叉輪流編程,輪流代碼審核,這樣編程效率高,還不容易出錯,而且可以通過結對程式設計,熟悉瞭解搭檔的編程風格和思路模式,也是對自己的不足的地方一種提高。是一種相互學習的方式,只會讓結對程式設計的兩人的編程水平共同提高,但是存在這樣的情況,你壓根不想和他一起編程,只會讓彼此相互埋汰,然後工作效率低。
對隊友的評價:在明白題意後,自己的思路是使用STL中的Map,時間複雜度logn,我先把map建立與資料的輸入進行簡單的測試,然後再把寫到多輪遊戲的開始完成。但是她給我提出一個如果要顯示多輪之後的成績怎麼顯示,她說,他可以定義另外一個map的變數,用來存每一次的分數,在累加,就可以實現。
六、原始碼(使用的軟體Code Block,在GCC編譯器編譯通過)
#include <iostream>#include<cstdio>#include<cstdlib>#include<map>using namespace std;int main(){ int game_num; map<string,double>mp; int i,n; double num,sum,ave; int G,temp=0; string name; printf("請輸入遊戲的人數:"); scanf("%d",&n); printf("\n"); printf("請輸入此次遊戲進行的輪數:"); scanf("%d",&game_num); printf("\n"); while(game_num--) { ++temp; mp.clear(); //清空map中的資料 sum=0;ave=0;G=0; printf("第%d輪開始:\n",temp); printf("請輸入每人的姓名和有理數(空格隔開):\n"); for(i=0;i<n;i++) { cin>>name>>num; if(num>0.0&&num<100.0) { mp[name]=num; //建立map的關係 sum=sum+num; } else { printf("請輸入(0-100)的有理數\n"); i--; } } map<string,double>::iterator iter,result_high,result_low; printf("總和為:%.4lf\n",sum); ave=sum/n; printf("平均值:%.4lf\n",ave); G=ave*0.618; printf("G點值:%.4lf\n",G); for(iter=mp.begin();iter!=mp.end();iter++) { iter->second =(int)abs(G-(int)iter->second); //iter存的是差值 } for(iter=mp.begin(),result_high=mp.begin(),result_low=mp.begin();iter!=mp.end();iter++) { if(iter->second<result_high->second) result_high=iter; if(iter->second>result_low->second) result_low=iter; } cout<<endl; cout<<"姓名"<<"\t"<<"差值"<<endl; cout<<result_high->first<<"\t"<<result_high->second<<"\t"<<"得到"<<n<<"分"<<endl; cout<<result_low->first<<"\t"<<result_low->second<<"\t"<<"得到-2分"<<endl; cout<<endl; for(iter=mp.begin();iter!=mp.end();iter++) { iter->second =0; } for(iter=mp.begin();iter!=mp.end();iter++) { if(iter==result_high) iter->second+=n; if(iter==result_low) iter->second+=-2; } cout<<"第"<<temp<<"輪結果:"<<endl; cout<<"姓名"<<"\t"<<"分數"<<endl; for(iter=mp.begin();iter!=mp.end();iter++) cout<<iter->first<<"\t"<<iter->second<<endl; cout<<endl; } return 0;}
如果文中存在錯誤,請幫忙指出,大家可以一起討論,共同提高。
資料
軟體工程-構建之法 黃金點小遊戲