Thread: Blackjack

  1. #1
    Registered User Tommo's Avatar
    Join Date
    Jun 2007
    Location
    Scotland
    Posts
    101

    Blackjack

    Hi there.

    I am trying to write a blackjack game and I am running into a few teething problems. My main() function currently outputs what values are stored for certain variables, just to see if I'm doing things properly. Here is the code:

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    #define MAX 10
    
    typedef struct {
      int card;
      int suit;
      int value;
    } card_t;
    
    void generate_card(card_t *crd, int *num, int *score);
    
    int main(void) {
    
      /* current scores for dealer and player */
      int p_score = 0;
      int d_score = 0;
    
      /* number of cards in their hand */
      int p_numofcards = 0;
      int d_numofcards = 0;
    
      /* initialise hands */
      card_t p_hand[MAX];
      card_t d_hand[MAX];
    
      srand((unsigned int)time(NULL));
    
      int i;
      for(i=0;i<2;i++) {          /*loop twice because at the start of blackjack, each player is given two cards*/
        generate_card(&p_hand[i], &p_numofcards, &p_score);
        generate_card(&d_hand[i], &d_numofcards, &d_score);
      }
    
      /* test */
      printf("p_score=&#37;d, p_numofcards=%d\n", p_score, p_numofcards);
      printf("d_score=%d, d_numofcards=%d\n", d_score, d_numofcards);
    int k;
      for(k=0;k<2;k++) {
        printf("p_hand[%d].card=%d,"
               " p_hand[%d].suit=%d, "
               " p_hand[%d].value=%d\n",
                k,p_hand[i].card,
                k,p_hand[i].suit,
                k,p_hand[i].value
               );
    
      printf("d_hand[%d].card=%d,"
             " d_hand[%d].suit=%d,"
             " d_hand[%d].value=%d\n",
              k,d_hand[i].card,
              k,d_hand[i].suit,
              k,d_hand[i].value
            );
      }
    
      return 0;
    }
    
    void generate_card(card_t *crd, int *num, int *score) {
    
      /* crd = (card_t *)malloc(MAX*sizeof(card_t)); */
    
      crd->card = (rand() % 13) + 1;
      crd->suit = (rand() % 4) + 1;
      int c;
      for(c=1;c<11;c++) {   
        if(crd->card == c) {  /*if card is 1-10 (ace- 10) then let the value of the card be whatever it is*/
          crd->value = c;       
          (*score)+=c;              /*adds to the score (eg. 10 of hearts would add a 10) */
          (*num)++;                 /*increments the number of cards in the players' hand*/
        }
      }
      switch(crd->card) {
        case 11: case 12: case 13:            /* if card is jack, queen or king...*/
          crd->value = 10;
          (*score)+=10; 
          (*num)++;   
          break;
      }
    
      /*free(crd);*/
    }
    Let me explain a few things. The card_t type represents with the following attributes: card( 1-13 for ace-king), suit(1-4 for hearts, clubs etc), value( ace=1, jack=10, queen=10 and so on). The generate_card function is supposed to generate a random card to simulate the dealer dealing unkown cards to the participants of the game. The program compiles but outputs rather absurd data:

    Code:
    $ gcc -o bjack bjack.c
    $ ./bjack
    p_score=8, p_numofcards=2
    d_score=8, d_numofcards=2
    p_hand[0].card=0, p_hand[0].suit=0,  p_hand[0].value=0
    d_hand[0].card=0, d_hand[0].suit=134513052, d_hand[0].value=24641422
    p_hand[1].card=0, p_hand[1].suit=0,  p_hand[1].value=0
    d_hand[1].card=0, d_hand[1].suit=134513052, d_hand[1].value=24641422
    Another run to show it is producing random cards correctly:
    Code:
    $ ./bjack
    p_score=11, p_numofcards=2
    d_score=6, d_numofcards=2
    p_hand[0].card=0, p_hand[0].suit=0,  p_hand[0].value=0
    d_hand[0].card=0, d_hand[0].suit=134513052, d_hand[0].value=24641422
    p_hand[1].card=0, p_hand[1].suit=0,  p_hand[1].value=0
    d_hand[1].card=0, d_hand[1].suit=134513052, d_hand[1].value=24641422
    Any help would be much appreciated, thanks.
    Last edited by Tommo; 06-14-2007 at 01:32 PM.

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    > k,p_hand[i].card,
    Maybe
    k,p_hand[k].card,

    Also, you need to introduce the idea of a "deck" of cards, which is initially "shuffled" into random order, then "dealt" one card at a time to each player.
    Your technique could easily have both players having the same cards.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User Tommo's Avatar
    Join Date
    Jun 2007
    Location
    Scotland
    Posts
    101
    Haha what a ignoramus I am. Thanks for that

    Regarding the deck of cards, you're right, it slipped my mind. Should I make an array of size 52, then mark each one null when it has been dealt? Seems kind of resource intensive, what would be a better way?

  4. #4
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Why not just start with every card, swap random cards a few times until all the cards are shuffled, and then take the top card off of the stack? Then you could set that card to NULL and take the next one, etc. This method wouldn't use too much CPU time, except for during initialization.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  5. #5
    Math wizard
    Join Date
    Dec 2006
    Location
    USA
    Posts
    582
    An array of 52 flags is one method (having "char cards[52]"), but it would require checking the array for unused cards and if used, the randomization is rerun. Using a card number from 1 to 52 in an array of 52 with each randomized is another method. Used cards would be zeros in the deck, unused cards (cards still in the deck) would be 1's in the flag method and the card number using the card number method. For determining the card number, come up with a pattern. I use A to K for 1 to 13 then clubs, diamonds, heats, then spades, for the groups of 13 (note that they are in numerical then alphabetical order). These are just some tips though. There's other ways available.
    High elevation is the best elevation. The higher, the better the view!
    My computer: XP Pro SP3, 3.4 GHz i7-2600K CPU (OC'd to 4 GHz), 4 GB DDR3 RAM, X-Fi Platinum sound, GeForce 460, 1920x1440 resolution, 1250 GB HDD space, Visual C++ 2008 Express

  6. #6
    Woof, woof! zacs7's Avatar
    Join Date
    Mar 2007
    Location
    Australia
    Posts
    3,459
    If you don't want it so 'resource intensive' then use a bitset perhaps? (Or a few bitsets...)

    You'd need ~7 bytes to store the flags... (52 / 8, 8 bits to a byte)

  7. #7
    Registered User Tommo's Avatar
    Join Date
    Jun 2007
    Location
    Scotland
    Posts
    101
    This is actually my second attempt at it, I made a meal of the first one. I actually made provisions for two of the same card being dealt, don't know why it slipped my mind this time. What I did was generate a random card, then see if it was already the the players' hand. If it was, I would generate another one. So something like:

    Code:
    while( card has already been dealt ) {
      generate_card();
    }
    Does this seem to be a good idea? Sorry, I am just starting out in C, forgive me if this is just as crap as my other idea.

    Thanks.

  8. #8
    Registered User Tommo's Avatar
    Join Date
    Jun 2007
    Location
    Scotland
    Posts
    101
    Hi, I have decided to redo it, the way dwks stated.

    But I'm getting strange output. Basically I have created a deck of cards and have shuffled them. It all seems fine. Then I created a cardtostring function to output '5 of spades' for example. But when testing the function, it produces strange output. Can someone please back me up on this:

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <time.h>
    
    #define NUMOFCARDS 52
    
    typedef struct {
      int card;
      int suit;
      int value;
    } card_t;
    
    int randy(void);
    void swapcards(card_t *c1, card_t *c2);
    int value(int a);
    void cardtostring(card_t crd, char *str);
    
    int main(void) {
    
      srand((unsigned int)time(NULL));
    
      card_t deck[NUMOFCARDS];
    
     /*this intialises the deck giving each card its attributes*/
      int i,k,index;
      for(i=0;i<4;i++) {
        for(k=0;k<13;k++) {
          index = (i*13) + k;
          deck[index].card = k+1;
          deck[index].suit = i+1;
          deck[index].value = value(k+1);
        }
      }
    
      int h=0;
      int j;
      while(h < 26) {   /*loop 26 times swapping a card from the first 26 with a random one from the last 26*/
        j = randy();
        swapcards(&deck[h],&deck[j]);
        h++;
      }
    
      /*  this is for testing what card is where in the deck after i shuffled them
      int p;
      for(p=0;p<52;p++) {
        printf("Card &#37; d: (card:%d,suit:%d,value:%d)\n",p+1,deck[p].card,deck[p].suit,deck[p].value);
      }
      */
    
      /* something is wrong here. this generates output to test the cardtostring function */
      char st[30];
      int l;
      for(l=0;l<52;l++) {
        cardtostring(deck[l], st);
        printf("The %dth card on the deck is: %s\n",l+1, st);
        strcpy(st,"");
      }
      
    
      return 0;
    }
    
    int randy(void) { 
      /* gen random number between 26 and 52 */
      return (rand() % (52-26+1))+ 26;
    }
    
    void swapcards(card_t *c1, card_t *c2) { /* function to swap two given cards in the deck */
      card_t temp;
      temp = *c1;
      *c1 = *c2;
      *c2 = temp;
    }
    
    int value(int a) {          /* value of card ace=1,jack=10,king=10 etc (will deal with ace=11 later*/
      if(a > 0 && a < 11)
        return a;
      else
        return 10;
    }
    
    void cardtostring(card_t crd, char *str) {
    
     /*try to create a string of the form "4 of spades" */
    
      if(crd.card > 1 && crd.card < 11) { /* between 2 and 10 then add it to the string */
        sprintf(str,"%d",crd.card);
      }
      switch(crd.card) {  /*here add ace for 1, jack for 11 etc */
      case 1:
        strcat(str, "Ace");
        break;
      case 11:
        strcat(str, "Jack");
        break;
      case 12:
        strcat(str, "Queen");
        break;
      case 13:
        strcat(str, "King");
        break;
      }
      strcat(str, " of "); /* the of part in '4 of hearts' */
      switch(crd.suit) {
      case 1:
        strcat(str, "spades");
        break;
      case 2:
        strcat(str, "clubs");
        break;
      case 3:
        strcat(str, "hearts");
        break;
      case 4:
        strcat(str, "diamonds");
      }
    }
    In my terminal I often see a '4 of <blank space> ' now and again (not all the time). Does anyone else get this? If so, can anyone see what I am doing wrong? Thanks

  9. #9
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    It sounds like none of these case statements are executing:
    Code:
      switch(crd.suit) {
      case 1:
        strcat(str, "spades");
        break;
      case 2:
        strcat(str, "clubs");
        break;
      case 3:
        strcat(str, "hearts");
        break;
      case 4:
        strcat(str, "diamonds");
      }
    Which would mean that crd.suit is invalid. I don't know why, because the rest of your code looks okay. It might give you a starting point.

    Rather than using the numeric literal "52" in your program, you should probably be using NUMOFCARDS, and NUMCARDS/2 instead of 26. Just a thought.

    Code:
      int h=0;
      int j;
      while(h < 26) {   /*loop 26 times swapping a card from the first 26 with a random one from the last 26*/
        j = randy();
        swapcards(&deck[h],&deck[j]);
        h++;
      }
    That works, I suppose, but it puts a slight bias on the results. You could get away with something as simple as
    Code:
    int x;
    for(x = 0; x < NUMCARDS * 10; x ++) {
        swapcards(&deck[rand() &#37; NUMCARDS], &deck[rand() % NUMCARDS]);
    }
    since swapcards() works perfectly well when passed the same card for both arguments. NUMCARDS*10 swaps might be overkill, but it would give you a very well shuffled deck.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  10. #10
    Registered User Tommo's Avatar
    Join Date
    Jun 2007
    Location
    Scotland
    Posts
    101
    No the case statements are executing. It is just the odd '4 of <space>' that crops up for no apparent reason. Well no reason that I can see, although there must be one. Here is the output:

    Code:
    The 1th card on the deck is: Ace of hearts
    The 2th card on the deck is: 9 of hearts
    The 3th card on the deck is: Ace of diamonds
    The 4th card on the deck is: King of hearts
    The 5th card on the deck is: 2 of hearts
    The 6th card on the deck is: 7 of hearts
    The 7th card on the deck is: 5 of spades
    The 8th card on the deck is: 3 of spades
    The 9th card on the deck is: Jack of diamonds
    The 10th card on the deck is: 4 of
    The 11th card on the deck is: Ace of spades
    The 12th card on the deck is: 3 of diamonds
    The 13th card on the deck is: 7 of spades
    The 14th card on the deck is: King of spades
    The 15th card on the deck is: Queen of diamonds
    The 16th card on the deck is: Ace of clubs
    The 17th card on the deck is: Queen of hearts
    The 18th card on the deck is: 5 of hearts
    The 19th card on the deck is: 7 of diamonds
    The 20th card on the deck is: 3 of clubs
    The 21th card on the deck is: 6 of spades
    The 22th card on the deck is: Jack of hearts
    The 23th card on the deck is: 7 of clubs
    The 24th card on the deck is: 10 of spades
    The 25th card on the deck is: 4 of diamonds
    The 26th card on the deck is: 4 of spades
    The 27th card on the deck is: Jack of spades
    The 28th card on the deck is: 10 of clubs
    The 29th card on the deck is: 3 of hearts
    The 30th card on the deck is: 4 of hearts
    The 31th card on the deck is: 5 of clubs
    The 32th card on the deck is: 6 of hearts
    The 33th card on the deck is: 8 of clubs
    The 34th card on the deck is: 8 of hearts
    The 35th card on the deck is: 2 of spades
    The 36th card on the deck is: 10 of hearts
    The 37th card on the deck is: 9 of clubs
    The 38th card on the deck is: 4 of clubs
    The 39th card on the deck is: King of clubs
    The 40th card on the deck is: 8 of spades
    The 41th card on the deck is: 2 of diamonds
    The 42th card on the deck is: Queen of spades
    The 43th card on the deck is: Queen of clubs
    The 44th card on the deck is: 5 of diamonds
    The 45th card on the deck is: 6 of diamonds
    The 46th card on the deck is: 6 of clubs
    The 47th card on the deck is: 8 of diamonds
    The 48th card on the deck is: 9 of diamonds
    The 49th card on the deck is: 10 of diamonds
    The 50th card on the deck is: 9 of spades
    The 51th card on the deck is: 2 of clubs
    The 52th card on the deck is: King of diamonds
    Everything apart from that '4 of <space>' is fine.

    Regarding the shuffle, you're right, I will give it a thorough shuffle. And yes, I should be using NUMOFCARDS, I was anxious to test it and it just slipped my mind. Thanks

  11. #11
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    I'll elaborate on "none of the case statements are executing".
    Code:
      switch(crd.suit) {
      case 1:
        strcat(str, "spades");
        break;
      case 2:
        strcat(str, "clubs");
        break;
      case 3:
        strcat(str, "hearts");
        break;
      case 4:
        strcat(str, "diamonds");
      }
    }
    If crd.suit is not 1, 2, 3, or 4, then nothing will get appended to str. You can see this if you do something like this:
    Code:
      switch(crd.suit) {
      case 1:
        strcat(str, "spades");
        break;
      case 2:
        strcat(str, "clubs");
        break;
      case 3:
        strcat(str, "hearts");
        break;
      case 4:
        strcat(str, "diamonds");
        break;
      default:
        strcat(str, "*error*");
      }
    }
    You'd probably get
    Code:
    The 10th card on the deck is: 4 of *error*
    when you ran this modified code.

    So, for the 10th card, the suit is not 1, 2, 3, or 4. If you look closely, you'll see that there are already four cards, on of each suit, that have the value 4. So, the 4 in the 10th card is messed up as well. The whole card is probably invalid.

    Careful examination shows that there are only three Aces, and so the tenth card should be the Ace of Spades. This is the very first card since spades are represented as 1 in your program.

    But wait . . . there are only three Jacks as well. So it's not just the first card that's not being initialized properly.

    So there's probably something wrong with this code:
    Code:
      int i,k,index;
      for(i=0;i<4;i++) {
        for(k=0;k<13;k++) {
          index = (i*13) + k;
          deck[index].card = k+1;
          deck[index].suit = i+1;
          deck[index].value = value(k+1);
        }
      }
    And, you guessed it, I think it's the red line. Multiplying i by 13 doesn't make sense, because i represents the suit and goes from 0 to 3. If you multiplied by 4 instead, it might work.
    Code:
    index = (i*4) + k;
    Anyway, I hope this helps in your debugging.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Simple Blackjack Program
    By saber1357 in forum C Programming
    Replies: 1
    Last Post: 03-28-2009, 03:19 PM
  2. Help with Blackjack program
    By sugie in forum C++ Programming
    Replies: 1
    Last Post: 04-30-2005, 12:30 AM
  3. Blackjack!
    By Dr. Bebop in forum Game Programming
    Replies: 1
    Last Post: 10-03-2002, 08:58 PM
  4. Blackjack
    By the_head in forum C Programming
    Replies: 1
    Last Post: 08-03-2002, 08:57 AM
  5. BlackJack Program...
    By 67stangman in forum C++ Programming
    Replies: 3
    Last Post: 05-06-2002, 10:44 PM