zoukankan      html  css  js  c++  java
  • 劣质代码评析——《写给大家看的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. 
    15. void dispTitle(void);
    16. void initCardsScreen(int cards[52],int playerPoints[2],
    17. int dealerPoints[2], int total[2], 
    18. int *numCards);
    19. int dealCard(int * numCards,int cards[52]);
    20. void dispCard(int cardDrawn,int points[2]);
    21. void totalIt(int points[2],int tatal[2],int who);
    22. void dealerGetsCard(int *numCards,int cards[52],
    23. int dealerPoints[2]);
    24. void playerGetsCard(int *numCards,int cards[52],
    25. int playerPoints[2]);
    26. char getAns(char mesg[]);
    27. void findWinner(int total[2]);
    28. 
    29. main()
    30. {
    31.    int numCards;
    32.    int cards[52],playerPoints[2],dealerPoints[2],total[2];
    33.    char ans;
    34.    
    35.    do 
    36.    { 
    37.       initCardsScreen(cards,playerPoints,dealerPoints,total, &numCards);
    38.       dealerGetsCard(&numCards,cards, dealerPoints);
    39.       printf("
    ");
    40.       playerGetsCard(&numCards,cards,playerPoints); 
    41.       playerGetsCard(&numCards,cards,playerPoints);
    42.       do
    43.       {
    44.          ans = getAns("Hit or stand (H/S)?");
    45.          if ( ans == 'H' )
    46.          { 
    47.             playerGetsCard(&numCards,cards,playerPoints);
    48.          }  
    49.       }
    50.       while( ans != 'S' );
    51.       
    52.       totalIt(playerPoints,total,PLAYER);
    53.       do
    54.       {
    55.          dealerGetsCard(&numCards,cards,dealerPoints);
    56.       }
    57.       while (dealerPoints[ACEHIGH] < 17 );
    58.       
    59.       totalIt(dealerPoints,total,DEALER);
    60.       findWinner(total); 
    61.       
    62.       ans = getAns("
    Play again(Y/N)?");  
    63.    }
    64.    while(ans=='Y');
    65.    
    66.    return 0;
    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!
    
    ",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
    ","Jack");
    135.                 points[ACELOW] += 10;
    136.                 points[ACEHIGH] += 10;
    137.                 break;
    138.       case(12): printf("%s
    ","Queen");
    139.                 points[ACELOW] += 10;
    140.                 points[ACEHIGH] += 10;
    141.                 break;
    142.       case(13): printf("%s
    ","King");
    143.                 points[ACELOW] += 10;
    144.                 points[ACEHIGH] += 10;
    145.                 break;
    146.       default : points[ACELOW] += cardDrawn;
    147.                 if(cardDrawn==1)
    148.                 { 
    149.                    printf("%s
    ","Ace");
    150.                    points[ACEHIGH]+= 11;
    151.                 }
    152.                 else
    153.                 {  
    154.                   points[ACEHIGH]+=cardDrawn;
    155.                   printf("%d
    ",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
    
    ", total[PLAYER]);
    176.    }
    177.    else
    178.    {
    179.        printf("The house stands with a total of %d
    
    ", 
    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.
    ");
    190.        return ;
    191.    }
    192.    if ( (total[DEALER] > 21) && (total[PLAYER] > 21) )
    193.    { 
    194.       printf("%s", "Nobody wins.
    ");
    195.       return ; 
    196.    }
    197.    if ((total[DEALER] >= total[PLAYER])&& (total[DEALER] < 21))
    198.    { 
    199.       printf("The house wins.
    ");
    200.       return ; 
    201.    }
    202.    printf("%s%c","You win!
    ",BELL);
    203.    return;
    204. }
    205. 
    206. char getAns(char mesg[])
    207. {
    208.    char ans;
    209.    printf("%s", mesg);
    210.    ans = getchar();
    211.    getchar();
    212.    return toupper(ans);
    213. }
    214. 
    215. void dispTitle(void)
    216. {
    217.    int i = 0 ;
    218.    while(i<25)
    219.    { 
    220.         printf("
    ");
    221.         i++; 
    222.    }
    223.    printf("
    
    *Step right up to the Blackjack tables*
    
    ");
    224.    return ;
    225. }
    View Code
    29. main()
    30. {
    31.    int numCards;
    32.    int cards[52],playerPoints[2],dealerPoints[2],total[2];
    33.    char ans;
    34.    
    35.    do 
    36.    { 
    37.       initCardsScreen(cards,playerPoints,dealerPoints,total, &numCards);
    38.       dealerGetsCard(&numCards,cards, dealerPoints);
    39.       printf("
    ");
    40.       playerGetsCard(&numCards,cards,playerPoints); 
    41.       playerGetsCard(&numCards,cards,playerPoints);
    42.       do
    43.       {
    44.          ans = getAns("Hit or stand (H/S)?");
    45.          if ( ans == 'H' )
    46.          { 
    47.             playerGetsCard(&numCards,cards,playerPoints);
    48.          }  
    49.       }
    50.       while( ans != 'S' );
    51.       
    52.       totalIt(playerPoints,total,PLAYER);
    53.       do
    54.       {
    55.          dealerGetsCard(&numCards,cards,dealerPoints);
    56.       }
    57.       while (dealerPoints[ACEHIGH] < 17 );
    58.       
    59.       totalIt(dealerPoints,total,DEALER);
    60.       findWinner(total); 
    61.       
    62.       ans = getAns("
    Play again(Y/N)?");  
    63.    }
    64.    while(ans=='Y');
    65.    
    66.    return 0;
    67. }

      现在回到main()继续代码走查。

       38.       dealerGetsCard(&numCards,cards, dealerPoints);

       这句话的意图是实现计算机(作为dealer)抽一张牌,并且这张牌的点数两个游戏者能看得见。其函数类型声明为: 

        22. void dealerGetsCard(int *numCards,int cards[52],
        23. int dealerPoints[2]);

       这个函数类型声明写得同样很不地道,原因前面提到过,这里不再复述。应该把它改为: 

        void dealerGetsCard ( int *numCards , int cards[] , int dealerPoints[] );
    

      该函数的函数定义为: 

        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. }

       有不少初学者不定义几个根本没必要的变量就不会写代码,这个函数犯的也是这种幼稚病。

      newCard这个变量明显多余。此外函数的头部也需要修改。形参numCards名字的毛病这里暂时就不改了: 

        void dealerGetsCard(int *numCards,int cards[],int dealerPoints[])
        {
           printf("The dealer draws:");
           dispCard ( dealCard( numCards , cards ) , dealerPoints ) ;
        }

       这里又涉及到了dealCard()函数和dispCard(),先来看dealCard()函数。

        19. int dealCard(int * numCards,int cards[52]);
        
        
        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));    /* From 0 to numcards */
        124.    cardDrawn = cards[subDraw];
        125.    cards[subDraw] = cards[*numCards -1];
        126.    (*numCards)--;
        127.    return cardDrawn;
        128. }

       函数原型方面的问题这里就不再提了。

      这个函数中有这样两层意思,首先在剩下的牌(共* numcards 张)中随机确定一张牌(第subDraw张),然后再模拟把这张牌从整副牌中抽走(cards[subDraw] = cards[*numCards -1]; (*numCards)--;)。

      这个函数有这样一些错误和毛病: 

        121.    time_t t;

       这个变量定义是毫无意义的,后面进一步说明。 

        122.    srand(time(&t));

       此函数调用的目的是设置伪随机数的种子(Seed),其中有两个错误:

      第一,&t作为实参是毫无必要的。因为这里只需要time()函数的返回值,而不需要通过变量t保存并带回时间的值。这时的代码应该这样写

        srand( time ( NULL ) );

      第二个错误是,需要得到伪随机数列时,只需要在最初设置一次种子,而不是反复设置种子。也就是说这个srand()只需要在每次游戏的初期调用一次,以后则毋庸再调用。那么,很显然,这个函数调用绝对不应该出现在dealCard()这个函数中,而应该出现在main()函数的do-while语句之中,如下面所示。 

        int main(void)
        {
           /*……*/
        
           do{
                srand( time ( NULL ) );
                /*21点游戏*/
            }
           while( getAns("
    Play again(Y/N)?") == 'Y' );  /*询问是否继续*/
        
            return 0;
        }
    

      dealCard()函数中的 

       123.    subDraw = ( rand() % (*numCards) );    /* From 0 to numcards */

       代码本身没有问题,但注释是错误的。作者忘记了numcards在这个函数中是一个指针,而且rand() % (*numCards) 所能得到的值只可能在 0 ~ (*numCards)-1 这个范围。

      这个函数的返回值即为抽到的牌的点数,这个点数作为实参调用dispCard ()函数。即

        dispCard ( dealCard( numCards , cards ) , dealerPoints ) ;
        //原115.    dispCard(newCard,dealerPoints);
    
    

    (未完待续)

  • 相关阅读:
    mysql免安装版配置+navicat测试
    查询SQL Version详细信息
    拆分数据库测试之--收缩数据库
    测试拆分比较大SQL Server数据库
    SQL捕捉blocking信息
    T-SQL 重复读(Double Read)问题的理解
    Node.js版-七夕无事,人艰勿拆,求别说...
    css实现三角箭头(兼容IE6)
    前端开发的基础知识点摘要
    jQuery原理系列-常用Dom操作
  • 原文地址:https://www.cnblogs.com/pmer/p/3181078.html
Copyright © 2011-2022 走看看