1、C/C+語言經(jīng)典、實(shí)用、趣味程序設(shè)計(jì)編程百例精解(18)86.自動(dòng)發(fā)牌一副撲克有52張牌,打橋牌時(shí)應(yīng)將牌分給四個(gè)人。請(qǐng)?jiān)O(shè)計(jì)一個(gè)程序完成自動(dòng)發(fā)牌的工作。要求:黑桃用S(Spaces)表示;紅桃用H(Hearts)表示;方塊用D(Diamonds)表示;梅花用C(Clubs)表示。*問題分析與算法設(shè)計(jì)按照打橋牌的規(guī)定,每人應(yīng)當(dāng)有13張牌。在人工發(fā)牌時(shí),先進(jìn)行洗牌,然后將洗好的牌按一定的順序發(fā)給每一個(gè)人。為了便于計(jì)算機(jī)模擬,可將人工方式的發(fā)牌過程加以修改:先確定好發(fā)牌順序:1、2、3、4;將52張牌順序編號(hào):黑桃2對(duì)應(yīng)數(shù)字0,紅桃2對(duì)應(yīng)數(shù)字1,方塊2對(duì)應(yīng)數(shù)字2,梅花2對(duì)應(yīng)數(shù)字3,黑桃3對(duì)應(yīng)數(shù)字4,紅
2、桃3對(duì)應(yīng)數(shù)字5,然后從52 張牌中隨機(jī)的為每個(gè)人抽牌。這里采用C語言庫(kù)函數(shù)的隨機(jī)函數(shù),生成0到51之間的共52個(gè)隨機(jī)數(shù),以產(chǎn)生洗牌后發(fā)牌的效果。*程序與程序注釋 #include<stdlib.h>#include<stdio.h>int comp(const void *j,const void *i);void p(int b,char n);int main(void)static char n='2','3','4','5','6','7','8',&
3、#39;9','T','J','Q','K','A'int a53,b113,b213,b313,b413;int b11=0,b22=0,b33=0,b44=0,t=1,m,flag,i;while(t<=52) /*控制發(fā)52張牌*/m=rand()%52; /*產(chǎn)生0到51之間的隨機(jī)數(shù)*/for(flag=1,i=1;i<=t&&flag;i+)/*查找新產(chǎn)生的隨機(jī)數(shù)是否已經(jīng)存在*/if(m=ai) flag=0; /*flag=1:產(chǎn)生的是新的隨機(jī)數(shù)flag=0:新產(chǎn)生的
4、隨機(jī)數(shù)已經(jīng)存在*/if(flag)at+=m; /*如果產(chǎn)生了新的隨機(jī)數(shù),則存入數(shù)組*/if(t%4=0) b1b11+=at-1; /*根據(jù)t的模值,判斷當(dāng)前*/else if(t%4=1) b2b22+=at-1; /*的牌應(yīng)存入哪個(gè)數(shù)組中*/else if(t%4=2) b3b33+=at-1;else if(t%4=3) b4b44+=at-1;qsort(b1,13,sizeof(int),comp); /*將每個(gè)人的牌進(jìn)行排序*/qsort(b2,13,sizeof(int),comp);qsort(b3,13,sizeof(int),comp);qsort(b4,13,sizeo
5、f(int),comp);p(b1,n); p(b2,n); p(b3,n); p(b4,n); /*分別打印每個(gè)人的牌*/return 0;void p(int b,char n)int i;printf("n006 "); /*打印黑桃標(biāo)記*/for(i=0;i<13;i+) /*將數(shù)組中的值轉(zhuǎn)換為相應(yīng)的花色*/if(bi/13=0) printf("%c ",nbi%13); /*該花色對(duì)應(yīng)的牌*/printf("n003 "); /*打印紅桃標(biāo)記*/for(i=0;i<13;i+)if(bi/13)=1) prin
6、tf("%c ",nbi%13);printf("n004 "); /*打印方塊標(biāo)記*/for(i=0;i<13;i+)if(bi/13=2) printf("%c ",nbi%13);printf("n005 "); /*打印梅花標(biāo)記*/for(i=0;i<13;i+)if(bi/13=3|bi/13=4) printf("%c ",nbi%13);printf("n");int comp(const void *j,const void *i) /*qsort
7、調(diào)用的排序函數(shù)*/return(*(int*)i-*(int*)j);87.黑白子交換有三個(gè)白子和三個(gè)黑子如下圖布置: . 游戲的目的是用最少的步數(shù)將上圖中白子和黑子的位置進(jìn)行交換: . 游戲的規(guī)則是:(1)一次只能移動(dòng)一個(gè)棋子; (2)棋子可以向空格中移動(dòng),也可以跳過一個(gè)對(duì)方的棋子進(jìn)入空格,但不能向后跳,也不能跳過兩個(gè)子。請(qǐng)用計(jì)算機(jī)實(shí)現(xiàn)上述游戲。*問題分析與算法設(shè)計(jì)計(jì)算機(jī)解決勝這類問題的關(guān)鍵是要找出問題的規(guī)律,或者說是要制定一套計(jì)算機(jī)行動(dòng)的規(guī)則。分析本題,先用人來解決問題,可總結(jié)出以下規(guī)則:(1) 黑子向左跳過白子落入空格,轉(zhuǎn)(5)(2) 白子向右跳過黑子落入空格,轉(zhuǎn)(5)(3) 黑子向左移
8、動(dòng)一格落入空格(但不應(yīng)產(chǎn)生棋子阻塞現(xiàn)象),轉(zhuǎn)(5)(4) 白子向右移動(dòng)一格落入空格(但不應(yīng)產(chǎn)生棋子阻塞現(xiàn)萌),轉(zhuǎn)(5)(5) 判斷游戲是否結(jié)束,若沒有結(jié)束,則轉(zhuǎn)(1)繼續(xù)。所謂的“阻塞”現(xiàn)象就是:在移動(dòng)棋子的過程中,兩個(gè)尚未到位的同色棋子連接在一起,使棋盤中的其它棋子無法繼續(xù)移動(dòng)。例如按下列方法移動(dòng)棋子:0 . 1 . 2 . 3 . 4 兩個(gè)連在一起產(chǎn)生阻塞 . 或4 兩個(gè)白連在一起產(chǎn)生阻塞 . 產(chǎn)生阻塞的現(xiàn)象的原因是在第2步(狀態(tài))時(shí),棋子不能向右移動(dòng),只能將向左移動(dòng)??偨Y(jié)產(chǎn)生阻塞的原因,當(dāng)棋盤出現(xiàn)“黑、白、空、黑”或“白、空、黑、白”狀態(tài)時(shí),不能向左或向右移動(dòng)中間的棋子,只移動(dòng)兩邊的棋子
9、。按照上述規(guī)則,可以保證在移動(dòng)棋子的過程中,不會(huì)出現(xiàn)棋子無法移動(dòng)的現(xiàn)象,且可以用最少的步數(shù)完成白子和黑子的位置交換。*程序說明與注釋#include<stdio.h>int number;void print(int a);void change(int *n,int *m);int main()int t7=1,1,1,0,2,2,2; /*初始化數(shù)組1:白子 2:黑子 0:空格*/int i,flag;print(t);while(t0+t1+t2!=6|t4+t5+t6!=3) /*判斷游戲是否結(jié)束若還沒有完成棋子的交換則繼續(xù)進(jìn)行循環(huán)*/flag=1; /*flag 為棋子移
10、動(dòng)一步的標(biāo)記1:尚未移動(dòng)棋子 0:已經(jīng)移動(dòng)棋子*/for(i=0;flag&&i<5;i+) /*若白子可以向右跳過黑子,則白子向右跳*/if(ti=1&&ti+1=2&&ti+2=0)change(&ti,&ti+2); print(t); flag=0;for(i=0;flag&&i<5;i+) /*若黑子可以向左跳過白子,則黑子向左跳*/if(ti=0&&ti+1=1&&ti+2=2)change(&ti,&ti+2); print(t); flag
11、=0;for(i=0;flag&&i<6;i+) /*若向右移動(dòng)白子不會(huì)產(chǎn)生阻塞,則白子向右移動(dòng)*/if(ti=1&&ti+1=0&&(i=0|ti-1!=ti+2)change(&ti,&ti+1); print(t);flag=0;for(i=0;flag&&i<6;i+) /*若向左移動(dòng)黑子不會(huì)產(chǎn)生阻塞,則黑子向左移動(dòng)*/if(ti=0&&ti+1=2&&(i=5|ti-1!=ti+2) change(&ti,&ti+1); print(t);fla
12、g=0;void print(int a)int i;printf("No. %2d:.n",number+);printf(" ");for(i=0;i<=6;i+)printf(" | %c",ai=1?'*':(ai=2?'':' ');printf(" |n .nn");void change(int *n,int *m)int term;term=*n; *n=*m; *m=term;*問題的進(jìn)一步討論本題中的規(guī)則不僅適用于三個(gè)棋子的情況,而且可以推而
13、廣之,適用于任意N個(gè)棋子的情況。讀者可以編程驗(yàn)證,按照本規(guī)則得到的棋子移動(dòng)步數(shù)是最少的。事實(shí)上,制定規(guī)則是解決這類問題的關(guān)鍵。一個(gè)游戲程序“思考水平的高低,完全取決于使用規(guī)則的好壞?!?思考題有兩個(gè)白子和兩個(gè)黑子如下左圖布置: . . . . . 棋盤中的棋子按”馬步“規(guī)則行走,要求用最少的步數(shù)將圖中白子和黑子的位置進(jìn)行交換,最終結(jié)果如下一幅圖所示。 . . . . . 88.常勝將軍現(xiàn)有21根火柴,兩人輪流取,每人每次可以取走1至4根,不可多取,也不能不取,誰取最后一楰火柴誰輸。請(qǐng)編寫一個(gè)程序進(jìn)行人機(jī)對(duì)弈,要求人先取,計(jì)算機(jī)后取;計(jì)算機(jī)一方為“常勝將軍”。*問題分析與算法設(shè)計(jì)在計(jì)算機(jī)后走的情
14、況下,要想使計(jì)算機(jī)成為“常勝將軍”,必須找出取 關(guān)鍵。根據(jù)本題的要求枷以總結(jié)出,后走一方取子的數(shù)量與對(duì)方剛才一步取子的數(shù)量之和等于,就可以保證最后一個(gè)子是留給先取子的那個(gè)人的。據(jù)此分析進(jìn)行算法設(shè)計(jì)就是很簡(jiǎn)單的工作,編程實(shí)現(xiàn)也十分容易。*程序說明與注釋#include<stdio.h>int main()int a=21,i;printf("Game begin:n");while(a>0)doprintf("How many stick do you wish to take(1%d)?",a>4?4:a);scanf("
15、;%d",&i);while(i>4|i<1|i>a); /*接收正在確的輸入*/if(a-i>0) printf(" %d stick left in the pile.n",a-i);if(a-i)<=0)printf(" You have taken the last stick.n");printf(" * * * You lose! nGame Over.n"); /*輸出取勝標(biāo)記*/break;elseprintf(" Compute take %d stick.n
16、",5-i); /*輸出計(jì)算機(jī)取的子數(shù)*/a-=5;printf(" %d stick left in the pile.n",a);*思考題改變題目中火柴的數(shù)量(如為22根),則后走的一方就不一定能夠保持常勝了,很可能改變成“常敗”。此時(shí)后走一方的勝負(fù)就與火柴的初始數(shù)量和每次允許取的火柴數(shù)量的最大值有直接關(guān)系,請(qǐng)編寫程序解決這一問題。 89.搶30這是中國(guó)民間的一個(gè)游戲。兩人從1開始輪流報(bào)數(shù),每人每次可報(bào)一個(gè)數(shù)或兩個(gè)連續(xù)的數(shù),誰先報(bào)到30,誰就為勝方。*問題分析與算法設(shè)計(jì)本題與上題類似,算法也類似,所不同的是,本誰先走第一步是可選的。若計(jì)算機(jī)走第一步,那么計(jì)算機(jī)
17、一定是贏家。若人先走一步,那么計(jì)算機(jī)只好等待人犯錯(cuò)誤,如果人先走第一步且不犯錯(cuò)誤,那么人就會(huì)取勝;否則計(jì)算機(jī)會(huì)抓住人的一次錯(cuò)誤使自己成為勝利者。*程序說明與注釋#include<stdio.h>#include<time.h>#include<stdlib.h>int input(int t);int copu(int s);int main()int tol=0;printf("n* * * * * * * *catch thirty* * * * * * * n");printf("Game Beginn");ra
18、ndomize(); /*初始化隨機(jī)數(shù)發(fā)生器*/if(random(2)=1) /*取隨機(jī)數(shù)決定機(jī)器和人誰先走第一步*/tol=input(tol); /*若為1,則余元走第一步*/while(tol!=30) /*游戲結(jié)束條件*/if(tol=copu(tol)=30) /*計(jì)算機(jī)取一個(gè)數(shù),若為30則機(jī)器勝利*/printf("I lose! n");elseif(tol=input(tol)=30) /*人取一個(gè)數(shù),若為30則人勝利*/printf("I lose! n");printf(" * * * * * * * *Game Over
19、 * * * * * * * *n");int input(int t)int a;doprintf("Please count:");scanf("%d",&a);if(a>2|a<1|t+a>30)printf("Error input,again!");elseprintf("You count:%dn",t+a);while(a>2|a<1|t+a>30);return t+a; /*返回當(dāng)前的已經(jīng)取走的數(shù)累加和*/int copu(int s)int
20、c;printf("Computer count:");if(s+1)%3=0) /*若剩余的數(shù)的模為1,則取1*/printf(" %dn",+s);else if(s+2)%3=0)s+=2; /*若剩余的數(shù)的模為2,則取2*/printf(" %dn",s);elsec=random(2)+1; /*否則隨機(jī)取1或2*/s+=c;printf(" %dn",s);return s;*思考題巧奪偶數(shù)。桌子上有25顆棋子,游戲雙方輪流取子,每人每次最少取走一顆棋子,最多可取走3顆棋子。雙方照這樣取下去,直到取光所
21、有的棋子。于是雙方手中必然一方為偶數(shù),一方為奇數(shù),偶數(shù)方為勝者。請(qǐng)編程實(shí)現(xiàn)人機(jī)游戲。90.搬山游戲設(shè)有n座山,計(jì)算機(jī)與人為比賽的雙方,輪流搬山。規(guī)定每次搬山的數(shù)止不能超 過k座,誰搬最后一座誰輸。游戲開始時(shí)。計(jì)算機(jī)請(qǐng)人輸入山的總數(shù)(n)和每次允許搬山的最大數(shù)止(k)。然后請(qǐng)人開始,等人輸入了需要搬走的山的數(shù)目后,計(jì)算機(jī)馬上打印出它搬多少座山,并提示尚余多少座山。雙方輪流搬山直到最后一座山搬完為止。計(jì)算機(jī)會(huì)顯示誰是贏家,并問人是否要繼續(xù)比賽。若人不想玩了,計(jì)算機(jī)便會(huì)統(tǒng)計(jì)出共玩了幾局,雙方勝負(fù)如何。*問題分析與算法設(shè)計(jì)計(jì)算機(jī)參加游戲時(shí)應(yīng)遵循下列原則:1) 當(dāng):剩余山數(shù)目-1<=可移動(dòng)的最大數(shù)
22、k 時(shí)計(jì)算機(jī)要移(剩余山數(shù)目-1)座,以便將最后一座山留給人。2)對(duì)于任意正整數(shù)x,y,一定有:0<=x%(y+1)<=y在有n座山的情況下,計(jì)算機(jī)為了將最后一座山留給人,而且又要控制每次搬山的數(shù)目不超過最大數(shù)k,它應(yīng)搬山的數(shù)目要滿足下列關(guān)系:(n-1)%(k+1)如果算出結(jié)果為0,即整除無余數(shù),則規(guī)定只搬1座山,以防止冒進(jìn)后發(fā)生問題。按照這樣的規(guī)律,可編寫出游戲程序如下:#include<stdio.h>int main()int n,k,x,y,cc,pc,g;printf("More Mountain Gamen");printf("
23、Game Beginn");pc=cc=0;g=1;for(;)printf("No.%2d game n",g+);printf("n");printf("How many mpuntains are there?");scanf("%d",&n);if(!n) break;printf("How many mountains are allowed to each time?");doscanf("%d",&k);if(k>n|k<1) printf("Repeat again!n");while(k>n|k<1);doprintf("How many mountains do you wish movw away?&qu
評(píng)論
0/150
提交評(píng)論