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