Search code examples
cdice

Advanced Dice game in C


Before I post the code there are two things I should mention, 1 there is a text file that works in link with this code that I will post the few details in the post. 2, I'm nearly done with this project of mine so I'm only really focused on the topFive() function and the topWin() function. My issue though is when I try to get the top five players in this function it only prints out one name five times. I'd really appreciate any help, very stumped!

Here are the players.txt file's contents followed by the code.

Peter   100 90  
Emma    150 0   
Richard 50  10  
Abigail 138 128 
Jacob   210 100 
Anthony 800 -10 
Joseph  328 62  
Ashley  89  16  
Hannah  197 7   
Ethan   11  -20 



#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
typedef struct { 
    char pl_name[10];
    int balance;
    int wincount;
} plyr;
plyr pl[10];
plyr top[5];
int psearch(){ // finds the index of the name in the file
    int i;
    char name[20];//This creates the initial array that searches throughout the array for the users name variable identity.
    printf("Enter the user's name. ");
    scanf("%s", name); // This will ask the user for the name whos balance they are changing.
    for(i=0;i<10;){
    if (strcmp(&name, pl[i].pl_name) == 0 ) break;
    i++; //This will continue the search.
    }
    return i;
}
void topBalance(){ // finds the top balance for 5 players
    int i;
    printf("What is the player name? ");
    scanf("%s", pl[i].pl_name); // This basically takes a users name and is ready to edit it.
    printf("What's the balance? ");
    scanf("%d", &pl[i].balance); // This changes whatever name is enters balance to whatever it wants to change it to.

}
void playGame(){ //Needs correction.
    srand(time(0));
    char enter = 'i'; 
    int r1, r2, sum, point;
    int playerno = psearch();
    char again = 'y';
    while (playerno == 10) { // This ensures that there are only 10 players that are going to be searched throughout.
        printf("Players not found.\n");
        playerno = psearch();   
    }
    while(again == 'y'){
        for(;;) {
            printf("Press enter to roll the dice. ");
            getchar(); // This will continue the dice to be rolled past the original point of just one or two rolls
            while (enter != '\n')
                enter = getchar();
            r1 = (rand() % 6) + 1; // This acts as the math of the function and it takes a random integer and divides it by 6 and takes the remainder by 1.
            r2 = (rand() % 6) + 1;
            sum = r1 + r2;
            printf("You got a %d and %d from the roll, the sum is %d. \n", r1, r2, sum);
            if(sum == 7 || sum == 11) {
                pl[playerno].balance += 10;
                pl[playerno].wincount += 10;
                printf("Your new balance is %d. \n", pl[playerno].balance);
                break;
            }
            else if(sum == 2 || sum == 3 || sum == 12){
                pl[playerno].balance -= 1; // This is anoyher simple way to lose if the sum is only equal to 2 or 3.
                pl[playerno].wincount -= 1;
                printf("You lose with a balance of %d", pl[playerno].balance);
                break; // The basic loss variable in the play game function.
                }
            else {
                point = sum;
                printf("Your point is %d. Roll %d without rolling a 7 to win. \n", point, point);
                for(;;){
                    enter = 'i'; 
                    printf("Roll the dice.\n");
                    while (enter != '\n') // This is a while loop that basically makes sure that if the dice is equal to 0 then it can not be submitted.
                        enter = getchar();
                    r1 = (rand() % 6) + 1;
                    r2 = (rand() % 6) + 1;
                    sum = r1 + r2; // Adds together the first and second random calculation above.
                    printf("You rolled %d and %d to get %d. \n", r1, r2, sum);
                    if(sum == point){
                        pl[playerno].balance += 10;
                        pl[playerno].wincount += 10;
                        printf("You win. New Balance is %d. \n", pl[playerno].balance);
                        break;
                    }
                    else if(sum == 7){
                        pl[playerno].balance -= 1;
                        pl[playerno].wincount -= 1;
                        printf("You lose. New Bal is %d. \n", pl[playerno].balance);
                        break;
                    }
                    else 
                        printf("Retry. \n");            
                }
                break;
            }
        }
    printf("Want to play again?");
    scanf("%s", &again);
    }
}

void topWin(){
int maxM, list, max1;
    for(int p = 0; p < 5; p++) {
        maxM = 999999;  //makes sure that the top maximum variable is a really high number in this loop, basically ensures that this loop will run as long as it doesn't go over 999999
        for(int a = 0; a < 10; a++){
            list = 0;
            for(int t = 0; t < 5; t++){
                if(strcmp(top[t].pl_name, pl[a].pl_name) == 0) list = 1;
                }
            if (pl[a].balance > maxM && !list) {
                maxM = pl[a].wincount;
                max1 = a;
            }
        }
        top[p] = pl[max1];
    }
    printf("\n");
    for(int a = 0; a < 5; a++) {
        printf("%s\t%d\n", top[a].pl_name, top[a].wincount);
    }
}
void topFive(){
int maxM, list, max1;
    for(int p = 0; p < 5; p++) {
        maxM = 999999;  //makes sure that the top maximum variable is a really high number in this loop, basically ensures that this loop will run as long as it doesn't go over 999999
        for(int a = 0; a < 10; a++){
            list = 0;
            for(int t = 0; t < 5; t++){
                if(strcmp(top[t].pl_name, pl[a].pl_name) == 0) list = 1;
                }
            if (pl[a].balance > maxM && !list) {
                maxM = pl[a].wincount;
                max1 = a;
            }
        }
        top[p] = pl[max1];
    }
    printf("\n");
    for(int a = 0; a < 5; a++) {
        printf("%s\t%d\n", top[a].pl_name, top[a].wincount);
    }
}
int main(){
    int i = 0, ch;
    FILE *rp;
    FILE *wp;
    rp = fopen("players.txt", "r");
    while(!feof(rp)){
        fscanf(rp, "%s\t%d\t%d", pl[i].pl_name, &pl[i].balance, &pl[i].wincount);
        i++;
}
    char name[10];
    srand (time(NULL));
    while (ch != 4) {
        printf("\n0. Top up your balance ");
        printf("\n1. Play Game!!! ");
        printf("\n2. Top 5 Players by Balance ");
        printf("\n3. Top 5 Winners! ");
        printf("\n4. Exit ");
        printf("\nWhat do you pick? ");
        scanf("%d", &ch);
        // From here on, I need to create seperate functions for each of these then tie them into the menu!!
        switch(ch) {
            case 0: 
                topBalance();
                wp = fopen("players.txt", "w");
                for(i = 0; i < 10; i++)
                    fprintf(wp, "%s\t%d\t%d\n", pl[i].pl_name, pl[i].balance, pl[i].wincount);
                fclose(wp);
                break;
            case 1: // Need to finish this and correct it!
                playGame();
                wp = fopen("players.txt", "w");
                for(i = 0; i < 10; i++)
                    fprintf(wp, "%s\t%d\t%d\n", pl[i].pl_name, pl[i].balance, pl[i].wincount);
                fclose(wp);
                break;                          
            case 2: // Segmentation Error
                topFive();
                break;
            case 3:
                topWin();
                break;
            case 4:
                break;

    break;      
    }
}
}

Solution

  • One problem I can see with your code is here -

    for(int t = 0; t < 5; t++){
        if(strcmp(top[t].pl_name, pl[a].pl_name) == 0) 
            list = 1;
    }
    

    You are checking for all the top 5, when only p of them are set yet. Meaning when you are checking for the second top, you are checking if the present name exists in any of the top 5. But only 1 has been set yet.

    This leads to reading memory (in strcmp) that has not been initialized. Most probably the uninitialized name is not a nul-terminated string and hence it leads to Undefined Behavior.

    This is the reason for your Segmentation fault.

    A simple fix here would be to change the loop to -

    for(int t = 0; t < p; t++){
        ....
    }
    

    Also, there is something seriously wrong with your topBalance function. You are using pl[i]. But i is never set to anything.