Thread: Problem with a very simple card game

  1. #1
    Registered User
    Join Date
    Mar 2014
    Posts
    12

    Problem with a very simple card game

    first of all I am very new. Only 3 weeks into a very intensive course.
    Secondly this will be very long. I appologize in advance. Thanks for your patience!
    We were tasked with writing a very simple - no stratagy - card game. The rules are as follow: first playr picks a random card and attacks the next one who has to respond with a higher card of the same suit ("match"). If he succeeds both cards are discarded, otherwise the defender picks up the attacking card and forfeits his turn to attack player 3. First player of 4 to drop all cards wins. This must go on for up to 20 rounds.
    The cards must be displayed in the bu suit and in ascending fashion like so:
    Diamonds: 2, 5, 8, K, A
    Clubs: 3, 5, Q..
    Etc. And must remain sorted at all times.

    I have a number of problems I cannot figure out:
    1. I'm trying to print all players "hands" (all the cards he has) at the end of each round (full circle from player 1 to 4). For some reason it sometimes does and sometimes doesn't and there doesn't seem to be a clear pattern. After 10th round it does work.. **
    2. During each "match" I wnt to print the outcome. I've succeeded except that in one case - if player 4 attacks player 1, for some reason player 1's name doesn't appear. **
    3. this cannot be seen in a pleayer's hand - only when looking at all the "matches": even though there are 4 suits (which I've ENUMed but don't know how to actually print the ENUM so I represent them by number 1-4) once or twice a game suddenly there is a card with the suit number 65... **

    ** it's much easier to understand if you run the code..

    I'm posting all my code for this purpose and I appologize for the length. Because I didn't want to post an extremely long post I used a website to save the pieces of code:

    Here are the links:

    Main:
    File #tpqxai41-27542 | sourcepod.com
    Signatures:
    File #mombhh61-27545 | sourcepod.com
    Functions:
    File #amkgud88-27546 | sourcepod.com

    Thanks a lot!!

  2. #2
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    Please post your code here, as plain text, in [code][/code] tags. Make sure it's properly formatted and indented so it's easy for us to read. Don't worry about the length, you're only at ~400 lines total.

    Just based on your description of the problem however, I suspect you have an array out of bounds error. Make sure you never go past the end of an array by ensuring each loop has a check similar to i < MAX_LEN. Make sure you also leave room for the null character '\0' that marks the end of a string. If you want a string to hold up to 10 characters, you actually need to declare it with size 11.

    A couple other quick notes:
    1. Why did you not #define MAX_NAME_LEN 20, so you can use that for player names?
    2. Why did you call it DENOMINATOR then use a comment to explain what it really is? Why not just call the constant CARDS_PER_SUIT?
    3. Constants for win types: nobody, first, second, both.

    The take-away here is: whenever you have to use a comment to describe a magic number, you should define constants. Whenever you need comments to explain a constant/variable/function name, you should pick a better name.

    Overall, however, it looks like you have good variable, function and constant names and pretty solid code organization and planning -- which is excellent.

  3. #3
    Registered User
    Join Date
    Mar 2014
    Posts
    12
    Thanks! That last comment means a lot

    signatures:

    Code:
    #ifndef CARDS_GAME_H
    #define CARDS_GAME_H
    
    #define DENOMENATOR 13 /* card per suit */
    #define DECK_SIZE 52
    #define NUM_OF_PLAYERS 4
    #define NUM_OF_SUITS 4
    #define NUM_OF_ROUNDS 20
    
    enum suits {Spade, Club, Diamond, Heart};
    
    typedef enum suits suits;
    
    struct Card    {
        int number;
        int value;    
        suits suit;
    };
    
    typedef struct Card Card;
    
    struct Player    {
        char name[20];
        int numOfCards;
        Card PlayerCards[DECK_SIZE];
        int winner;
    };
    
    typedef struct Player Player;
    
    Card * ShuffleCards (Card *);
    Player * Dealing (Player *, Card *);
    void Print (Player *);
    void PlayGame (Player * _player);
    int Match(Card _attackerCard, Player _attacker, Player _defender);
    void PlayGame (Player * _players);    
    
    #endif
    Main:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include "Cards_Signatures.h"
    
    int main(int argc, char **argv)    {
        int cont = 1;            
        int option;
        Card cards[DECK_SIZE];
        Card * cardsPtr = cards;
        Player players[NUM_OF_PLAYERS];
        Player * playersPtr = players;
        
        while (cont) 
        {
            printf("Choose option: \n");
            printf("1: Play  \n");
            printf("Any other nuber - Quit \n");
            
            scanf("%d", &option);
            switch (option) {
                case 1:
                        system("clear");
                        cardsPtr = ShuffleCards (cards);
                        playersPtr = Dealing (playersPtr, cardsPtr);
                        Print (players);    
                        PlayGame (playersPtr);
                        getchar();
                    break;
                    
                default: 
                    cont = 0;    
                    break;
            }
        putchar('\n');
        }
        
        return 0;
    }
    functions:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <time.h>
    #include "Cards_Signatures.h"
    
    Player * SortCards (Player*, int, int);
    void PrintSuit (Player*, int, int);    
    
    Card * ShuffleCards (Card * _cards)    
    {
        int cardsArray[DECK_SIZE];
        int i;
        int place;
        
        for (i = 0 ; i < DECK_SIZE ; i++)    
        {
            cardsArray[i] = 0;
        }
        
        i = 2;
        srand(time(NULL));
        while (i < DECK_SIZE + 2)    
        {
            place = rand() % DECK_SIZE;
            if (cardsArray[place] == 0)    
            {
                cardsArray[place] = i;
                i++;
            }
        }
        
        for (i = 0 ; i < DECK_SIZE ; i++)    
        {
            _cards[i].number = cardsArray[i];
            _cards[i].value = (cardsArray[i] - 2) % DENOMENATOR + 2;
            _cards[i].suit = (cardsArray[i] - 2) / DENOMENATOR;
            
        }
        
        return _cards;
    }
    
    Player * Dealing (Player * _players, Card * _cardsArray)    
    {
        int i;
        
        for (i = 0 ; i < NUM_OF_PLAYERS ; i++)    
        {
            _players[i].numOfCards = DENOMENATOR;
        }
            
        for (i = 0 ; i < DECK_SIZE ; i++)    
        {
            _players[i % NUM_OF_PLAYERS].PlayerCards[i / NUM_OF_PLAYERS].number = _cardsArray[i].number;
            _players[i % NUM_OF_PLAYERS].PlayerCards[i / NUM_OF_PLAYERS].value = _cardsArray[i].value;
            _players[i % NUM_OF_PLAYERS].PlayerCards[i / NUM_OF_PLAYERS].suit = _cardsArray[i].suit;
        }
            
        for (i = 0 ; i < NUM_OF_PLAYERS ; i++)    
        {
            _players = SortCards(_players, _players[i].numOfCards, i);
            sprintf(_players[i].name, "Player %d", i + 1);
        }
    
        return _players;
    }
    
    void Print (Player * _players)    
    {
        int i;
        
        for (i = 0 ; i < NUM_OF_PLAYERS ; i++)    
        {
            putchar('\n');
            printf("Player %d cards are:\n\n", i + 1);
            printf("Spades: ");
            PrintSuit(_players, i, 0);
            putchar('\n');
            printf("Clubs: ");
            PrintSuit(_players, i, 1);
            putchar('\n');
            printf("Diamonds: ");
            PrintSuit(_players, i, 2);
            putchar('\n');
            printf("Hearts: ");
            PrintSuit(_players, i, 3);    
            putchar('\n');
            putchar('\n');
            
        }
    }
    
    void PrintSuit (Player * _players, int i, int suit)    
    {
        int j;
        
        for (j = 0 ; j < _players[i].numOfCards ; j++)    
        {
            if (_players[i].PlayerCards[j].suit == suit)    
            {
                if (_players[i].PlayerCards[j].value > 1 && _players[i].PlayerCards[j].value < 10)
                    printf ("%d ", _players[i].PlayerCards[j].value);
                if (_players[i].PlayerCards[j].value == 10)
                    printf ("T ");
                if (_players[i].PlayerCards[j].value == 11)
                    printf ("J ");
                if (_players[i].PlayerCards[j].value == 12)
                    printf ("Q ");
                if (_players[i].PlayerCards[j].value == 13)
                    printf ("K ");
                if (_players[i].PlayerCards[j].value == 14)
                    printf ("A ");
            }
        }
    }
        
    Player * SortCards (Player * _players, int _n, int _numOfPlayer)    
    {
        int i,j;
        Card temp;
        
        for (i = 1 ; i < _n ; i++)    
        {
            for (j = i ; j > 0 ; j--)    
            {
                if (_players[_numOfPlayer].PlayerCards[j].number < _players[_numOfPlayer].PlayerCards[j - 1].number)    
                {
                    temp = _players[_numOfPlayer].PlayerCards[j];
                    _players[_numOfPlayer].PlayerCards[j] = _players[_numOfPlayer].PlayerCards[j - 1];
                    _players[_numOfPlayer].PlayerCards[j - 1] = temp;
                }
                else    
                {
                    break;
                }
            }     
        }
        
        return _players;
    }
    
    int Match(Card _attackerCard, Player _attacker, Player _defender)
    {
        int i;
        printf("\n%s attacks with card %d-%d. ", _attacker.name, _attackerCard.suit +1, _attackerCard.value);
        for (i = _defender.numOfCards -1; i >= 0; i--)
        {
            if (((_attackerCard.suit == ((_defender.PlayerCards)[i]).suit)))
            {
                if (((_attackerCard.value < ((_defender.PlayerCards)[i]).value)))
                {
                    printf("%s defends with card %d-%d\n", _defender.name, _defender.PlayerCards[i].suit +1, _defender.PlayerCards[i].value);
                    return i; /* Second player won the match. Returnes number of card in player's hand */
                }
            }
        }
        printf("%s couldn't counter and loses his turn!!\n", _defender.name);
        return 0; /* First player won the match */
    }
    
    Player InternalSort(Player _player)
    {
        int i,j;
        Card temp;
    
        for (i = _player.numOfCards - 1; i > 0; i--)
        {
            for (j = 0; j < _player.numOfCards; j++)
            {
                if (((_player.PlayerCards[j].number > _player.PlayerCards[j + 1].number)))
                {
                    temp = ((_player.PlayerCards)[j]);
                    (_player.PlayerCards)[j] = (_player.PlayerCards)[j + 1];
                    (_player.PlayerCards)[j + 1] = temp;
                } 
            
            }
        }
        
        return _player;
    }
    
    Player DiscardLeftShift(Player _player, Card _attackerCard)
    {
        int i, place;
        Card temp;
        place = _player.numOfCards - 1;
    
        for (i = 0; i < place - 1; i++)
        {
            if (_attackerCard.number == ((_player.PlayerCards)[i]).number)
            {
                temp = (_player.PlayerCards)[place];
                (_player.PlayerCards)[place] = (_player.PlayerCards)[i];
                (_player.PlayerCards)[i] = temp;
                break;
            }
        }
        
        if (_player.numOfCards > 0)
        {
            (_player.numOfCards)--;
        }
        place = _player.numOfCards;
        _player = InternalSort(_player);
        
        return _player;
    }
    
    Player RightShift(Player _player, Card _card)
    {
        _player.numOfCards++;
        _player.PlayerCards[_player.numOfCards] = _card;
        
        _player = InternalSort(_player);
        
        return _player;
    }
    
    void PlayGame (Player * _players)    
    {
        int i, j, lowestCardCount, currentWinner;
        int index = 0;
        int matchResult = 0;                
        int winNumber = 0;                    /* '0' - nobody won, '1' - first won, '2' - second won. '3' - both players won */
        Card attackerCard;
        lowestCardCount = 0;
        currentWinner = 0;
        
        system("clear");
        srand(time(NULL));
        for (i = 0 ; i < (NUM_OF_PLAYERS * NUM_OF_ROUNDS) ; i++)    
        {
            index = (i % 4);
            
            if ((index == 0) && (i > 0))
            {
                printf("************************************************************************************************\nEnd of round %d\n", (i / 4));
                printf("************************************************************************************************\n\n");
                Print(_players);
                getchar();
            }
            
            /*printf("%s number of cards %d\n",_players[index].name, _players[index].numOfCards);*/
            attackerCard = (_players[index].PlayerCards[rand() % _players[index].numOfCards]);
            matchResult = Match(attackerCard, _players[index], _players[index+1]);
            
            if (matchResult == 0) /* First (attacking) player won the match */
            {
                _players[index] = DiscardLeftShift(_players[index], attackerCard); 
                _players[index + 1] = RightShift(_players[index + 1], attackerCard); 
                i++;
            }
            else /* Second (defending) player won the match */
            {
                _players[index] = DiscardLeftShift(_players[index], attackerCard); 
                _players[index + 1] = DiscardLeftShift(_players[index+1], _players[index + 1].PlayerCards[matchResult]);            
            }
            if (((_players[index].numOfCards) == 0) && (_players[index + 1].numOfCards) > 0)
            {
                printf("break1");
                winNumber = 1;
                break;
            }
                    
            if (((_players[index].numOfCards) > 0) && (_players[index + 1].numOfCards) == 0)
            {
                printf(" break2 ");
                winNumber = 2;
                break;
            }
            
            if (((_players[index].numOfCards) == 0) && (_players[index + 1].numOfCards) == 0)
            {
                printf("break3");
                winNumber = 3;
                break;
            }
            
            
        }
        
        switch (winNumber)
        {
            case(1):
                printf("\nPlayer %d won!!", index + 1);
                break;
            case(2):
                printf("\nPlayer %d won!!", index + 2);
                break;
            case(3):
                printf("\nPlayers %d and %d won together! Hooray for partnership, good will and stuff!\n\n", index +1 , index + 2);
                break;
            case(0):
                for (j = 0; j < NUM_OF_PLAYERS; j++)
                {
                    if (_players[j + 1].numOfCards < _players[index].numOfCards)
                    {
                        lowestCardCount = _players[j + 1].numOfCards;
                        currentWinner = j + 1; 
                        break;
                    }
                }
                printf("\nThere were no outright winners, so the players holding the lowest number of cards win: Player %d\n\n", currentWinner);
                for (i = 0; i < NUM_OF_PLAYERS; i++)
                {
                    if (i !=currentWinner && _players[i].numOfCards == lowestCardCount)
                    {
                        printf(" and Player %d", i);
                    }
                } 
                printf("!!");
                break;        
        }
    }

  4. #4
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    Quote Originally Posted by Amos Bordowitz View Post
    2. During each "match" I wnt to print the outcome. I've succeeded except that in one case - if player 4 attacks player 1, for some reason player 1's name doesn't appear. **
    Look at the following line of code:
    [code]matchResult = Match(attackerCard, _players[index], _players[index+1]);
    _players is an array of size NUM_OF_PLAYERS (4). Thus, valid indexes are 0..3. So if the attacking player is player 4, then index is 3. index+1 is 4, which is out of bounds, thus player 4 is constantly attacking player 5 who doesn't really exist, You correctly wrap index around: index = (i % 4); but you need to make sure you also wrap around index+1. My suggestion is to use two index variables, attacker_index and defender_index. defender_index will always be attacker_index+1 modulo number of players. Besides, it makes your code a bit more natural to read too, and readability is key.

    Quote Originally Posted by Amos Bordowitz View Post
    1. I'm trying to print all players "hands" (all the cards he has) at the end of each round (full circle from player 1 to 4). For some reason it sometimes does and sometimes doesn't and there doesn't seem to be a clear pattern. After 10th round it does work.. **
    Quote Originally Posted by Amos Bordowitz View Post
    3. this cannot be seen in a pleayer's hand - only when looking at all the "matches": even though there are 4 suits (which I've ENUMed but don't know how to actually print the ENUM so I represent them by number 1-4) once or twice a game suddenly there is a card with the suit number 65... **
    You should try printing all of the players cards right after you call Dealing. I think you'll find they're not what you expect.

    Also, your DiscardLeftShift + InternalSort functions are broken. You swap the discarded card out to the last used spot in PlayerCards, but then you sort it right back into the array. I think it's because your inner loop in the sort function goes one too far. For example, if numOfCards is 3, then j will take on values 0, 1 and 2 (the 3 valid cards for that player). So when j is 2, j+1 is 3 and you're comparing and possibly swapping in the card at j+1.

    You should really only call srand once, near the very beginning of main.

    Try those changes and see if you get any closer.

    Note, you should really learn to use a debugger. Also, Valgrind and Electric Fence library are useful.

    You should learn to unit test your code. This basically is the idea that you test and prove individual functions correct one at a time. Then, once they're all working, you can integrate them. This allows you to narrow the scope of your debugging to a single function instead of (like you were experiencing) "somewhere between the start and end of the program". For example, you should test your InternalSort function thoroughly on it's own, using a bunch of PlayerCards arrays that you made by hand. Make sure it only sorts the data you asked it to, not going out of bounds. Make sure it works if the data is already sorted, is reverse sorted, contains repeats, etc. When that's all working, you can "put away InternalSort", knowing that it works and will never be the source of your problems.

  5. #5
    Registered User
    Join Date
    Mar 2014
    Posts
    12
    wow thanks a lot!
    I will try your corrections and post my results later on.
    Much appreciated!

  6. #6
    Registered User
    Join Date
    Mar 2014
    Posts
    12
    OK -
    Fisrt off - the intrenal sort has been repaired and also the problem with "player 5"
    I still cannot figure out why it doesn't stop at the end of every round..
    this code, in my mind, should do the trick but for some reason it doesn't quite:
    Code:
        for (i = 0 ; i < (NUM_OF_PLAYERS * NUM_OF_ROUNDS) ; i++)    
        {
            attackerNum = (i % 4);
            defenderNum = (attackerNum + 1) % NUM_OF_PLAYERS;
            
            if ((attackerNum == 0) && (i > 0))
            {
                printf("************************************************************************************************\nEnd of round %d\n", (i / 4));
                printf("************************************************************************************************\n\n");
                Print(_players);
                getchar();
            }
    about the cards - If you look in the "main" you'll see that I DO print the cards right at the begining and there is absolutely no problem. The reason you might think I'm wrong is that during the rest of the game the cards are represented by a int-int sytem (suit 0-3, value 2-14, where 14 = ace, 13 = king etc.). So it looks different but it works. For some reason from time to time a junk figure still pops up :\
    There is another small bug but I'm pretty sure it stems from the same problem so I won't get into it.
    Suggestions? Sorry if I'm being difficult. I have tried solving with this with a debugger but I'm really brand new to the whole process..

  7. #7
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    Nah, I think you're wrong because some of your player card arrays have garbage values in them. But I wasn't really clear. I meant print the whole array (all DECK_SIZE cards) for each player, not just up to numOfCards. That gave me something like the following where for xx_yy_zz, xx is card number, yy is value and zz is suit.
    Code:
    name = Player 1, num cards = 13, winner = 0
    05_05_00  08_08_00  10_10_00  12_12_00  13_13_00  14_14_00  20_07_01  22_09_01
    23_10_01  34_08_02  37_11_02  46_07_03  47_08_03  00_00_00  00_00_00  00_00_00
    00_00_00  00_00_00  00_00_00  00_00_00  00_00_00  00_00_00  00_00_00  00_00_00
    00_00_00  00_00_00  00_00_00  00_00_00  00_00_00  00_00_00  00_00_00  00_00_00
    00_00_00  00_00_00  00_00_00  00_00_00  00_00_00  00_00_00  00_00_00  00_00_00
    00_00_00  00_00_00  00_00_00  00_00_00  00_00_00  00_00_00  00_00_00  00_00_00
    00_00_00  00_00_00  00_00_00  00_00_00
    name = Player 2, num cards = 13, winner = 0
    03_03_00  11_11_00  16_03_01  18_05_01  19_06_01  29_03_02  31_05_02  33_07_02
    35_09_02  43_04_03  44_05_03  49_10_03  50_11_03  00_00_00  00_00_00  00_00_00
    00_00_00  00_00_00  00_00_00  00_00_00  00_00_00  00_00_00  00_00_00  00_00_00
    00_00_00  00_00_00  00_00_00  00_00_00  00_00_00  00_00_00  00_00_00  00_00_00
    00_00_00  00_00_00  00_00_00  00_00_00  00_00_00  00_00_00  00_00_00  00_00_00
    00_00_00  00_00_00  00_00_00  00_00_00  00_00_00  00_00_00  00_00_00  00_00_00
    00_00_00  00_00_00  00_00_00  00_00_00
    name = Player 3, num cards = 13, winner = 0
    04_04_00  06_06_00  26_13_01  27_14_01  32_06_02  36_10_02  40_14_02  41_02_03
    42_03_03  45_06_03  48_09_03  52_13_03  53_14_03  626_01_1296449075  08_1296490436_-1216915848  1296493140_1296449075_08
    15_1296490436_1296407760  -1216915216_-1216915864_15
    Players 3 and 4 have 13 good cards then random junk instead of all zeros (and the all zeros for player 1 and 2 seem to be sheer luck). This was definitely a problem when your sort function was broken. I think it may still be a problem, since I'm noticing the following:
    Code:
    (gdb) p _players[attacker_index].PlayerCards
    $4 =   {{number = 0, value = 0, suit = Spade},
      {number = 4, value = 4, suit = Spade},
      {number = 5, value = 5, suit = Spade},
      {number = 6, value = 6, suit = Spade},
    That is showing that somehow, you are swapping in a bogus card into a used slot in player cards. So that is the reason cards sometimes don't show up. Your Print() function only prints valid cards, but if you get an invalid card in there, it prints nothing. And since it only prints numOfCards cards for each player, if some are invalid, the valid cards are not printed (they exist in PlayerCards beyond numOfCards index).

    I suspect your RightShift function. Look carefully at it and think about what those first two lines are doing -- especially in relation to eachother. What slot in the array do you insert the new card into? If you're not sure, work it out on paper.

  8. #8
    Registered User
    Join Date
    Mar 2014
    Posts
    12
    To the best of my knowledge - I have corrected all the problems ad the game works
    Thanks a million @anduril462! I have learned quite a lot through your comments!

  9. #9
    Registered User
    Join Date
    Mar 2014
    Posts
    12
    Nope, I was wrong..
    There are still 2 bugs and I cannot figure them out :\

    1. once or twice a game it suddenly skips a player.
    2. Almost after every round (after player 4 has played or forfeited his turn) it prints the "end of round" bit but not always. Plus after round 1 it will sometimes print it but not wait for the getchar()..
    I've tried with the debugger but cannot seem to get a handle on what I'm doing wrong.
    Last edited by Amos Bordowitz; 04-21-2014 at 05:42 AM.

  10. #10
    Registered User
    Join Date
    Mar 2014
    Posts
    12
    I wanted to edit the last message to add code but for some reason I can't so sorry for the multiple replies.
    I realized that after all the changes I made you will need the new code.

    signatures:
    Code:
    #ifndef CARDS_GAME_H
    #define CARDS_GAME_H
    
    #define CARDS_PER_SUIT 13
    #define DECK_SIZE 52
    #define NUM_OF_PLAYERS 4
    #define NUM_OF_SUITS 4
    #define NUM_OF_ROUNDS 20
    
    enum suits {Spade, Club, Diamond, Heart};
    
    typedef enum suits suits;
    
    struct Card    {
        int number;
        int value;    
        suits suit;
    };
    
    typedef struct Card Card;
    
    struct Player    {
        char name[20];
        int numOfCards;
        Card playerCards[DECK_SIZE];
        int winner;
    };
    
    typedef struct Player Player;
    
    Card * ShuffleCards (Card *);
    Player * Dealing (Player *, Card *);
    void Print (Player *);
    void PlayGame (Player * _player);
    int Match(Card _attackerCard, Player _attacker, Player _defender);
    void PlayGame (Player * _players);    
    
    #endif
    Main
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include "Cards_Signatures.h"
    
    int main(int argc, char **argv)    {
        int cont = 1;            
        int option;
        Card cards[DECK_SIZE];
        Card * cardsPtr = cards;
        Player players[NUM_OF_PLAYERS] = {0};
        Player * playersPtr = players;
        
        while (cont) 
        {
            printf("Choose option: \n");
            printf("1: Play  \n");
            printf("Any other nuber - Quit \n");
            
            scanf("%d", &option);
            switch (option) {
                case 1:
                    system("clear");
                    cardsPtr = ShuffleCards (cards);
                    playersPtr = Dealing (playersPtr, cardsPtr);
                    Print (players);    
                    PlayGame (playersPtr);
                    getchar();
                    break;
                    
                default: 
                    cont = 0;    
                    break;
            }
        putchar('\n');
        }
        
        return 0;
    }
    functions
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <time.h>
    #include "Cards_Signatures.h"
    
    Player * SortCards (Player*, int, int);
    void PrintSuit (Player*, int, int);    
    
    Card * ShuffleCards (Card * _cards)    
    {
        int cardsArray[DECK_SIZE];
        int i;
        int place;
        
        for (i = 0 ; i < DECK_SIZE ; i++)    
        {
            cardsArray[i] = 0;
        }
        
        i = 2;
        srand(time(NULL));
        while (i < DECK_SIZE + 2)    
        {
            place = rand() % DECK_SIZE;
            if (cardsArray[place] == 0)    
            {
                cardsArray[place] = i;
                i++;
            }
        }
        
        for (i = 0 ; i < DECK_SIZE ; i++)    
        {
            _cards[i].number = cardsArray[i];
            _cards[i].value = (cardsArray[i] - 2) % CARDS_PER_SUIT + 2;
            _cards[i].suit = (cardsArray[i] - 2) / CARDS_PER_SUIT;
            
        }
        
        return _cards;
    }
    
    Player * Dealing (Player * _players, Card * _cardsArray)    
    {
        int i;
        
        for (i = 0 ; i < NUM_OF_PLAYERS ; i++)    
        {
            _players[i].numOfCards = CARDS_PER_SUIT;
        }
            
        for (i = 0 ; i < DECK_SIZE ; i++)    
        {
            _players[i % NUM_OF_PLAYERS].playerCards[i / NUM_OF_PLAYERS].number = _cardsArray[i].number;
            _players[i % NUM_OF_PLAYERS].playerCards[i / NUM_OF_PLAYERS].value = _cardsArray[i].value;
            _players[i % NUM_OF_PLAYERS].playerCards[i / NUM_OF_PLAYERS].suit = _cardsArray[i].suit;
        }
            
        for (i = 0 ; i < NUM_OF_PLAYERS ; i++)    
        {
            _players = SortCards(_players, _players[i].numOfCards, i);
            sprintf(_players[i].name, "Player %d", i + 1);
        }
    
        return _players;
    }
    
    void Print (Player * _players)    
    {
        int i;
        
        for (i = 0 ; i < NUM_OF_PLAYERS ; i++)    
        {
            putchar('\n');
            printf("Player %d cards are:\n\n", i + 1);
            printf("Spades: ");
            PrintSuit(_players, i, 0);
            putchar('\n');
            printf("Clubs: ");
            PrintSuit(_players, i, 1);
            putchar('\n');
            printf("Diamonds: ");
            PrintSuit(_players, i, 2);
            putchar('\n');
            printf("Hearts: ");
            PrintSuit(_players, i, 3);    
            putchar('\n');
            putchar('\n');
            
        }
    }
    
    void PrintSuit (Player * _players, int i, int suit)    
    {
        int j;
        
        for (j = 0 ; j < _players[i].numOfCards ; j++)    
        {
            if (_players[i].playerCards[j].suit == suit)    
            {
                if (_players[i].playerCards[j].value > 1 && _players[i].playerCards[j].value < 10)
                    printf ("%d ", _players[i].playerCards[j].value);
                if (_players[i].playerCards[j].value == 10)
                    printf ("T ");
                if (_players[i].playerCards[j].value == 11)
                    printf ("J ");
                if (_players[i].playerCards[j].value == 12)
                    printf ("Q ");
                if (_players[i].playerCards[j].value == 13)
                    printf ("K ");
                if (_players[i].playerCards[j].value == 14)
                    printf ("A ");
            }
        }
    }
        
    Player * SortCards (Player * _players, int _n, int _numOfPlayer)    
    {
        int i,j;
        Card temp;
        
        for (i = 1 ; i < _n ; i++)    
        {
            for (j = i ; j > 0 ; j--)    
            {
                if (_players[_numOfPlayer].playerCards[j].number < _players[_numOfPlayer].playerCards[j - 1].number)    
                {
                    temp = _players[_numOfPlayer].playerCards[j];
                    _players[_numOfPlayer].playerCards[j] = _players[_numOfPlayer].playerCards[j - 1];
                    _players[_numOfPlayer].playerCards[j - 1] = temp;
                }
                else    
                {
                    break;
                }
            }     
        }
        
        return _players;
    }
    
    int Match(Card _attackerCard, Player _attacker, Player _defender)
    {
        int i;
        printf("\n%s attacks with card %d-%d. ", _attacker.name, _attackerCard.suit +1, _attackerCard.value);
        for (i = _defender.numOfCards - 1; i >= 0; i--)
        {
            if (((_attackerCard.suit == ((_defender.playerCards)[i]).suit)))
            {
                if (((_attackerCard.value < ((_defender.playerCards)[i]).value)))
                {
                    printf("%s defends with card %d-%d\n", _defender.name, _defender.playerCards[i].suit +1, _defender.playerCards[i].value);
                    return i; /* Second player won the match. Returnes number of card in player's hand */
                }
            }
        }
        printf("%s couldn't counter and loses his turn!!\n", _defender.name);
        printf("\n%s forfeits!!\n", _defender.name);
        return 0; /* First player won the match */
    }
    
    Player InternalSort(Player _player)
    {
        int i,j;
        Card temp;
    
        for (i = _player.numOfCards - 1; i > 0; i--)
        {
            for (j = 0; j < _player.numOfCards - 1; j++)
            {
                if (((_player.playerCards[j].number > _player.playerCards[j + 1].number)))
                {
                    temp = ((_player.playerCards)[j]);
                    (_player.playerCards)[j] = (_player.playerCards)[j + 1];
                    (_player.playerCards)[j + 1] = temp;
                } 
            
            }
        }
        
        return _player;
    }
    
    Player DiscardLeftShift(Player _player, Card _attackerCard)
    {
        int i, place;
        Card temp;
        place = _player.numOfCards - 1;
    
        for (i = 0; i < place - 1; i++)
        {
            if (_attackerCard.number == ((_player.playerCards)[i]).number)
            {
                temp = (_player.playerCards)[place];
                (_player.playerCards)[place] = (_player.playerCards)[i];
                (_player.playerCards)[i] = temp;
                break;
            }
        }
        
        if (_player.numOfCards > 0)
        {
            (_player.numOfCards)--;
        }
        place = _player.numOfCards;
        _player = InternalSort(_player);
        
        return _player;
    }
    
    Player RightShift(Player _player, Card _card)
    {
        _player.numOfCards++;
        _player.playerCards[_player.numOfCards - 1] = _card;
        
        _player = InternalSort(_player);
        
        return _player;
    }
    
    void PlayGame (Player * _players)    
    {
        int i, j, lowestCardCount, currentWinner;
        int attackerNum = 0;
        int defenderNum = 0;
        int matchResult = 0;                
        int winNumber = 0;                    /* '0' - nobody won, '1' - first won, '2' - second won. '3' - both players won */
        Card attackerCard;
        lowestCardCount = 0;
        currentWinner = 0;
        
        system("clear");
    
        for (i = 0 ; i < (NUM_OF_PLAYERS * NUM_OF_ROUNDS) ; i++)    
        {
            attackerNum = (i % 4);
            defenderNum = (attackerNum + 1) % NUM_OF_PLAYERS;
            
            if ((attackerNum == 0) && (i > 0))
            {
                printf("************************************************************************************************\nEnd of round %d\n", (i / 4));
                printf("************************************************************************************************\n\n");
                putchar('\n');
                printf("Here are the players hand at the end of the round: \n");
                Print(_players);
                getchar();
            }
            
            /*printf("%s number of cards %d\n",_players[attackerNum].name, _players[attackerNum].numOfCards);*/
            attackerCard = (_players[attackerNum].playerCards[rand() % _players[attackerNum].numOfCards]);
            matchResult = Match(attackerCard, _players[attackerNum], _players[defenderNum]);
            
            if (matchResult == 0) /* First (attacking) player won the match */
            {
                _players[attackerNum] = DiscardLeftShift(_players[attackerNum], attackerCard); 
                _players[defenderNum] = RightShift(_players[defenderNum], attackerCard); 
                i++;
            }
            else /* Second (defending) player won the match */
            {
                _players[attackerNum] = DiscardLeftShift(_players[attackerNum], attackerCard); 
                _players[defenderNum] = DiscardLeftShift(_players[defenderNum], _players[defenderNum].playerCards[matchResult]);            
            }
            if (((_players[attackerNum].numOfCards) == 0) && (_players[defenderNum].numOfCards) > 0)
            {
                printf("break1");
                winNumber = 1;
                break;
            }
                    
            if (((_players[attackerNum].numOfCards) > 0) && (_players[defenderNum].numOfCards) == 0)
            {
                printf(" break2 ");
                winNumber = 2;
                break;
            }
            
            if (((_players[attackerNum].numOfCards) == 0) && (_players[defenderNum].numOfCards) == 0)
            {
                printf("break3");
                winNumber = 3;
                break;
            }
            
            
        }
        
        switch (winNumber)
        {
            case(1):
                printf("\nPlayer %d won!!", attackerNum + 1);
                break;
            case(2):
                printf("\nPlayer %d won!!", defenderNum +1);
                break;
            case(3):
                printf("\nPlayers %d and %d won together! Hooray for partnership, good will and stuff!\n\n", attackerNum +1 , defenderNum + 1);
                break;
            case(0):
                for (j = 0; j < NUM_OF_PLAYERS; j++)
                {
                    if (_players[j + 1].numOfCards < _players[attackerNum].numOfCards)
                    {
                        lowestCardCount = _players[j + 1].numOfCards;
                        currentWinner = j + 1; 
                        break;
                    }
                }
                printf("\nThere were no outright winners, so the players holding the lowest number of cards win: Player %d\n\n", currentWinner);
                for (i = 0; i < NUM_OF_PLAYERS; i++)
                {
                    if (i !=currentWinner && _players[i].numOfCards == lowestCardCount)
                    {
                        printf(" and Player %d", i);
                    }
                } 
                printf("!!");
                break;        
        }
    }

  11. #11
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    I'm going to answer things out of order. First, there is a 1-hour edit limit on posts. After an hour, you can no longer edit, you must make a new post.
    Quote Originally Posted by Amos Bordowitz View Post
    Plus after round 1 it will sometimes print it but not wait for the getchar()..
    This one at least, should be pretty easy -- at least, I think this is it, but I haven't tried/tested. Read FAQ > How do I avoid a "dangling" newline when reading single character user input? - Cprogramming.com and FAQ > Flush the input buffer - Cprogramming.com.
    Quote Originally Posted by Amos Bordowitz View Post
    1. once or twice a game it suddenly skips a player.
    Quote Originally Posted by Amos Bordowitz View Post
    2. Almost after every round (after player 4 has played or forfeited his turn) it prints the "end of round" bit but not always.
    Well, you print the "End of round" message when attackerNum is 0 and i > 0. i is always greater than 0 (except the first time), so it's not that condition that is causing it to be skipped. It must be attackerNum skipping over 0. Let's take a look:
    Code:
        for (i = 0 ; i < (NUM_OF_PLAYERS * NUM_OF_ROUNDS) ; i++)  // increments i every time through the loop
        {
            attackerNum = (i % 4);
            defenderNum = (attackerNum + 1) % NUM_OF_PLAYERS;
    
    
            if ((attackerNum == 0) && (i > 0))
            {
                printf("*******************************************************************\nEnd of round %d\n", (i / 4));
                printf("*******************************************************************\n");
                //putchar('\n');
                printf("Here are the players hand at the end of the round: \n");
                Print(_players);
                getchar();
            }
    
    
            /*printf("%s number of cards %d\n",_players[attackerNum].name, _players[attackerNum].numOfCards);*/
            attackerCard = (_players[attackerNum].playerCards[rand() % _players[attackerNum].numOfCards]);
            matchResult = Match(attackerCard, _players[attackerNum], _players[defenderNum]);
    
    
            if (matchResult == 0) /* First (attacking) player won the match */
            {
                _players[attackerNum] = DiscardLeftShift(_players[attackerNum], attackerCard);
                _players[defenderNum] = RightShift(_players[defenderNum], attackerCard);
                i++;  // also increments i when a player wins
            }
    attackerNum is defined as i % 4. That is basically turn_number % NUM_OF_PLAYERS (which is probably how your code should read -- change i to turn_number and use NUM_OF_PLAYERS instead of a literal 4).

    So, when the attacking player wins, you increment i, but it gets incremented a second time when the loop repeats. That effectively causes a turn-skip (defender loses), but also causes it to skip the end of turn message. I would suggest that, instead of incrementing turn_number when matchResult is 0, you set a flag called something like skip_turn, and check it right after the "End of round" message.
    Code:
    int skip_turn = 0;
    for (turn_number = 0; ...; turn_number++)
    {
        set attacker & defender nums
        if (end of turn)
            print message
        if skip_turn
            continue;
        do match
        if matchResult is 0
            left/right shift cards
            skip_turn = 1
    That will keep your turn counting in sync, but still let you print a message and skip a turn. Note, it is always* better to simply use an extra variable (especially when you can give it a meaningful name that makes your code clearer) instead of trying to use a single variable for two purposes and cluttering up the logic.

    NOTE: The skip_turn flag may fix both of the above errors. I didn't see the random turn skipping before or after my changes, so it's hard for me to say for sure.

    * Of course, there are exceptions, such as highly resource-constrained systems like small embedded devices, where extra variables can be problematic.

  12. #12
    Registered User
    Join Date
    Mar 2014
    Posts
    12
    You are amazing!
    I can't believe how much patience you have.
    Thanks a lot

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Card game, having a problem with strings.
    By atac in forum C Programming
    Replies: 4
    Last Post: 06-15-2013, 12:42 PM
  2. Problem with simple Mastermind game(beginner)
    By newbie2012 in forum Game Programming
    Replies: 1
    Last Post: 11-12-2012, 03:51 AM
  3. Card game war
    By Dr Saucie in forum C Programming
    Replies: 3
    Last Post: 02-11-2010, 11:25 PM
  4. Card game help
    By aaroroge in forum Game Programming
    Replies: 9
    Last Post: 07-16-2005, 06:37 PM
  5. Simple memory game problem
    By Eamusuta in forum C++ Programming
    Replies: 2
    Last Post: 06-21-2005, 07:59 AM

Tags for this Thread