Home > Back-end >  War Card Game in C, Implementing Linked Lists, Segmentation Error when shuffling deck and distributi
War Card Game in C, Implementing Linked Lists, Segmentation Error when shuffling deck and distributi

Time:03-16

I am having a couple problems with this code that I am working on for a school assignment. I was wondering if anyone with more experience can point me towards the errors in my code so I can fix them. At this point I am trying to shuffle the deck using rand() (My professor instructed us to do so) and move the card from the linked List for the deck into the players hand. Unfortunately I also get segmentation errors. The debugger points the error towards the insertBackDeck() function. I have posted both the full function below and the playRound() and insertBackDeck() that messes me up.

//Name:
//Dr. Steinberg
//COP3502 Spring 2022
//Programming Assignment 3 Skeleton

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

typedef struct card_s{
    int rank;    //number
    char * type; //type of card
    struct card_s * nextptr;
}card_t;

//function prototypes
void rules(); //display rules
int playRound(); //simulate round
card_t * openCardDeck(); //open the card deck and place into a linkedlist setup
card_t * insertBackSetup(card_t *node, char *name, int cardrank); //take card from orginial deck and place in back of linked list for setup of game
int empty(card_t * node); //check to see if linked list is empty
void cleanUp(card_t * head); //free memory to prevent memory leaks
int deckSize(card_t * head); //count number of nodes in the linked list
card_t * search(card_t * node, int spot); //search list for a specific spot in the card deck indexing is similar to array setup
card_t * copyCard(card_t * node); //make a deep copy of card
card_t * removeCard(card_t * node, int spot); //remove card from linkedlist
card_t * insertBackDeck(card_t *head, card_t *node); //place card at end of pile
int compareCard(card_t * cardp1, card_t * cardp2); //compare cards
card_t * moveCardBack(card_t *head); //place card at top of deck to the bottom of the deck

int main()
{
    int seed;
    printf("Enter Seed: ");
    scanf("%d", &seed);
    
    srand(seed); //seed set
    rules();
    
    int player; //1 or 2
    int result;
    
    printf("Would you like to be player 1 or 2?\n");
    printf("Enter 1 or 2: ");
    scanf("%d", &player); //choose player
    
    for(int game = 1; game <= 5;   game) //simulate games
    {
        printf("Alright lets play game %d.\n", game);
        printf("Lets split the deck.\n");

        result = playRound(); //play game
        
        if((result == 1 && player == 1) || (result == 2 && player == 2)) //determine who won
            printf("You won game %d.\n", game);
        else
            printf("I won game %d.\n", game);
    }
    
    return 0;
}

void rules()
{
    printf("Welcome to the card game war!\n");
    printf("Here are the rules.\n");
    printf("You have a pile of cards and I have a pile of cards.\n");
    printf("We will each pull the top card off of our respective deck and compare them.\n");
    printf("The card with the highest number will win the round and take both cards.\n");
    printf("However if there is a tie, then we have to we have to place one card faced down and the next one faced up and compare the results.\n");
    printf("Winner of the tie, will grab all the cards out. However if it's a tie again, then we repeat the same action.\n");
    printf("Ready? Here we go!\n");
}

int playRound()
{
    card_t *head = openCardDeck();
    card_t *p1Deck = NULL;
    card_t *p2Deck = NULL;
    //card_t *temp;
    printf("There are %d cards in the deck.", deckSize(head));
    while(deckSize(head) != 0)
    {
        int spot = rand() % deckSize(head);
        insertBackDeck(p1Deck, copyCard(search(head, spot)));
        head = removeCard(head, spot);
        spot = rand() % deckSize(head);
        insertBackDeck(p2Deck, copyCard(search(head, spot)));
        head = removeCard(head, spot);
        //printf("Player 1 pulled %s",p1Deck->type);
    }
    printf("Test");
    return 1;
}

card_t * openCardDeck()
{
    FILE *fptr = fopen("deck.txt", "r");
    
    char *name = (char *) malloc(sizeof(char) * 20);
    
    if (name == NULL)
    {
        printf("Error in malloc...\n");
        exit(1);
    }
    
    card_t * head = NULL;
    
    int cardrank = 13;
    int tracker = 1;
    while(fscanf(fptr, "%s", name) == 1)
    {           
        strcat(name, " ");
        
        if(tracker % 5 == 1)
        {
            strcat(name, "of Clubs");
            head = insertBackSetup(head, name, cardrank);
        }
        else if(tracker % 5 == 2)
        {
            strcat(name, "of Diamonds");
            head = insertBackSetup(head, name, cardrank);
        }
        else if(tracker % 5 == 3)
        {
            strcat(name, "of Hearts");
            head = insertBackSetup(head, name, cardrank);
        }
        else if(tracker % 5 == 4)
        {
            strcat(name, "of Spades");
            head = insertBackSetup(head, name, cardrank);
            tracker = 0;
            --cardrank;
        }
        
          tracker;
        
    }
    
    free(name);
    fclose(fptr);
    
    return head;
}

card_t * insertBackSetup(card_t *node, char *name, int cardrank)
{
    
    if(empty(node)) //check to see if list is empty
    {
        node = (card_t *) malloc(sizeof(card_t));
        
        if(empty(node)) //check to see if malloc worked
        {
            printf("Did not allocate head successfully...");
            printf("Program Terminating...\n");
            exit(1);
        }
        else //otherwise populate data of new head node
        {
            node->type = (char *) malloc(sizeof(char) * 20);
            
            if(node->type == NULL)
            {
                printf("Error with malloc...\n");
                exit(1);
            }
            
            strcpy(node->type, name);
            node->rank = cardrank;
            node->nextptr = NULL; //must make new tail nextptr NULL!!!
            
            return node;  //terminate
        }
      
    }
    
    //here we know that the list has at least one node
    
    card_t *head = node; //keep pointer to head since we will need to return this address
    
    while(node->nextptr != NULL) //traverse to tail
        node = node->nextptr;
    
    node->nextptr = (card_t *) malloc(sizeof(card_t)); 
    
    if(node->nextptr == NULL) //see if new tail was allocated successfully
    {
        printf("Did not allocate node successfully...");
        return head; //terminate if tail didn't get created
    }
    
    //populate new node
    node->nextptr->type = (char *) malloc(sizeof(char) * 20);
    
    if(node->nextptr->type == NULL)
    {
        printf("Error with malloc...\n");
        exit(1);
    }
    
    strcpy(node->nextptr->type, name); // THIS IS KHAN'S ASSIGNMENTS HOWD YOU GET IT
    node->nextptr->rank = cardrank;
    node->nextptr->nextptr = NULL; //very important
            
    return head; //return head node since we need our starting point of the linked list
}

int empty(card_t * node)
{
    return (node == NULL); //return condition result
}

void cleanUp(card_t * head)
{
    card_t* temp;
    while(head->nextptr != NULL)
    {
        temp = head;
        head = head->nextptr;
        free(temp);
    }
    
}

int deckSize(card_t * head)
{
    int count = 0;
    card_t* temp;
    temp = head;
    while(temp != NULL)
    {
        temp = temp->nextptr;
        count  ;
    }
    return count;
}


card_t * search(card_t * node, int spot)
{
    int i = 0;
    card_t *temp = node;
    while(temp != NULL)
    {
        if(i == spot)
            return temp;
        i  ;
        temp = temp->nextptr;
    }
    printf("error");
    return node;
}

card_t * copyCard(card_t * node)
{
    if(node == NULL)
        return NULL;
    card_t* copy = (card_t*)malloc(sizeof(card_t));
    copy->nextptr = NULL;
    copy->rank = node->rank;
    copy->type = (char*)malloc(sizeof(char) * (strlen(node->type)   1));
    strcpy(copy->type, node->type);
    return copy;
}

card_t * removeCard(card_t * node, int spot)
{
    if(empty(node))
        return NULL;
    card_t * head = node;
    card_t * temp = search(node, spot);
    if(temp == NULL)
        return head;
    if(head == temp)
    {
        head = head->nextptr;
        free(temp);
        return head;
    }
    while(head->nextptr != temp)
        head = head->nextptr;
    head->nextptr = temp->nextptr;
    free(temp);
    return head;
}

card_t * insertBackDeck(card_t *head, card_t *node)
{
    if(head == NULL)
    {
        head = node;
        head->nextptr = NULL;
        return head;
    }   
    card_t * temp;
    temp = head;
    while(temp != NULL)
    {
        temp = temp->nextptr;
    }
    temp = node;
    return head;
}

int compareCard(card_t * cardp1, card_t * cardp2)
{
    if(cardp1 == NULL && cardp2 != NULL)
        return 2;
    if(cardp1 != NULL && cardp2 == NULL)
        return 1;
    if(cardp1 == NULL && cardp2 == NULL)
        return 0;
    if(cardp1->rank == cardp2->rank)
        return 0;
    if(cardp1->rank > cardp2->rank)
        return 1;
    if(cardp1->rank< cardp2->rank)
        return 2;
    return 3;
}

card_t * moveCardBack(card_t *head)
{
    if(head == NULL)
        return NULL;
    card_t *front = head; card_t *last = head;
    while(last->nextptr != NULL)
        last = last->nextptr;
    last->nextptr = head;
    head = front->nextptr;
    front->nextptr = NULL;
    return head;
}

EDIT: I updated the code and posted it below. The error I get is when I use the printf.

//Name:
//Dr. Steinberg
//COP3502 Spring 2022
//Programming Assignment 3 Skeleton

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

typedef struct card_s{
    int rank;    //number
    char * type; //type of card
    struct card_s * nextptr;
}card_t;

//function prototypes
void rules(); //display rules
int playRound(); //simulate round
card_t * openCardDeck(); //open the card deck and place into a linkedlist setup
card_t * insertBackSetup(card_t *node, char *name, int cardrank); //take card from orginial deck and place in back of linked list for setup of game
int empty(card_t * node); //check to see if linked list is empty
void cleanUp(card_t * head); //free memory to prevent memory leaks
int deckSize(card_t * head); //count number of nodes in the linked list
card_t * search(card_t * node, int spot); //search list for a specific spot in the card deck indexing is similar to array setup
card_t * copyCard(card_t * node); //make a deep copy of card
card_t * removeCard(card_t * node, int spot); //remove card from linkedlist
card_t * insertBackDeck(card_t *head, card_t *node); //place card at end of pile
int compareCard(card_t * cardp1, card_t * cardp2); //compare cards
card_t * moveCardBack(card_t *head); //place card at top of deck to the bottom of the deck

int main()
{
    int seed;
    printf("Enter Seed: ");
    scanf("%d", &seed);
    
    srand(seed); //seed set
    rules();
    
    int player; //1 or 2
    int result;
    
    printf("Would you like to be player 1 or 2?\n");
    printf("Enter 1 or 2: ");
    scanf("%d", &player); //choose player
    
    for(int game = 1; game <= 5;   game) //simulate games
    {
        printf("Alright lets play game %d.\n", game);
        printf("Lets split the deck.\n");

        result = playRound(); //play game
        
        if((result == 1 && player == 1) || (result == 2 && player == 2)) //determine who won
            printf("You won game %d.\n", game);
        else
            printf("I won game %d.\n", game);
    }
    
    return 0;
}

void rules()
{
    printf("Welcome to the card game war!\n");
    printf("Here are the rules.\n");
    printf("You have a pile of cards and I have a pile of cards.\n");
    printf("We will each pull the top card off of our respective deck and compare them.\n");
    printf("The card with the highest number will win the round and take both cards.\n");
    printf("However if there is a tie, then we have to we have to place one card faced down and the next one faced up and compare the results.\n");
    printf("Winner of the tie, will grab all the cards out. However if it's a tie again, then we repeat the same action.\n");
    printf("Ready? Here we go!\n");
}

int playRound()
{
    card_t *head = openCardDeck();
    card_t *p1Deck = NULL;
    card_t *p2Deck = NULL;
    int deckSized = deckSize(head);
    printf("There are %d cards in the deck.", deckSized);
    while(deckSized != 0)
    {
        int spot = rand() % deckSized;
        insertBackDeck(p1Deck, search(head, spot));
        head = removeCard(head, spot);
        deckSized--;
        spot = rand() % deckSized;
        insertBackDeck(p2Deck, search(head, spot));
        head = removeCard(head, spot);
        deckSized--;
        printf("Player 1 pulled %s",p1Deck->type);
    }
    printf("Test");
    return 1;
}

card_t * openCardDeck()
{
    FILE *fptr = fopen("deck.txt", "r");
    
    char *name = (char *) malloc(sizeof(char) * 20);
    
    if (name == NULL)
    {
        printf("Error in malloc...\n");
        exit(1);
    }
    
    card_t * head = NULL;
    
    int cardrank = 13;
    int tracker = 1;
    while(fscanf(fptr, "%s", name) == 1)
    {           
        strcat(name, " ");
        
        if(tracker % 5 == 1)
        {
            strcat(name, "of Clubs");
            head = insertBackSetup(head, name, cardrank);
        }
        else if(tracker % 5 == 2)
        {
            strcat(name, "of Diamonds");
            head = insertBackSetup(head, name, cardrank);
        }
        else if(tracker % 5 == 3)
        {
            strcat(name, "of Hearts");
            head = insertBackSetup(head, name, cardrank);
        }
        else if(tracker % 5 == 4)
        {
            strcat(name, "of Spades");
            head = insertBackSetup(head, name, cardrank);
            tracker = 0;
            --cardrank;
        }
        
          tracker;
        
    }
    
    free(name);
    fclose(fptr);
    
    return head;
}

card_t * insertBackSetup(card_t *node, char *name, int cardrank)
{
    
    if(empty(node)) //check to see if list is empty
    {
        node = (card_t *) malloc(sizeof(card_t));
        
        if(empty(node)) //check to see if malloc worked
        {
            printf("Did not allocate head successfully...");
            printf("Program Terminating...\n");
            exit(1);
        }
        else //otherwise populate data of new head node
        {
            node->type = (char *) malloc(sizeof(char) * 20);
            
            if(node->type == NULL)
            {
                printf("Error with malloc...\n");
                exit(1);
            }
            
            strcpy(node->type, name);
            node->rank = cardrank;
            node->nextptr = NULL; //must make new tail nextptr NULL!!!
            
            return node;  //terminate
        }
      
    }
    
    //here we know that the list has at least one node
    
    card_t *head = node; //keep pointer to head since we will need to return this address
    
    while(node->nextptr != NULL) //traverse to tail
        node = node->nextptr;
    
    node->nextptr = (card_t *) malloc(sizeof(card_t)); 
    
    if(node->nextptr == NULL) //see if new tail was allocated successfully
    {
        printf("Did not allocate node successfully...");
        return head; //terminate if tail didn't get created
    }
    
    //populate new node
    node->nextptr->type = (char *) malloc(sizeof(char) * 20);
    
    if(node->nextptr->type == NULL)
    {
        printf("Error with malloc...\n");
        exit(1);
    }
    
    strcpy(node->nextptr->type, name); // THIS IS KHAN'S ASSIGNMENTS HOWD YOU GET IT
    node->nextptr->rank = cardrank;
    node->nextptr->nextptr = NULL; //very important
            
    return head; //return head node since we need our starting point of the linked list
}

int empty(card_t * node)
{
    return (node == NULL); //return condition result
}

void cleanUp(card_t * head)
{
    card_t* temp;
    while(head->nextptr != NULL)
    {
        temp = head;
        head = head->nextptr;
        free(temp);
    }
    
}

int deckSize(card_t * head)
{
    int count = 0;
    card_t* temp;
    temp = head;
    while(temp != NULL)
    {
        temp = temp->nextptr;
        count  ;
    }
    return count;
}


card_t * search(card_t * node, int spot)
{
    int i = 0;
    card_t *temp = node;
    while(temp != NULL)
    {
        if(i == spot)
            return temp;
        i  ;
        temp = temp->nextptr;
    }
    printf("error");
    return node;
}

card_t * copyCard(card_t * node)
{
    if(node == NULL)
        return NULL;
    card_t* copy = (card_t*)malloc(sizeof(card_t));
    copy->nextptr = NULL;
    copy->rank = node->rank;
    copy->type = (char*)malloc(sizeof(char) * (strlen(node->type)   1));
    strcpy(copy->type, node->type);
    return copy;
}

card_t * removeCard(card_t * node, int spot)
{
    if(empty(node))
        return NULL;
    card_t * head = node;
    card_t * temp = search(node, spot);
    if(temp == NULL)
        return head;
    if(head == temp)
    {
        head = head->nextptr;
        free(temp);
        return head;
    }
    while(head->nextptr != temp)
        head = head->nextptr;
    head->nextptr = temp->nextptr;
    free(temp);
    return node;
}

card_t * insertBackDeck(card_t *head, card_t *node)
{
    card_t *newCard = copyCard(node);
    if(head == NULL)
    {
        head = newCard;
        head->nextptr = NULL;
        return head;
    }   
    card_t * temp;
    temp = head;
    while(temp != NULL)
    {
        temp = temp->nextptr;
    }
    temp = newCard;
    return head;
}

int compareCard(card_t * cardp1, card_t * cardp2)
{
    if(cardp1 == NULL && cardp2 != NULL)
        return 2;
    if(cardp1 != NULL && cardp2 == NULL)
        return 1;
    if(cardp1 == NULL && cardp2 == NULL)
        return 0;
    if(cardp1->rank == cardp2->rank)
        return 0;
    if(cardp1->rank > cardp2->rank)
        return 1;
    if(cardp1->rank< cardp2->rank)
        return 2;
    return 3;
}

card_t * moveCardBack(card_t *head)
{
    if(head == NULL)
        return NULL;
    card_t *front = head; card_t *last = head;
    while(last->nextptr != NULL)
        last = last->nextptr;
    last->nextptr = head;
    head = front->nextptr;
    front->nextptr = NULL;
    return head;
}

This is the deck.txt

Ace
Ace
Ace
Ace
King
King
King
King
Queen
Queen
Queen
Queen
Jack
Jack
Jack
Jack
10
10
10
10
9
9
9
9
8
8
8
8
7
7
7
7
6
6
6
6
5
5
5
5
4
4
4
4
3
3
3
3
2
2
2
2

CodePudding user response:

my compiler immediately complains about this

card_t *head = openCardDeck();
card_t *p1Deck;  <<<<<<<<<<<<<=========================
card_t *p2Deck;
card_t *temp;
printf("There are %d cards in the deck.", deckSize(head));
int deckSized = deckSize(head);
while(deckSized != 0)
{
    int spot = rand() % deckSized;
    insertBackDeck(p1Deck, search(head, spot)); <<<<<<<==========

p1Deck is unititlaized. You need

     card_t* p1Deck = NULL;

likewise you have

int deckSize(card_t* head)
{
    int count; <<<<===============================
    card_t* temp;
    temp = head;
    while (temp != NULL)
    {
        temp = temp->nextptr;
        count  ;
    }
    return count;
}

also 'search' doesnt return a value. Nor does 'campareCard' or 'playRound'

All these were errors or warnings from my compiler. Pay attention to the messages from the compiler, it is trying to help you

CodePudding user response:

Ok in playRound you do this

 insertBackDeck(p1Deck, search(head, spot));

you are clearly hoping that insertBackDeck will update p1Deck because you use it a few lines later (it was NULL)

  printf("Player 1 pulled %s", p1Deck->type);

In fact insertBAckDeck return a new valid card pointer but you ignore it.

You need to do

 p1Deck = insertBackDeck(p1Deck, search(head, spot));

Alternatively, you could have had insertBAckDeck update p1Deck in place by passing it using 'c style pass by reference'

But mainly - learn to use your debugger. A program this size is hard to debug without one, it is very simple using a debugger

anyway when I fix that it runs to the end and produces lots of text, dont know if its correct

  • Related