home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1998 May / Pcwk5b98.iso / Borland / Cplus45 / BC45 / BLAKJAK.PAK / BLAKJACK.CPP next >
C/C++ Source or Header  |  1995-08-29  |  13KB  |  674 lines

  1. //-----------------------------------------------------------------------------
  2. // ObjectWindows - (C) Copyright 1995 by Borland International
  3. // blakjack.cpp
  4. // This is the engine for the blackjack game, it does not contain any
  5. // windows or OWL code.
  6. //-----------------------------------------------------------------------------
  7.  
  8. #include "blakjack.h"
  9. #include <stdlib.h>
  10. #include <ctype.h>
  11. #include <iostream.h>
  12.  
  13. //------------------------------Card--------------------------
  14.  
  15. Card::Card(int iVal, int iType, int iface=0)
  16. :    number(iVal),
  17.     type(iType),
  18.     face(iface),
  19.     mark(0),
  20.     pVBXCard( NULL)
  21. {
  22. }
  23. // Sets new number i to the card, returns the old number.
  24. inline
  25. Card::setNumber(int i)
  26. {
  27.     int t = number;
  28.     number = i;
  29.     return t;
  30. }
  31. // Sets the new Type (HEARTS, CLUBS, DIAMONDS, SPADE),
  32. // returns the old type.
  33. inline
  34. Card::setType(int i)
  35. {
  36.     int t = type;
  37.     type = i;
  38.     return t;
  39. }
  40. inline
  41. Card::isUp() const
  42. {
  43.     return (face?1:0);
  44. }
  45. // Flips the card.
  46. inline void
  47. Card::flip()
  48. {
  49.     face = face? 0: 1;
  50. }
  51. // If a card is marked as 1, it means it has been
  52. // dealt by the dealer from the deck and can be no longer used
  53. // to deal or shuffle.
  54. inline void
  55. Card::setMark(int i)
  56. {
  57.     mark = i;
  58. }
  59. inline
  60. Card::isMarked() const
  61. {
  62.     return (mark?1:0);
  63. }
  64. void
  65. Card::setVBXCard(int VBXCardArrayIndexPlus1)
  66. {
  67.     pVBXCard = VBXCardArrayIndexPlus1;
  68. }
  69. //------------------------------------ Deck---------------------
  70. // returns total number of cards in the deck.
  71. Deck::GetTotal() const
  72. {
  73.     return total;
  74. }
  75. void
  76. Deck::SetTotal(int i) throw (const char* )
  77. {
  78.     if(i > 52)
  79.         throw "SetTotal:Invalid range, try 0-52";
  80.     else
  81.       total = i;
  82. }
  83. void
  84. Deck::SetTopIndex(int i)
  85. {
  86.     topIndex = i;
  87. }
  88. Card *
  89. Deck::GetCard()
  90. {
  91.     if(!total)
  92.         return (Card *)NULL;
  93.     else
  94.     {
  95.       total--;
  96.       Card *retCard = ppCards[topIndex];
  97.       ppCards[topIndex++] = NULL;
  98.       return retCard;
  99.     }
  100. }
  101. // It generates a random number between 0 and 51
  102. // For 100 times it generates 2 random numbers in the above range
  103. // and exchanges the cards in these 2 positions in the deck.
  104. // Returns how many times the card gets shuffled for 100 tries.
  105. Deck::Shuffle()
  106. {
  107.   int i;
  108.   int j;
  109.   int s =0;
  110.  
  111.   Card *tmp;
  112.  
  113.   randomize();
  114.   for(int k = 0; k <100; k++)
  115.   {
  116.         i = rand() % 52; // generates 0 to 51.
  117.         j = rand() % 52;
  118.  
  119.         // swap cards only if the cards are in the
  120.         // deck.
  121.  
  122.         if(ppCards[i] && ppCards[j])
  123.         {
  124.             // Shuffle only if the cards are in deck.
  125.             tmp          = ppCards[i  ];
  126.             ppCards[i]   = ppCards [j];
  127.             ppCards[j]   = tmp;
  128.             s++;
  129.         }
  130.   }
  131.   return s;
  132. }
  133.  
  134. Deck::Deck() throw(const char *)
  135. :    total(52),
  136.     ppCards((Card **)new char [sizeof(Card *)*(52+1)]),
  137.     topIndex(0)
  138.  
  139. {
  140.  
  141.     if(!ppCards)
  142.         throw "Error:Deck::Deck() out of memory.";
  143.     for(int i=0; i < 52; i++)
  144.  
  145.     {             // Number (0-13)  Type(1-4)
  146.         ppCards[i] = new Card(i%13, ((i/13)+1), 1);
  147.     }
  148.     ppCards[i] = NULL; // the last cell
  149.  
  150.     Shuffle();
  151. }
  152. Deck::~Deck()
  153. {
  154.     for(int i=0; i < 52; i++)
  155.     {
  156.         delete ppCards[i];
  157.     }
  158.     delete ppCards;
  159. }
  160.  
  161. // This funtion prints the all the crads in the deck.
  162. // Do not use this funtion in the OWL program. Used for
  163. // debugging purpose only.
  164.  
  165. ostream&
  166. operator<<(ostream &str, Deck& rhs)
  167. {
  168.   for(int i =0; i < 52; i++)
  169.   {
  170.     // if the card is already dealt to the player it will not be present
  171.     //  on the deck. In that case do not try to print it.
  172.     if(rhs.ppCards[i])
  173.     {
  174.          str << rhs.ppCards[i]->getNumber() << " " ;
  175.          switch(rhs.ppCards[i]->getType())
  176.          {
  177.              case 1:
  178.              str << "Hearts";
  179.              break;
  180.              case 2:
  181.              str << "Spades";
  182.              break;
  183.              case 3:
  184.              str << "Clubs";
  185.              break;
  186.              case 4:
  187.              str << "Diamonds";
  188.              break;
  189.              default:
  190.              str << "Uninitialized card";
  191.              break;
  192.          }
  193.          str << "  ";
  194.     }
  195.   }
  196.   return str;
  197. }
  198.  
  199. //-----------------------Hand----------------------------------
  200. void
  201. Hand::AdjustAceValueIfTotalIs21Plus()
  202. {
  203.             // Check if the player/Dealer has any ACE in his hand.
  204.             // If it was 11 make it 1 and give the player
  205.             // a 2nd chance. Adjust the players score also.
  206.  
  207.             Card *pCard = ppCards[0];
  208.             int done = 0;
  209.             for(int i =0; pCard && !done; i++)
  210.             {
  211.                 pCard = ppCards[i];
  212.                 if(pCard)
  213.                 {
  214.                     if(pCard->getNumber() == 0)
  215.                     {
  216.                       // card is ACE
  217.                       if(pCard->getMark())
  218.                       {
  219.                           //ACE is marked as 11, mark it as 1.
  220.                           pCard->setMark(0);
  221.  
  222.                           // recalculate points with ACE as 1 instead of 11.
  223.                           setPoints(getPoints()-10);
  224.                           done = 1;
  225.                       }
  226.                     }
  227.                 }
  228.                 else
  229.                   done = 1;
  230.             }
  231. }
  232. //
  233. // It calculates the total number of points including the added card.
  234. // and stores it in "points" data member.
  235. // Returns the index at which the new card was added.
  236. //
  237. Hand::AddCard(Card *pCard)
  238. {
  239. int retVal = getTotalCards();
  240.     ppCards[retVal] = pCard;
  241.  
  242.     // Add the Card and then increase the total.
  243.     incTotalCards();
  244.     calcPoints(pCard->getNumber());
  245.     return retVal;
  246. }
  247.  
  248. // Set value for point data member. Which holds total points for the hand.
  249. void
  250. Hand::setPoints(int i)
  251. {
  252.     points = i;
  253. }
  254.  
  255. // Get the total point for the particular hand.
  256. Hand::getPoints() const
  257. {
  258.     return points;
  259. }
  260. inline void
  261. Hand::setResult(int i)
  262. {
  263.     result = i;
  264. }
  265. Hand::getResult() const
  266. {
  267.     return result;
  268. }
  269. // if bet amount is more than total
  270. // return 0.
  271. // else 1.
  272. inline
  273. Hand::setBetMoney(int i)
  274. {
  275.     {
  276.         betMoney = i;
  277.         return 1;
  278.     }
  279. }
  280. Hand::getBetMoney() const
  281. {
  282.     return betMoney;
  283. }
  284. Hand::getTotalCards() const
  285. {
  286.     return totalCards;
  287. }
  288. // Increments and returns the value of the
  289. // new "totalCards".
  290. Hand::incTotalCards()
  291. {
  292.   return ++totalCards;
  293. }
  294. //
  295. // It is called after a game is over, to initialize
  296. // the hand.
  297. // Returns how many cards where actually flushed.
  298. //
  299. Hand::flushCards()
  300. {
  301. int howManyFlushed =0;
  302.     for(int i=0; i < 52; i++)
  303.     {
  304.          if(ppCards[i])
  305.          {
  306.              delete(ppCards[i]);
  307.              ppCards[i] = NULL;
  308.              howManyFlushed++;
  309.          }
  310.  
  311.     }
  312.  
  313.     totalCards = 0;
  314.     points =0;
  315.     return howManyFlushed;
  316. }
  317. //-------------------------calcPoints()-----------------------------------
  318. // Numbers    Blackjack
  319. // which      points
  320. // represent
  321. // a card.
  322. // ----------------------
  323. // 0 -       Ace (is 11 if total in hand is <= 10 else 1, cannot go over 21.)
  324. // 1         2 of any suit
  325. // 2         3 of any suit
  326. // ...
  327. // 9 -       10 of any suit
  328. // 10 -       Jack   (10)
  329. // 11 -       Queen  (10)
  330. // 12 -       King   (10)
  331. // After a new card is added this is called to calculate the total points.
  332. // Input is the internal number representation of the card as shown in the
  333. // first column above. The 2nd column shows the points for different cards.
  334. // Returns the incremented value of total point.
  335.  
  336. Hand::calcPoints(int number) throw(const char*)
  337. {
  338.     switch(number)
  339.     {
  340.         case 0:
  341.             if(points <= 10)
  342.             {
  343.                 points += 11;
  344.  
  345.                 // Mark the card as 1, that means, ACE which is 11.
  346.                 ppCards[getTotalCards() - 1]->setMark(1);
  347.             }
  348.             else
  349.                 points +=1;
  350.  
  351.         break;
  352.         case 10:  // jack
  353.         case 11:  // Queen
  354.         case 12:  // King
  355.             points += 10;
  356.         break;
  357.         default:
  358.             if(number >=1 && number <=9)
  359.                 points += (++number);
  360.             else
  361.              throw "Error:calcPoints():Card number outof range.\n";
  362.     }
  363.     // Adjust the point of the card here.
  364.     if(points > 21)
  365.         AdjustAceValueIfTotalIs21Plus();
  366.  
  367.     return points;
  368. }
  369.  
  370. Hand::Hand() throw (const char *)
  371. :  ppCards ((Card **)new char [sizeof(Card *)*(52+1)]),
  372.     totalCards(0),
  373.     points(0),
  374.     result(UNKNOWN),
  375.     betMoney(0)
  376. {
  377.     // Array of pointers to Card type.
  378.  
  379.     if(!ppCards)
  380.         throw "Ran out of memory in Hand::Hand()";
  381.     for(int i=0; i < 52; i++)
  382.     {
  383.         ppCards[i] = NULL;
  384.     }
  385.     ppCards[i] = NULL;
  386. }
  387. Hand::~Hand()
  388. {
  389.     for(int i=0; i < 52; i++)
  390.     {
  391.         delete ppCards[i];
  392.     }
  393.     delete ppCards;
  394. }
  395.  
  396. //-----------------------------Bankroll---------------------------
  397.  
  398. Bankroll::Bankroll(int i = 100):total(i)
  399. {
  400. }
  401.  
  402. Bankroll::~Bankroll()
  403. {
  404. }
  405. void
  406. Bankroll::setTotal(int i)
  407. {
  408.     total = i;
  409. }
  410. Bankroll::getTotal() const
  411. {
  412.     return total;
  413. }
  414. // returns 0 if input > total
  415. // else returns 1.
  416. Bankroll::decrementBy(int i)
  417. {
  418.     if( (total -i) < 0)
  419.         return 0;
  420.     else
  421.     {
  422.         total -= i;
  423.         return 1;
  424.     }
  425. }
  426. // increaments the total by input
  427. // and returns the new total.
  428. Bankroll::incrementBy(int i)  throw(const char *)
  429. {
  430.     if(i>=0)
  431.     {
  432.         total += i;
  433.     }
  434.     else
  435.     {
  436.         throw "Error:Bankroll.incrementby: -ve input\n";
  437.     }
  438.     return total;
  439. }
  440. // returns
  441. // 1 if empty.
  442. // 0 if not empty.
  443.  
  444. Bankroll::isEmpty() const
  445. {
  446.     return(total?0:1);
  447. }
  448. //------------------------Player---------------------------
  449. //
  450. // returns
  451. // 0 if bet > bankroll
  452. // 1 if bet has been made.
  453. // sets the "betMoney" data member to inut.
  454. //
  455. Player::Bet(int i)
  456. {
  457.     if(i > pocket.getTotal() || (i <=0))
  458.       return 0;
  459.     else
  460.     {
  461.         // in Hand.
  462.         setBetMoney(i);
  463.         return 1;
  464.     }
  465. }
  466. //-----------------Lost()-----------------------
  467. // Decrements the bankroll by "betMoney".
  468. // Returns the amount of bankroll money left.
  469.  
  470. Player::Lost() throw(const char *)
  471. {
  472. int total = pocket.getTotal();
  473.     if(getBetMoney() <= total)
  474.     {
  475.         pocket.decrementBy(getBetMoney());
  476.     }
  477.     else
  478.     {
  479.         // Fatal error, it should not happen.
  480.         // before betting this condition is checked.
  481.         throw "Error:Player.Lost():You lost more money than you have\n";
  482.     }
  483.     return (total - getBetMoney());
  484. }
  485. // Increments the bankRoll by "betMoney".
  486. // Returns the total after winning.
  487. Player::Won()
  488. {
  489.     return (pocket.incrementBy(getBetMoney()));
  490. }
  491.  
  492. Player::Player(int money)
  493. {
  494.     pocket.setTotal(money);
  495. }
  496. Player::~Player()
  497. {
  498. }
  499. //-------------------------Dealer--------------------------------
  500. Dealer::Dealer()
  501. :    deck( new Deck)
  502. {
  503. }
  504. Dealer::~Dealer()
  505. {
  506.     delete deck;
  507. }
  508. Deck &
  509. Dealer::getDeck() const
  510. {
  511.     return *deck;
  512. }
  513. void
  514. Dealer::setDeck(Deck *p)
  515. {
  516.     deck = p;
  517. }
  518. //-------------------------BlackJack----------------------------
  519. // Returns the nth number player.
  520. // If no such player exists then it returns NULL.
  521. // Player number starts from 1.
  522. // There is no 0th player.
  523.  
  524. Player *Blackjack::getPlayer(int p) const
  525. {
  526.     if (p ==0)
  527.         return NULL;
  528.  
  529.     // finds the total number of players.
  530.     for(int i=0; ppPlayer[i]; i++)
  531.       ;
  532.      if(p <= (i))
  533.         return ppPlayer[p-1];
  534.      else
  535.         return NULL;
  536. }
  537. // Returns
  538. // PLAYER ->  1 or
  539. // DEALER ->  2 or
  540. // BOTH   ->  3 or
  541. // UNKNOWN -> 4
  542. // Depending on who lost.
  543. // header file.
  544.  
  545. Blackjack::whoLost()
  546. {
  547.     int pPoint = (*getPlayer(1)).getPoints();
  548.     int dPoint = getDealer().getPoints();
  549.  
  550.     // if any player has scored more than 21
  551.  
  552.     if(dPoint > 21 && pPoint <= 21)
  553.         return DEALER;
  554.     if(pPoint > 21 && dPoint <= 21)
  555.         return PLAYER;
  556.  
  557.     // Following cases cannot be "greater than 21" cases
  558.     if(dPoint > pPoint)
  559.       return PLAYER;
  560.     else
  561.       if(dPoint < pPoint)
  562.         return DEALER;
  563.       else
  564.         if(dPoint == pPoint)
  565.             return BOTH;
  566.  
  567.      return(UNKNOWN);
  568. }
  569.  
  570. // Returns
  571. // 1
  572. // when a player or both(player and dealer) hit blackjack
  573. // ie, scored 21 points when the 1st 2 cards where dealt.
  574. // 0 - if not.
  575.  
  576. Blackjack::IsBlackjack()
  577. {
  578.     int pPoint = (*getPlayer(1)).getPoints();
  579.     int dPoint = (getDealer()).getPoints();
  580.     if(pPoint == 21 || dPoint == 21)
  581.         return 1;
  582.     else
  583.         return 0;
  584. }
  585. Blackjack::Blackjack()
  586. {
  587.     // This application uses only one player and one dealer
  588.    // You can extend the game by adding more number of players.
  589.     ppPlayer = (Player **)new char[sizeof(Player *)*2];
  590.     ppPlayer[0] = new Player(100);
  591.     ppPlayer[1] = NULL;
  592.  
  593. }
  594. Blackjack::~Blackjack()
  595. {
  596.     for(int i=0; ppPlayer[i]; i++)
  597.         delete ppPlayer[i];
  598.     delete ppPlayer;
  599. }
  600. // This is the "Deal" operator for dealing a card to the dealer.
  601. // eg: "Dealer << Dealer", means Dealer deals a card to himself.
  602.  
  603. Dealer& operator << (Dealer &p, Dealer &d) throw(const char *)
  604. {
  605.     Card *pCard = (d.deck)->GetCard();
  606.     if(pCard)
  607.     {
  608.         if(p.getTotalCards()> 52)
  609.             throw "Dealer cannot have more than 52 cards\n";
  610.         else
  611.         {
  612.               p.AddCard(pCard);
  613.         }
  614.     }
  615.     else
  616.         throw "All cards exhausted\n";
  617.     return p;
  618. }
  619. // This is the "Deal" operator for dealing a card to the player.
  620. // eg: "Player << Dealer", means Dealer deals a card to the player.
  621. // Returns always 0.
  622. // DO NOT chain it.
  623. //
  624. operator << (Player &p, Dealer &d) throw(const char *)
  625. {
  626.     Card *pCard = (d.deck)->GetCard();
  627.     if(pCard)
  628.     {
  629.         if(p.getTotalCards()> 52)
  630.             throw "Player cannot have more than 52 cards\n";
  631.         else
  632.         {
  633.               p.AddCard(pCard);
  634.         }
  635.     }
  636.     else
  637.         throw "All cards exhausted\n";
  638.     return 0;
  639. }
  640. // This is a debugging function to print out the hand status.
  641. // Useful while debugging the engine in text mode. Now it is not
  642. // used any where.
  643. ostream& 
  644. operator << (ostream& str, Hand &rhs)
  645. {
  646. int total = rhs.getTotalCards();
  647.   for(int i =0; i < total; i++)
  648.   {
  649.     str << rhs.ppCards[i]->getNumber() << " " ;
  650.     switch(rhs.ppCards[i]->getType())
  651.     {
  652.         case 3:
  653.         str << "Hearts";
  654.         break;
  655.         case 4:
  656.         str << "Spades";
  657.         break;
  658.         case 1:
  659.         str << "Clubs";
  660.         break;
  661.         case 2:
  662.         str << "Diamonds";
  663.         break;
  664.         default:
  665.         break;
  666.     }
  667.     str << "  ";
  668.   }
  669.   str << "total: " << rhs.getPoints();
  670.   str << endl;
  671.   return str;
  672. }
  673.  
  674.