劣质代码评析——《写给大家看的C语言书(第2版)》》附录B之21点程序(七)
0. #include <stdio.h>
1. #include <time.h>
2. #include <ctype.h>
3. #include <stdlib.h>
4.
5. #define BELL '\a'
6. #define DEALER 0
7. #define PLAYER 1
8.
9. #define ACELOW 0
10. #define ACEHIGH 1
11.
12. int askedForName = 0;
13.
14. void dispTitle(void);
15. void initCardsScreen(int cards[52],int playerPoints[2],
16. int dealerPoints[2], int total[2],
17. int *numCards);
18. int dealCard(int * numCards,int cards[52]);
19. void dispCard(int cardDrawn,int points[2]);
20. void totalIt(int points[2],int tatal[2],int who);
21. void dealerGetsCard(int *numCards,int cards[52],
22. int dealerPoints[2]);
23. void playerGetsCard(int *numCards,int cards[52],
24. int playerPoints[2]);
25. char getAns(char mesg[]);
26. void findWinner(int total[2]);
27.
28. main()
29. {
30. int numCards;
31. int cards[52],playerPoints[2],dealerPoints[2],total[2];
32. char ans;
33.
34. do
35. {
36. initCardsScreen(cards,playerPoints,dealerPoints,total, &numCards);
37. dealerGetsCard(&numCards,cards, dealerPoints);
38. printf("\n");
39. playerGetsCard(&numCards,cards,playerPoints);
40. playerGetsCard(&numCards,cards,playerPoints);
41. do
42. {
43. ans = getAns("Hit or stand (H/S)?");
44. if ( ans == 'H' )
45. {
46. playerGetsCard(&numCards,cards,playerPoints);
47. }
48. }
49. while( ans != 'S' );
50.
51. totalIt(playerPoints,total,PLAYER);
52. do
53. {
54. dealerGetsCard(&numCards,cards,dealerPoints);
55. }
56. while (dealerPoints[ACEHIGH] < 17 );
57.
58. totalIt(dealerPoints,total,DEALER);
59. findWinner(total);
60.
61. ans = getAns("\nPlay again(Y/N)?");
62. }
63. while(ans=='Y');
64.
65. return ;
66.
67. }
68.
69. void initCardsScreen( int cards[52],int playerPoints[2],
70. int dealerPoints[2], int total[2],
71. int *numCards )
72. {
73. int sub,val = 1 ;
74. char firstName[15];
75. *numCards=52;
76.
77. for(sub=0;sub<=51;sub++)
78. {
79. val = (val == 14) ? 1 : val;
80. cards[sub] = val;
81. val++;
82. }
83.
84. for(sub=0;sub<=1;sub++)
85. {
86. playerPoints[sub]=dealerPoints[sub]=total[sub]=0;
87. }
88. dispTitle();
89.
90. if (askedForName==0)
91. {
92. printf("What is your first name?");
93. scanf(" %s",firstName);
94. askedForName=1;
95. printf("Ok, %s,get ready for casino action!\n\n",firstName);
96. getchar();
97. }
98. return;
99. }
100.
101. void playerGetsCard(int *numCards,int cards[52],int playerPoints[2])
102. {
103. int newCard;
104. newCard = dealCard(numCards, cards);
105. printf("You draw:");
106. dispCard(newCard,playerPoints);
107. }
108.
109.
110. void dealerGetsCard(int *numCards,int cards[52],int dealerPoints[2])
111. {
112. int newCard;
113. newCard = dealCard(numCards,cards);
114. printf("The dealer draws:");
115. dispCard(newCard,dealerPoints);
116. }
117.
118. int dealCard(int * numCards,int cards[52])
119. {
120. int cardDrawn,subDraw;
121. time_t t;
122. srand(time(&t));
123. subDraw = (rand()%(*numCards));
124. cardDrawn = cards[subDraw];
125. cards[subDraw] = cards[*numCards -1];
126. (*numCards)-;
127. return cardDrawn;
128. }
129.
130. void dispCard(int cardDrawn, int points[2])
131. {
132. switch(cardDrawn)
133. {
134. case(11): printf("%s\n","Jack");
135. points[ACELOW] += 10;
136. points[ACEHIGH] += 10;
137. break;
138. case(12): printf("%s\n","Queen");
139. points[ACELOW] += 10;
140. points[ACEHIGH] += 10;
141. break;
142. case(13): printf("%s\n","King");
143. points[ACELOW] += 10;
144. points[ACEHIGH] += 10;
145. break;
146. default : points[ACELOW] += cardDrawn;
147. if(cardDrawn==1)
148. {
149. printf("%s\n","Ace");
150. points[ACEHIGH]+= 11;
151. }
152. else
153. {
154. points[ACEHIGH]+=cardDrawn;
155. printf("%d\n",cardDrawn);
156. }
157. }
158. return ;
159. }
160.
161. void totalIt(int points[2],int total[2],int who)
162. {
163. if ( (points[ACELOW] == points[ACEHIGH])
164. ||(points[ACEHIGH] > 21 ))
165. {
166. total[who] = points[ACELOW];
167. }
168. else
169. {
170. total[who] = points[ACEHIGH];
171. }
172.
173. if (who == PLAYER )
174. {
175. printf("You have a total of %d\n\n", total[PLAYER]);
176. }
177. else
178. {
179. printf("The house stands with a total of %d\n\n",
180. total[DEALER]);
181. }
182. return;
183. }
184.
185. void findWinner(int total[2])
186. {
187. if ( total[DEALER] == 21 )
188. {
189. printf("The house wins.\n");
190. return ;
191. }
192. if ( (total[DEALER] > 21) && (total[PLAYER] > 21) )
193. {
194. printf("%s", "Nobody wins.\n");
195. return ;
196. }
197. if ((total[DEALER] >= total[PLAYER])&& (total[DEALER] < 21))
198. {
199. printf("The house wins.\n");
200. return ;
201. }
202. if ((total[PLAYER] > 21)&& (total[DEALER] < 21))
203. {
204. printf("The house wins.\n");
205. return ;
206. }
207. printf("%s%c","You win!\n",BELL);
208. return;
209. }
210.
211. char getAns(char mesg[])
212. {
213. char ans;
214. printf("%s", mesg);
215. ans = getchar();
216. getchar();
217. return toupper(ans);
218. }
219.
220. void dispTitle(void)
221. {
222. int i = 0 ;
223. while(i<25)
224. {
225. printf("\n");
226. i++;
227. }
228. printf("\n\n*Step right up to the Blackjack tables*\n\n");
229. return ;
230. }
庄家抽牌结束后,就到了宣布胜负的时候。
26. void findWinner(int total[2]);
185. void findWinner(int total[2])
186. {
187. if ( total[DEALER] == 21 )
188. {
189. printf("The house wins.\n");
190. return ;
191. }
192. if ( (total[DEALER] > 21) && (total[PLAYER] > 21) )
193. {
194. printf("%s", "Nobody wins.\n");
195. return ;
196. }
197. if ((total[DEALER] >= total[PLAYER])&& (total[DEALER] < 21))
198. {
199. printf("The house wins.\n");
200. return ;
201. }
202. if ((total[PLAYER] > 21)&& (total[DEALER] < 21))
203. {
204. printf("The house wins.\n");
205. return ;
206. }
207. printf("%s%c","You win!\n",BELL);
208. return;
209. }
这个函数写得比较乱,缺乏条理。改成下面的写法更清晰:
void findWinner(int total[]); void findWinner(int total[]) { if ( total[DEALER] == 21 ) { printf("The house wins.\n"); return ; } if ( total[DEALER] > 21 ) { if( total[PLAYER] > 21 ) { printf("%s", "Nobody wins.\n"); return ; } } if ( total[DEALER] < 21 ) { if( (total[PLAYER] > 21) ) { printf("The house wins.\n"); return ; } if( (total[DEALER] >= total[PLAYER]) ) { printf("The house wins.\n"); return ; } } printf("%s%c","You win!\n",BELL); return; }
【重构】
从程序总体来看,无非是一个反复进行21点游戏的过程。
/* 21点游戏:对《写给大家看的C语言书》附录B之21点程序的重构 */ #include <stdio.h> typedef enum { NO , YES, } YESNO ; YESNO again( void ); void game_21( void ); int main( void ) { do{ game_21(); //一轮游戏 }while ( again() == YES ); return 0; } void game_21( void ) { //待完成 } YESNO again( void ) { int c; puts("继续游戏(Y/N)?"); c = getchar() ; while ( getchar() != '\n'){ //读完一行 } if ( c=='y' || c == 'Y' ){ return YES; } return NO; }
main()的含义很清晰,应该不用解释。这就是结构化程序设计所谓的“自顶向下”的魅力。
(未完待续)