Search code examples
arrayscloopsdo-whilegetchar

How do you prevent blank lines when checking answers in an array in C?


I am making a Bingo game in C for a project and have made it through the initial board creation: B = 1-20, I = 21-40, N = 41-60, G = 61-80, O = 81-99. I have also been able to randomly generate a letter/number pair that doesn't repeat that is to be used to play the game per the following:

int main()
{
    srand(time(0));

    int rollcount = 0, rollc, rollr, nohund, basec=5, base=20;
    const char BINGO[5] = {'B','I','N','G','O'};
    bool check[101];

    //fills check array with falses that will change to true as numbers are picked.        
    for(int i = 0; I < 100; i++) 
        check[i]=false;
    
    //marks free space as true, free = 100 on board
    check[100]=true; 

    do
    {
        //test var to prevent duplicate "rolls" until a game is won
        bool reroll=true; 

        rollcount++;

        //here's where the problem starts
        //This is meant to loop if the number rolled has been rolled before.
        do  
        {
            //getchar();
            if(getchar() == 'q')
            {
               //future code to display stats and escape game
               return 0;
            }

            rollc = rand() %basec;  //pick random column

            //pick random number in range of selected column
            rollr = rand() %base + 1;
            rollr += (rollc * 20);  

            //limits last col to 99 instead of 100
            nohund = (rollr == 100 ? rollr -= 1 : rollr);  

            if (check[rollr] == false)  //checks if number has been used
            {
                //prints the number of the roll, column letter, and random number
                printf("%d: %c-%d", rollcount, BINGO[rollc], rollr);
                    
                check[rollr]=true;  //prevents future use of that number
                reroll=false;  //escapes loop to roll another number
            }
        }
        //roll current roll again when duplicate is generated
        while(reroll==true);  
    }
    //intended to roll with each press of 'ENTER'
    while(getchar()=='\n');  
}

I have tried a few things. As written above, the major problem is if a duplicate is found, it shows the blank line from the getchar() input in the if() statement. As more numbers are found, wider and wider gaps between lines appear (due to needing more ENTER presses to find a unique number), leaving a mostly blank screen. With a single ENTER press, I need it to loop until it finds a good number. If I get rid of all getchar() expressions, the program will do this, and I can press ENTER until I get 99 unique numbers, but I need to allow to press q to quit the program.

Example Output

1: B-15  
2: G-78  
3: I-37  
4: G-62  

To summarize, I need it to display numbers like it does without getchar(), make it through all 99 possibilities, and let me quit with q.

Please help, and thank you in advance.


Solution

  • Let's first apply some fixes to other parts of the code, to make sure it all works as intended. This is the typical signature for a main function without parameters:

    int main(void)
    

    The middle I here needs to be lowercase, otherwise the code won't compile or it will use the imaginary number from the complex numbers:

    // Note: index 0 is not used
    for(int i = 1; i < 100; i++) 
    

    The most direct way of making the program work, would be to move the getchar() == 'q' check to before the do-loop. The function of the do-loop is now to loop until it finds a number which hasn't been chosen before. The problem is now that this will loop forever if all numbers are taken. Therefore, we'll add an additional check: only loop if there are still numbers available.

    if(getchar() == 'q')
    {
        return 0;
    }
    
    bool aNumberIsAvailable;
    do
    {
        // ... same code as before ...
    
        aNumberIsAvailable = false;
        for(int i = 0; i < 100; i++) 
        {
            if (!check[i])
            {
                aNumberIsAvailable = true;
                break;
            }
        }
    }
    while(reroll==true && aNumberIsAvailable);
    

    That said, there are better ways to design this program. One simple step is to combine the two getchars into one, as if it is a menu: A '\n' result means "roll another number" and a 'q' result means "quit". As user3386109 suggested, there are better ways to solve the "sample without replacement"-problem.
    Finally, note that getchar does not detect key presses. It simply reads a single character from the (terminal) input buffer. If you would like see actual key up/down movements, you will need a library which gives you more direct access to the keyboard such as SDL2.