New Posts  All Forums:Forum Nav:

C War game bugs

post #1 of 7
Thread Starter 
Hi everyone,

I am having trouble with my code. I am not getting the expected output for the score for both and the number of rounds. Any help is appreciated.
Code:
#include <stdio.h>
#include <time.h>
#include <stdlib.h>

int getUserInput(int upperLimit)
{
    int chance;
    scanf("%d", &chance);
    
    if (chance <= upperLimit){
        return chance;
    }
    else{
        return -1;
    }
}//end of getUserInput
char luckInput()
{
    char luck;
    scanf("%s", &luck);
    if (luck == 'y')
        luck = 'Y';
    if (luck == 'n')
        luck = 'N';
    if (luck == 'Y') {
        printf("I hope you are correct.");
    }
    else if (luck == 'N'){
        printf("Too bad.");
    }
    else{
        printf("Whatever.");
    }
    return luck;
    
}//end of luckImput

int randomNumberGenerator(int upperLimit)
{
    int computerSelection;

    srand(time(NULL));
    computerSelection = 1 + rand() % upperLimit;//Random number generated
    
    return computerSelection;
}
int randomNumberGenerator2(int upperLimit)
{
    int computerSelection2;
    
    srand(time(NULL));
    computerSelection2 = 1 + rand() % upperLimit;//Random number generated
    
    return computerSelection2;
}//end of randomNumberGenerator2
int main(int argc, const char * argv[]){
    int player1;
    int computer;
    int howManyPlays;
    int round = 1;
    int player1Score = 0;
    int computerScore = 0;
    char chance;
    const int WAR = 10;
    const int COMPWAR = 10;
    const int MAXNUMBEROFPLAYS = 5;
    
    printf("How many rounds would you like to play? The max is %d: ", MAXNUMBEROFPLAYS);
    howManyPlays = getUserInput(MAXNUMBEROFPLAYS);
    
    while (round <= howManyPlays) {
        player1 = (randomNumberGenerator(WAR) + randomNumberGenerator(COMPWAR)) / 2;
        printf("Player1 drew a %d\n", player1);
        printf("Are you feeling lucky? Y for yes or N for no: ");
        chance = luckInput();
        computer = randomNumberGenerator2(WAR);
        printf("The computer drew a %d\n", computer);
        if (player1 < computer){
            printf("The computer wins\n");
            computerScore++;
        }//end of if player1
        if (player1 == computer){
            printf("It is a tie\n");
            computerScore++;
            player1Score++;
        }//end of if statement
        if (player1 > computer) {
            printf("You win!!!\n");
            player1Score++;
        }//end of if statement
    round ++;
    }//end of while loop
    printf("You played %d round(s).\n", round-1);
    printf("Player1 your final score is %d\n", player1Score);
    printf("The computer's score is %d\n", computerScore);
    if(player1Score > computerScore){
        printf("You defeated the computer.\n");
    }//end of if
    else if (player1Score < computerScore){
        printf("The computer bested you.\n");
    }//end of else if
    else if (player1Score == computerScore){
        printf("You tied the computer.\n");
    }//end of else if
}//end of main
post #2 of 7
Thread Starter 
Also it is getting the winner wrong at times and it won't loop.
post #3 of 7
Quote:
Originally Posted by lessismore11 View Post

Also it is getting the winner wrong at times and it won't loop.

You're allocating a single character for your "luck" variable, but telling scanf to read a string into it. The string you're reading will contain "y" or "n", likely a newline, and a terminating null byte for a total of 2 or 3 characters. This leads to stack corruption (scanf is overwriting other variables) which is causing the weird behavior.

A simple fix is to change your luckInput method to something like:
Code:
char luckInput()
{
    char luck[10];
    scanf("%s", luck);
    if (*luck == 'y')
        *luck = 'Y';
    if (*luck == 'n')
        *luck = 'N';
    if (*luck == 'Y') {
        printf("I hope you are correct.");
    }
    else if (*luck == 'N'){
        printf("Too bad.");
    }
    else{
        printf("Whatever.");
    }
    return *luck;

}//end of luckImput
Cube
(9 items)
 
  
CPUMotherboardRAMHard Drive
i7-4930k EVGA X79 Dark Corsair Vengeance Pro Samsung 840 Pro 
CoolingMonitorPowerCase
Corsair H100i Viewsonic VP2770 EVGA SuperNova 1000P2 Corsair Air 540 
Mouse
Corsair M65 
  hide details  
Reply
Cube
(9 items)
 
  
CPUMotherboardRAMHard Drive
i7-4930k EVGA X79 Dark Corsair Vengeance Pro Samsung 840 Pro 
CoolingMonitorPowerCase
Corsair H100i Viewsonic VP2770 EVGA SuperNova 1000P2 Corsair Air 540 
Mouse
Corsair M65 
  hide details  
Reply
post #4 of 7
Thread Starter 
Thanks I works perfectly now.
post #5 of 7
Thread Starter 
What do the *s before luck do?
post #6 of 7
That question has a long answer that is historically difficult for beginners to understand.

The asterisk in this context dereferences the luck pointer.

The first version had "char luck;" -- luck is an 8-bit char value. The modified version has "char luck[10]" which, while appearing similar, is a completely different datatype. In the latter case, "luck" is now a pointer to memory and is a 32-bit or 64-bit value depending on your system. In C and C++, any array variable is treated as a pointer type, not a value type.

Pointers are heavily used in C and are the reason your first implementation did not work. In your initial version, you defined "char luck" and then passed "&luck" to scanf. &luck is also a pointer value pointing to the memory location containing "char luck".

Example, the following are the same:
Code:
char luck = 'Y';

// This defines a pointer to a char value
char *luck_ptr = &luck;

// We can reference and dereference as many times as we want
char same1 = luck;
char same2 = *&luck;
char same3 = *&*&luck;

// luck_ptr is already a reference, so we start by dereferencing it
char same4 = *luck_ptr;
char same4 = *&*luck_ptr;

Now in practice there's no reason to flip back and forth between reference and value types in this manner without doing something in between, but you'll find yourself often going from a value to a reference or back again.

There are two ways for a C function to return a result. One way is obvious: the function returns a result using the return statement. This works if your value is a simple value type; i.e., int, char, float, etc. The way in which such a value is returned depends on the calling convention of the language and platform that you're using; generally the return value will be placed in a designated CPU register and the routine that called the function will read from this register after the function returns. However, you can't return, for example, a string in this fashion, since a string is of variable length and would never fit into the result register.

So instead, a function like scanf takes as a parameter a char pointer (or in the case of scanf, a "void" pointer since the type of the value being returned is not necessarily a char). scanf uses that pointer to write directly to some memory location. scanf doesn't care where this memory is allocated or how much space is allocated, but in this case the memory is allocated on the call stack in the frame of the luckInput call and it's 10 bytes in length. I did not tell scanf that the memory location is only sized for 10 characters, so the program will still run into problems if I respond to the luck prompt with something like "YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY". This is called a buffer overflow and is the cause of numerous security and reliability problems. scanf likely isn't the best function to use in this case since it doesn't provide a way to protect against buffer overflows.

There's a lot of material here, including: pointers (referencing and dereferencing), the call stack and stack allocation, different ways to return values, stack vs. heap allocation (I didn't mention heap allocation but it's a related subject), buffer management and buffer overflows, etc. Google will give you numerous resources for these subjects, ideally with diagrams to aid in understanding.
Cube
(9 items)
 
  
CPUMotherboardRAMHard Drive
i7-4930k EVGA X79 Dark Corsair Vengeance Pro Samsung 840 Pro 
CoolingMonitorPowerCase
Corsair H100i Viewsonic VP2770 EVGA SuperNova 1000P2 Corsair Air 540 
Mouse
Corsair M65 
  hide details  
Reply
Cube
(9 items)
 
  
CPUMotherboardRAMHard Drive
i7-4930k EVGA X79 Dark Corsair Vengeance Pro Samsung 840 Pro 
CoolingMonitorPowerCase
Corsair H100i Viewsonic VP2770 EVGA SuperNova 1000P2 Corsair Air 540 
Mouse
Corsair M65 
  hide details  
Reply
post #7 of 7
Thread Starter 
Thank you
Really helpful
New Posts  All Forums:Forum Nav:
  Return Home
  Back to Forum: Application Programming