Thread: Beginner C Minesweeper game - How can i improve it?

  1. #1
    Registered User
    Join Date
    Dec 2016
    Posts
    4

    Beginner C Minesweeper game - How can i improve it?

    Hi guys, im a new forum member and pretty new to C. I've been studying C for about 3 months now and have made a beginner minesweeper. Was hoping people could take a look at it and tell me what beginner errors i made and some improvements like formatting and general programming.

    Code:
    /*
     * William Haworth
     * Minesweeper game
     */
    
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <ctype.h>
    #include <time.h>
    #include <windows.h>
    
    
    #define BOARD_SIZE 10
    #define TRUE 1
    #define FALSE 0
    
    
    typedef struct playerInfo{
        char name[15];
        int age;
        int time;
    } Player;
    //^to be added later for more marks???
    /*typedef struct position{
        int xpos;
        int ypos;
    } boardPosition;*/
    
    
    
    
    char board[BOARD_SIZE][BOARD_SIZE];
    char uboard[BOARD_SIZE][BOARD_SIZE]; //game board
    
    
    void setupMines();
    void buildUserBoard();
    void printBoard();
    void printUserBoard();
    void getInfo();
    int findMines(int row, int column);
    int mineSweep(int row, int column);
    void setupGame();
    int winCheck();
    void win();
    void loss();
    
    
    int main(){
    
    
        setupGame();
        return 0;
    }
    
    
    void getInfo(){ // Hope to expand this function to write names and ages to a file, also want to
                    //write times but not sure how to find the time taken to play the game.
    
    
        Player p1;
        printf("Please enter your name: ");
        scanf("%s", p1.name);
        printf("Please enter your age: ");
        scanf("%i", &p1.age);
        printf("\nHi %s, welcome to Minesweeper!\n\n",p1.name);
    
    
    }
    
    
    void printBoard(){
    
    
        int column, row;
    
    
        // Print the top row of numbers.
        for(column = 0; column < BOARD_SIZE ; column++)
            printf(" %d ", column);
        printf("\n");
    
    
        for(row = 0; row < BOARD_SIZE; row++)
        {
            for(column = 0; column < BOARD_SIZE; column++)
                printf(" %c ", board[row][column]);
            if(row >= 0 &&  row <= BOARD_SIZE -1)
                printf("%d", row);
            printf("\n");
        }
    }
    
    
    
    
    void buildUserBoard(){
        int column, row;
    
    
        // Set all elements in the board to '-'
        for(column = 0; column < BOARD_SIZE; column++)
            for(row = 0; row < BOARD_SIZE; row++)
                uboard[column][row] = '-';
    }
    void printUserBoard(){
        int column, row;
    
    
        system("cls");
        // Print the top row of numbers.
        for(column = 0; column < BOARD_SIZE ; column++)
            printf(" %d ", column);
        printf("\n\n");
    
    
        // Print the actual board with column numbers.
        for(column = 0; column < BOARD_SIZE ; column++)
        {
            for(row = 0; row < BOARD_SIZE; row++)
            {
                printf(" %c ", uboard[column][row]);
            }
            if(column >= 0 &&  column <= BOARD_SIZE  )
                printf("   %d", column);
            printf("\n");
        }
    
    
    }
    
    
    
    
    // Setting up mines within the board, represented by M
    void setupMines(){
    
    
        int column, row;
    
    
        for(column = 0; column < BOARD_SIZE ; column++){
            for (row = 0; row < BOARD_SIZE ; row++)
                board[column][row] = '-';
        }
    
    
        srand(time(0));
        for(row = 0; row < BOARD_SIZE ; row++){
            int random = rand() % (BOARD_SIZE );
            board[random][row] = 'M';
        }
    }
    //Finds mines in adjacent locations to user selection
    int findMines(int row, int column){
    
    
         int mines = 0;
    
    
        // Check up, down, left, right.
        if(board[row - 1][ column] == 'M')
            mines++;
        if(board[row + 1][ column] == 'M')
            mines++;
        if(board[row][ column - 1] == 'M')
            mines++;
        if(board[row][ column + 1] == 'M')
            mines++;
    
    
    
    
        // Check all diagonal directions
        if(board[row - 1][ column + 1] == 'M')
            mines++;
        if(board[row - 1][ column - 1] == 'M')
            mines++;
        if(board[row + 1][ column + 1] == 'M')
            mines++;
        if(board[row + 1][ column - 1] == 'M')
            mines++;
    
    
        return mines;
    }
    
    
    //Sets up board and prints intial board for user input.
    void setupGame(){
    
    
        int xpos, ypos;
    
    
        getInfo();
        system("pause");
        setupMines();
        buildUserBoard();
        printUserBoard();
    
    
        for(;;){
        do{ printf("\nEnter the row: ");
            scanf("%d",&xpos);
            printf("Enter the column: ");
            scanf("%d",&ypos);
            printf("\n");
            } while(xpos < 0 || xpos > BOARD_SIZE -1 || ypos < 0 || ypos > BOARD_SIZE -1 );
    
    
            if (board[xpos][ypos] == 'M'){
                printf("You have hit a mine!\n\n");
                printBoard();
                loss();
            }
            else
                mineSweep(xpos, ypos);
    
    
        printUserBoard();
        }
    }
    //Checks to see if a loss has occurred
    void loss(){
    
    
        char choice;
    
    
        scanf("%c", &choice);
        printf("You have lost!\n\nWould you like to play again? (Y/N)--> ");
        scanf("%c", &choice);
        if (toupper(choice) == 'Y'){
            system("cls");
            setupGame();
        }
    
    
        else
            printf("\nThanks for playing, bye! \n\n ");
            exit(0);
    }
    
    
    //Checks to see if a win has occurred
    int winCheck(){
    
    
        int column, row;
    
    
        for(column = 1; column < BOARD_SIZE - 1; column++)
            for(row = 1; row < BOARD_SIZE - 1; row++) {
                if(uboard[column][row] == '-' && board[column][row] != 'M')
                    return FALSE;
            }
    
    
        return TRUE;
    }
    
    
    void win(){
    
    
        char choice;
    
    
        printf("Congratulations, you have won! \nWould you like to start another game? (Y/N)--> ");
        scanf("%c", &choice);
    
    
        if (toupper(choice) == 'y'){
            system("cls");
        }
        else
            exit(99);
    }
    
    
    int mineSweep(int column, int row){
    
    
        int nearbymines = 0;
    
    
        if( row < 0 || row >= BOARD_SIZE || column < 0 || column >= BOARD_SIZE || uboard[column][row] != '-'){
            return 0;
        }
    
    
    
    
        nearbymines = findMines(column, row);
        uboard[column][row] = (char)(((int)'0') + nearbymines);
        //Want to check each mine see if 0, if 0 check each space around it
        if (nearbymines < 1){
            mineSweep(column, row -1);
            mineSweep(column+1, row-1);
            mineSweep(column+1, row);
            mineSweep(column+1, row+1);
            mineSweep(column, row+1);
            mineSweep(column-1, row+1);
            mineSweep(column-1, row);
            mineSweep(column-1, row-1);
        }
    
    
    
    
        return 1;
    
    
    }

  2. #2
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    I assume the board messed up your spacing so I can't really comment on that (WAY too many blank lines!).

    If you're not using anything from windows.h, get rid of it. People running a real OS don't want to see that kind of filth.

    Your main doesn't make sense. All it says is setup_game. That sounds like it sets up the game. If it's also playing the game, reporting results, and cleaning the dishes, then it's not a very well-designed function! I would've expected main to look more like:
    Code:
    int main() {
        general_setup();    // if needed
    
        do {
            game_setup();
            play();
        } while (play_again());
    
        print_stats();      // if desired
    
        return 0;
    }
    Actually, I would've expected the board(s) to be defined in main and passed into the funcions instead of being a global.

    There are virtually no useful comments. For example, why are there two boards?

    Maybe get rid of the separate win and loss functions and make a single function called play_again (as this is almost the entire content of both).

    You don't need separate print_board, print_user_board functions. Make a single function and pass in the board you want to print.

    Your mine placement is strange. You're placing one mine randomly in each row. That's not what the actual game does.

    The first part of setup_mines and the whole of build_user_board are both setting an entire board to dashes. Maybe make a function, clear_board, that does this for whichever board it is passed.

    It looks like find_mines could accidentally access outside the bounds of the board.

    As for times, you will need to use functions from time.h, something like:
    Code:
    time_t start_time = time(NULL);
    ...
    time_t end_time = time(NULL);
    double diff = difftime(end_time, start_time);
    // Now diff is the time between those two times, in seconds.
    That should be enough for now.

  3. #3
    Registered User
    Join Date
    Dec 2016
    Posts
    4
    Thanks for your reply, i have a few questions that i hope you can answer (please note i am not questioning whether you are right, just trying to understand).

    1) Why is it more useful to have the boards defined in main, does this not mean extra passing of pointers etc

    2) I was thinking that find mines might do that , but was unsure if it was something that would need to be changed as i don't know if it would affect anything when the program is running?

    3) I'm not entirely sure on how to use comments, other than the 2 board thing which i agree i should do, i don't know what i should/shouldn't be commenting on. I am told excessive commenting is bad

    4) With your comment on main, do you mean that this bit of code should be within main
    Code:
     for(;;){    do{ printf("\nEnter the row: ");
            scanf("%d",&xpos);
            printf("Enter the column: ");
            scanf("%d",&ypos);
            printf("\n");
            } while(xpos < 0 || xpos > BOARD_SIZE -1 || ypos < 0 || ypos > BOARD_SIZE -1 );
    
    
            if (board[xpos][ypos] == 'M'){
                printf("You have hit a mine!\n\n");
                printBoard();
                loss();
            }
            else
                mineSweep(xpos, ypos);
    
    
        printUserBoard();
        }

  4. #4
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    1) Why is it more useful to have the boards defined in main, does this not mean extra passing of pointers etc
    It does mean passing parameters (what's wrong with that?), but doing so ensures that only the functions that are supposed to see the data can access it. If a variable is global it might be modified anywhere. In a larger program this becomes a problem. In a small program, globals are not actually a bad thing (they're like the data in a C++ object). But it's extremely important to learn to pass variables to functions, so globals are considered a no-no for beginners. It's similar to how beginners are warned not to use goto because they tend to overuse it.

    2) I was thinking that find mines might do that , but was unsure if it was something that would need to be changed as i don't know if it would affect anything when the program is running?
    I believe that it will access outside the array bounds or at least access an essentially arbitrary element in the array as it tries to access, e.g., board[3][-1], which will presumably access the last element in the row 2, probably not what you want. BTW, your call to findMines seems to have the parameters reversed.

    3) I'm not entirely sure on how to use comments, other than the 2 board thing which i agree i should do, i don't know what i should/shouldn't be commenting on. I am told excessive commenting is bad
    Excessive (beginnerish, as seen in learn-to-code books) commenting is definitely bad. However, some overall explanation of what-in-the-world is going on is helpful. Just imagine you're me seeing the code for the first time. You should at least explain why there are two boards as this is not at all clear at first.

    4) With your comment on main, do you mean that this bit of code should be within main
    That's the idea.

  5. #5
    Registered User
    Join Date
    Dec 2016
    Posts
    4
    Thank you for the advice.

    It seems that you are right about findMines, i just checked and findMines will add mines to the count even if they are on the other side of the board. I didn't expect it to do that, aside from adding a column of blanks spaces is there any nice way to fix that?
    Last edited by NappySlapper; 12-05-2016 at 07:08 AM.

  6. #6
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    Quote Originally Posted by NappySlapper View Post
    It seems that you are right about findMines, i just checked and findMines will add mines to the count even if they are on the other side of the board. I didn't expect it to do that, aside from adding a column of blanks spaces is there any nice way to fix that?
    EDIT!!! I put the modifictaions on the wrong piece of code!
    Here's the findMines function.

    Just put in some extra tests:
    Code:
    int findMines(int row, int column){
         int mines = 0; 
    
        // Check up, down, left, right.
    
        if(row - 1 >= 0 && board[row - 1][ column] == 'M')
    
            mines++;
    
        if(row + 1 < BOARD_SIZE && board[row + 1][ column] == 'M')
    
            mines++;
        etc.
    Last edited by algorism; 12-05-2016 at 10:32 AM.

  7. #7
    Registered User
    Join Date
    Dec 2016
    Posts
    4
    Thanks, been stuck trying to figure this out for ages and the solution was so simple!
    Seems like i need to work on my problem solving skills!

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. may somebody help me with this simple minesweeper game??
    By matthewxd in forum C Programming
    Replies: 3
    Last Post: 12-01-2014, 11:29 PM
  2. Need tips on how to continue Minesweeper game in C
    By cjsam1324 in forum C Programming
    Replies: 4
    Last Post: 10-24-2013, 06:14 PM
  3. Beginner HiLo game glitches?
    By C22 in forum C++ Programming
    Replies: 2
    Last Post: 10-06-2013, 03:34 PM
  4. Confused Beginner - hangman game
    By goodfornothing in forum C++ Programming
    Replies: 4
    Last Post: 11-30-2009, 11:06 PM
  5. Replies: 14
    Last Post: 12-04-2006, 05:16 PM

Tags for this Thread