home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1989 / 07 / stevens.lst < prev    next >
File List  |  1989-06-01  |  15KB  |  594 lines

  1. _C PROGRAMMING COLUMN_
  2. by Al Stevens
  3.  
  4. [LISTING ONE]
  5.  
  6.  
  7. /* ------------- bj.c ---------------- */
  8. /*
  9.  * A Blackjack Simulation
  10.  */
  11. #include <conio.h>
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <ctype.h>
  15. #include <time.h>
  16.  
  17. #define TRUE 1
  18. #define FALSE 0
  19. #define IBMPC
  20.  
  21. /* ------- ANSI.SYS screen controls --------- */
  22. #define clr_scrn() puts("\033[2J")
  23. #define cursor(x,y) printf("\033[%02d;%02dH",y+1,x+1)
  24.  
  25. /* --------- for display purposes ------------- */
  26. #define CARDWIDTH 5
  27. #define CARDHEIGHT 4
  28. #define PLAYERS 7     /* number of players (not incl dealer) */
  29. #define DECKS   6     /* number of decks to play             */
  30. #define CARDS (52*DECKS)
  31.  
  32. /* -------- the card display characters -------- */
  33. #ifdef IBMPC
  34. #define UL 218        /* IBM Graphics upper left box corner  */
  35. #define HZ 196        /*              box horizontal line    */
  36. #define UR 191      /*              upper right box corner */
  37. #define VT 179      /*              box vertical line      */
  38. #define LL 192      /*              lower left box corner  */
  39. #define LR 217      /*              lower right box corner */
  40. #define HEARTS   3
  41. #define DIAMONDS 4
  42. #define CLUBS    5
  43. #define SPADES   6
  44. #else
  45. #define UL '.'        /*    ASCII     upper left box corner  */
  46. #define HZ '-'        /*              box horizontal line    */
  47. #define UR '.'      /*              upper right box corner */
  48. #define VT '|'      /*              box vertical line      */
  49. #define LL '\''     /*              lower left box corner  */
  50. #define LR '\''     /*              lower right box corner */
  51. #define HEARTS   'h'
  52. #define DIAMONDS 'd'
  53. #define CLUBS    'c'
  54. #define SPADES   's'
  55. #endif
  56.  
  57. /* --------- the card display values ---------- */
  58. char topline[] = {UL, HZ,  HZ,  HZ,  UR, 0};
  59. char midline[] = {VT, ' ', ' ', ' ', VT, 0};
  60. char botline[] = {LL, HZ,  HZ,  HZ,  LR, 0};
  61. int suits[] = {HEARTS,DIAMONDS,CLUBS,SPADES};
  62. char *vals[] = {"A","2","3","4","5","6","7","8","9","10",
  63.                 "J","Q","K"};
  64. /* --------- a card ----------- */
  65. typedef struct crd {
  66.     int value;
  67.     int suit;
  68. } CARD;
  69. /* ---------- a player -------- */
  70. typedef struct ply {
  71.     CARD phand[10];         /* the player's hand               */
  72.     int playing;         /* true if the player is playing */
  73.     int cards;             /* the card count in the hand    */
  74.     int bank;             /* player's bank account          */
  75.     int bet;             /* player's bet amount              */
  76.     int mode;             /* D = double-down                  */
  77.     int pushing;         /* true = player tied last hand  */
  78.     int (*strat)(int);     /* pointer to hit/pass strategy  */
  79. } PLAYER;
  80.  
  81. /* ----- 1 per player, 1 per split, 1 dealer ------ */
  82. #define NBRPLAYERS (PLAYERS*2+1) 
  83. int hands;
  84. #define dealer (NBRPLAYERS-1)
  85. PLAYER players [NBRPLAYERS+1];    /* the players  */
  86. CARD shoe[CARDS];                /* the shoe     */
  87. CARD discards[CARDS];            /* the discards */
  88. int nextshoe;        /* shoe subscript      */
  89. int inshoe;            /* # cards in the shoe */
  90. int nextdisc;        /* discard subscript   */
  91. int display=TRUE;    /* true if hands are being displayed   */
  92. int stopping=TRUE;    /* true if display stops at every hand */
  93. int stopper;        /* the key that restarts the display   */
  94.  
  95. /* ---------- prototypes ----------- */
  96. void shuffle(void);
  97. void bury(void);
  98. void hand(CARD *lst, int x, int y);
  99. void card(int sut, int val, int x, int y);
  100. void cardframe(int x, int y);
  101. void play(void);
  102. void playahand(void);
  103. int split(int p);
  104. void discs(void);
  105. int pstrategy(int p);
  106. void doubledown(int p);
  107. int bj_bust(int p);
  108. int dstrategy(int p);
  109. void winlose(int p);
  110. void won(int p);
  111. void lost(int p);
  112. void push(int p);
  113. void post(int p, char *s);
  114. void nextcard(CARD *cd);
  115. void shoes(void);
  116. void showhand(int pl);
  117. void cleargame(void);
  118. void nohand(CARD *lst, int x, int y);
  119. void nocardframe(int x, int y);
  120. int handvalue(int pl);
  121. void stat(int p, char *s);
  122.  
  123. void main(void)
  124. {
  125.     int i, s, v;
  126.     clr_scrn();
  127.     /* --- build the decks of cards in the discard pile --- */
  128.     for (i = 0; i < DECKS; i++)
  129.         for (s = 0; s < 4; s++)
  130.             for (v = 0; v < 13; v++)    {
  131.                 discards[nextdisc].value = v;
  132.                 discards[nextdisc++].suit = suits[s];
  133.             }
  134.     /* ----- initialize the players ----- */
  135.     for (i = 0; i < NBRPLAYERS-1; i++)    {
  136.         players[i].bet = 1;
  137.         players[i].strat = pstrategy;
  138.         /* --- every other player is a split --- */
  139.         players[i].playing = !(i & 1);
  140.     }
  141.     players[dealer].playing = TRUE;
  142.     play();
  143.     clr_scrn();
  144. }
  145. /* --------- begin play of the game --------- */
  146. void play(void)
  147. {
  148.     int c;
  149.     while (TRUE)    {
  150.         if (stopping || kbhit())    {
  151.             if (!stopping || NBRPLAYERS == 1)
  152.                 c = getch();
  153.             else    {
  154.                 c = stopper;
  155.                 stopper = FALSE;
  156.             }
  157.             if (c == 27)
  158.                 break;
  159.             if (tolower(c) == 'd')
  160.                 display ^= TRUE;
  161.             if (c == 's')
  162.                 stopping ^= TRUE;
  163.         }
  164.         playahand();
  165.     }
  166. }
  167. /* --------- play one hand of blackjack ------------- */
  168. void playahand(void)
  169. {
  170.     int p, i, bnk;
  171.     CARD *cd;
  172.     /* -------- deal everyone one card ----------- */
  173.     for (p = 0; p < NBRPLAYERS; p++)    {
  174.         if (players[p].playing == TRUE)    {
  175.             nextcard(players[p].phand);
  176.             players[p].cards++;
  177.             showhand(p);
  178.         }
  179.     }
  180.     /* ----- deal each of the players a second card ----- */
  181.     for (p = 0; p < dealer; p++)    {
  182.         if (players[p].playing == TRUE)    {
  183.             nextcard(players[p].phand+1);
  184.             players[p].cards++;
  185.             /* -- test to see if this player should split -- */
  186.             if (split(p))    {
  187.                 /* ----- split the hand ------- */
  188.                 players[p].cards = 1;
  189.                 players[p].phand[1].suit =
  190.                     players[p].phand[1].value = 0;
  191.                 bnk = players[p+1].bank;
  192.                 players[p+1] = players[p];
  193.                 players[p+1].bank = bnk;
  194.                 stat(p, "SPLT");
  195.             }
  196.             showhand(p);
  197.         }
  198.     }
  199.     /*  deal the rest of the hand for each player in turn  */
  200.     for (p = 0; p < NBRPLAYERS-1; p++)    {
  201.         if (players[p].playing == TRUE)    {
  202.             while (!bj_bust(p) && (*players[p].strat)(p))
  203.                nextcard(players[p].phand+(players[p].cards++));
  204.             showhand(p);
  205.         }
  206.     }
  207.     /* ------ see if all the players went bust ------- */
  208.     for (p = 0; p < NBRPLAYERS-1; p++)
  209.         if (players[p].playing == TRUE && handvalue(p) <= 21)
  210.             break;
  211.     /* ----- if so, the dealer doesn't have to play ---- */
  212.     if (p < NBRPLAYERS-1)    {
  213.         /* ------ deal the rest of the dealer's hand ------- */
  214.         while (!bj_bust(dealer) && dstrategy(dealer))
  215.             nextcard(players[dealer].phand+
  216.                 (players[dealer].cards++));
  217.         showhand(dealer);
  218.     }
  219.     /* ------ post players' wins and losses --------- */
  220.     for (p = 0; p < NBRPLAYERS-1; p++)    {
  221.         if (players[p].playing == TRUE)
  222.             winlose(p);
  223.         players[p].mode = FALSE;
  224.     }
  225.     post(dealer, "DEAL");
  226.     cursor(0, 1);
  227.     for (i = 0; i < NBRPLAYERS+1; i += 2)
  228.         printf("%5d     ", players[i].bank+players[i+1].bank);
  229.     /* -- gather the players' cards into the discard pile -- */
  230.     for (p = 0; p < NBRPLAYERS; p++)    {
  231.         cd = players[p].phand;
  232.         for (i = 0; i < players[p].cards; i++)
  233.             discards[nextdisc++] = *cd++;
  234.     }
  235.     /* ---- if display stops on every hand, read a key ---- */
  236.     if (stopping)
  237.         stopper = getch();
  238.     cleargame();
  239.     discs();
  240.     ++hands;
  241.     if (display)    {
  242.         cursor(40,0);
  243.         printf("HANDS: %d ", hands);
  244.     }
  245. }
  246. /* ---- test to see if a player should split the hand ---- */
  247. int split(int p)
  248. {
  249.     int a, b;
  250.     a = players[p].phand[0].value + 1;
  251.     b = players[dealer].phand[0].value + 1;
  252.     if (b > 10)
  253.         b = 10;
  254.     if (a == players[p].phand[1].value + 1)    {
  255.         switch (a)    {
  256.             case 1:    return TRUE;
  257.             case 2:
  258.             case 3:    return (b > 1 && b < 8);
  259.             case 4: return (b == 5 || b == 6);
  260.             case 5: return FALSE;
  261.             case 6:    return (b > 1 && b < 7);
  262.             case 7:    return (b > 1 && b < 8);
  263.             case 8: return TRUE;
  264.             case 9: return !(b == 7 || b == 10 || b == 1);
  265.             case 10: return FALSE;
  266.         }
  267.     }
  268.     return FALSE;
  269. }
  270. /* -------- display the discards pile count -------- */
  271. void discs(void)
  272. {
  273.     if (display)       {
  274.         cursor(20,0);
  275.         printf("DISCARDS: %d   ", nextdisc);
  276.     }
  277. }
  278. /* ---- test if a player has blackjack or went bust ---- */
  279. int bj_bust(int p)
  280. {
  281.     int rtn;
  282.     if ((rtn = (players[p].cards == 2 && handvalue(p) == 21))
  283.             == TRUE)
  284.         stat(p, "*BJ*");        /* player has blackjack */
  285.     else if ((rtn = (handvalue(p) > 21)) == TRUE)
  286.         stat(p, "BUST");        /* player went bust     */
  287.     return rtn;
  288. }
  289. /* ---- player strategy (true = hit, false = stand) ---- */
  290. int pstrategy(int p)
  291. {
  292.     int b, h;
  293.     /* ---- smart player watches dealers up card ---- */
  294.     b = players[dealer].phand[0].value+1;
  295.     h = handvalue(p);
  296.     if (players[p].mode == 'D')
  297.         return 0;
  298.     if (players[p].cards == 2 &&
  299.         players[p].phand[0].value+1 == 1 ||
  300.         players[p].phand[1].value+1 == 1)    {
  301.         switch (h)    {
  302.             case 3:
  303.             case 4:    if (b == 5 || b == 6)
  304.                         doubledown(p);
  305.                     return TRUE;
  306.             case 5:
  307.             case 6:    if (b > 3 && b < 7)
  308.                         doubledown(p);
  309.                     return TRUE;
  310.             case 7: if (b > 2 && b < 7)
  311.                         doubledown(p);
  312.                     return TRUE;
  313.             case 8: if (b > 3 && b < 7)
  314.                         doubledown(p);
  315.                     if (b == 2 || b == 7 || b == 8)
  316.                         return FALSE;
  317.                     return TRUE;
  318.             default: break;
  319.         }
  320.     }
  321.     switch (h)    {
  322.         case 4:
  323.         case 5:
  324.         case 6:
  325.         case 7:
  326.         case 8:        return TRUE;
  327.         case 9:        if (b > 2 && b < 7)
  328.                         doubledown(p);
  329.                     return TRUE;
  330.         case 10:    if (b > 1 && b < 10)
  331.                         doubledown(p);
  332.                     return TRUE;
  333.         case 11:    if (b != 1)
  334.                         doubledown(p);
  335.                     return TRUE;
  336.         case 12:    return !(b > 3 && b < 7);
  337.         case 13:
  338.         case 14:
  339.         case 15:
  340.         case 16:    return !(b > 1 && b < 7);
  341.         case 17:
  342.         case 18:
  343.         case 19:
  344.         case 20:
  345.         case 21:    return FALSE;
  346.     }
  347.     return FALSE;
  348. }
  349. /* ----------- double down the hand ---------- */
  350. void doubledown(int p)
  351. {
  352.     players[p].mode = 'D';
  353.     stat(p, "DBDN");
  354. }
  355. /* --------- the dealer strategy ---------- */
  356. int dstrategy(int p)
  357. {
  358.     /* - dealer hits on 16 or below, stands on 17 or above - */
  359.     return (handvalue(p) < 17);
  360. }
  361. /* ------- test if a hand wins or loses -------- */
  362. void winlose(int p)
  363. {
  364.     /* --- doubled-down hand bets twice as much --- */
  365.     if (players[p].mode == 'D')
  366.         players[p].bet *= 2;
  367.     /* ---- value > 21 is a bust ---- */
  368.     if (handvalue(p) > 21)
  369.         lost(p);
  370.     /* - blackjack wins if dealer does not have blackjack - */
  371.     else if (handvalue(p) == 21 && players[p].cards == 2 &&
  372.             !(handvalue(dealer) == 21 &&
  373.             players[dealer].cards == 2))
  374.         won(p);
  375.     /* ----- value greater than dealer wins ----- */
  376.     else if (handvalue(p) > handvalue(dealer))
  377.         won(p);
  378.     /* ----- if dealer busts, player wins ----- */
  379.     else if (handvalue(dealer) > 21)
  380.         won(p);
  381.     /* -- if dealer's hand > player's hand, player loses -- */
  382.     else if (handvalue(p) < handvalue(dealer))
  383.         lost(p);
  384.     /* ---- tied hand (push) if none of the above --- */
  385.     else
  386.         push(p);
  387.     /* ------ reset bet for doubled-down hand ------- */
  388.     if (players[p].mode == 'D')
  389.         players[p].bet /= 2;
  390. }
  391. /* -------- compute the value of a hand ------ */
  392. int handvalue(int pl)
  393. {
  394.     CARD *hd;
  395.     int vl = 0, cd, aces = 0;
  396.  
  397.     hd = players[pl].phand;        /* point to 1st card in hand */
  398.     while (hd->suit)    {
  399.         cd = hd->value+1;        /* value of the card         */
  400.         if (cd > 10)            /* jack, queen, king = 10    */
  401.             cd = 10;
  402.         if (cd == 1)    {        /* ace = 11                  */
  403.             cd = 11;
  404.             aces++;                /* count aces in the hand    */
  405.         }
  406.         vl += cd;                /* accumulate hand value     */
  407.         hd++;                    /* point to next card        */
  408.     }
  409.     while (vl > 21 && aces--)    /* adjust for aces if > 21   */
  410.         vl -= 10;                /* ace = 1                   */
  411.     return vl;
  412. }
  413. /* ------ the player won the hand :-) -------- */
  414. void won(int p)
  415. {
  416.     players[p].bank += players[p].bet + players[p].pushing;
  417.     players[p].pushing = 0;
  418.     players[dealer].bank -= players[p].bet;
  419.     post(p, "WIN ");
  420. }
  421. /* -------- the player lost the hand :-( --------- */
  422. void lost(int p)
  423. {
  424.     players[p].bank -= players[p].bet + players[p].pushing;
  425.     players[p].pushing = 0;
  426.     players[dealer].bank += players[p].bet;
  427.     post(p, "LOSS");
  428. }
  429. /* ------- the player tied :-| -------- */
  430. void push(int p)
  431. {
  432.     players[p].pushing = players[p].bet;
  433.     post(p, "PUSH");
  434. }
  435. /* ------- post the WIN/LOSS/PUSH ------ */
  436. void post(int p, char *s)
  437. {
  438.     if (display)    {
  439.         cursor(1+p*5, 24);
  440.         printf("%s", s);
  441.     }
  442. }
  443. /* -------- get the next card from the shoe ------ */
  444. void nextcard(CARD *cd)
  445. {
  446.     if (nextshoe == inshoe)    {
  447.         shuffle();                /* time to reshuffle */
  448.         bury();                    /* bury one          */
  449.     }
  450.     *cd = shoe[nextshoe++];
  451.     (cd+1)->suit = FALSE;
  452.     shoes();
  453. }
  454. /* --------- shuffle the discards into the shoe -------- */
  455. void shuffle(void)
  456. {
  457.     int cdp, nd;
  458.  
  459.     if (display)     {
  460.         cursor(0,0);
  461.         printf("SHUFFLE");
  462.     }
  463.     randomize();
  464.     nd = nextdisc;
  465.     for (nextshoe = 0; nextshoe < nd; nextshoe++)    {
  466.         cdp = random(nextdisc);
  467.         shoe[nextshoe] = discards[cdp];
  468.         while (cdp < nextdisc)    {
  469.             discards[cdp] = discards[cdp+1];
  470.             cdp++;
  471.         }
  472.         --nextdisc;
  473.     }
  474.     discs();
  475.     inshoe = nextshoe;
  476.     nextshoe = 0;
  477.     if (display)     {
  478.         cursor(0,0);
  479.         printf("       ");
  480.     }
  481. }
  482. /* ---------- bury the first card ----------- */
  483. void bury(void)
  484. {
  485.     CARD cd[2];
  486.  
  487.     nextcard(cd);
  488.     discards[nextdisc++] = *cd;
  489.     if (display)    {
  490.         card(cd[0].suit, cd[0].value, 1, 16);
  491.         cursor(1, 15);
  492.         printf("BURIED");
  493.         if (stopping)
  494.             stopper = getch();
  495.         nocardframe(1, 16);
  496.         cursor(1, 15);
  497.         printf("      ");
  498.     }
  499. }
  500. /* ----- display the number of cards left in the shoe ----- */
  501. void shoes(void)
  502. {
  503.     if (display)       {
  504.         cursor(10, 0);
  505.         printf("SHOE: %d ", inshoe-nextshoe);
  506.     }
  507. }
  508. /* ------- display the hand and the player's money ------ */
  509. void showhand(int pl)
  510. {
  511.     if (display)    {
  512.         cursor(1+pl*5, 3);
  513.         printf("%d", handvalue(pl));
  514.         hand(players[pl].phand, pl*CARDWIDTH, 4);
  515.     }
  516. }
  517. /* --------- display a hand -------- */
  518. void hand(CARD *lst, int x, int y)
  519. {
  520.     while (lst->suit)    {
  521.         card(lst->suit, lst->value, x++,y);
  522.         lst++;
  523.         y += 2;
  524.     }
  525. }
  526. /* ---------- display a card ---------- */
  527. void card(int sut, int val, int x, int y)
  528. {
  529.     cardframe(x, y);
  530.     cursor(x+1, y+1);
  531.     printf("   \b\b\b");
  532.     printf("%s%c", vals[val], sut);
  533. }
  534. /* ---------- display the card frame -------- */
  535. void cardframe(int x, int y)
  536. {
  537.     int y1;
  538.  
  539.     cursor(x, y);
  540.     printf(topline);
  541.     for (y1 = y+1; y1 < y+CARDHEIGHT-1; y1++)    {
  542.         cursor(x,y1);
  543.         printf(midline);
  544.     }
  545.     cursor(x,y1);
  546.     printf(botline);
  547. }
  548. /* --------- clear the game display ---------- */
  549. void cleargame(void)
  550. {
  551.     int i;
  552.  
  553.     for (i = 0; i < NBRPLAYERS; i++)    {
  554.         if (players[i].playing == TRUE)    {
  555.             if (display)    {
  556.                 cursor(1+i*5, 3);
  557.                 printf("  ");
  558.                 nohand(players[i].phand, i*CARDWIDTH, 4);
  559.             }
  560.             players[i].cards = 0;
  561.             players[i].playing = !(i & 1);
  562.             stat(i, "    ");
  563.             post(i, "    ");
  564.         }
  565.     }
  566. }
  567. /* ----- display a null hand to erase the hand ----- */
  568. void nohand(CARD *lst, int x, int y)
  569. {
  570.     while (lst->suit)    {
  571.         nocardframe(x++,y);
  572.         y += 2;
  573.         lst++;
  574.     }
  575. }
  576. /* ----- null card frame ------------ */
  577. void nocardframe(int x, int y)
  578. {
  579.     int y1;
  580.  
  581.     for (y1 = y; y1 < y+CARDHEIGHT; y1++)    {
  582.         cursor(x,y1);
  583.         printf("     ");
  584.     }
  585. }
  586. /* ---- print the status *BJ*, BUST, DBLD, SPLT, etc. ---- */
  587. void stat(int p, char *s)
  588. {
  589.     if (display)    {
  590.         cursor(p*CARDWIDTH, 2);
  591.         printf(s);
  592.     }
  593. }
  594.