Thread: Simple Minesweeper [C] -- Kinda eh..

  1. #1
    Registered User
    Join Date
    Nov 2012
    Posts
    3

    Simple Minesweeper [C] -- Kinda eh..

    Just practicing. I was trying to make a console version of Minesweeper. It works (mostly) how I want, but there's got to be a way to make it more.. elegant... Any suggestions?

    Code:
    /*********************************************************************************
        Console-based version of Minesweeper 1.01
        Copyright (C) <2012>  <Samuel Joseph>
    
        Email: [email protected]
    
        To-do list:
        1. Create a function where user can select levels {easy, medium, hard}
    
        2. Create a better procedure for finding nearby mines,
            preferably, one less clunky and difficult to read and follow,
            and debug, and ... just about everything else.. something
            simple, yet, efficient. Elegant..
                
    
        This program is free software: you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation, either version 3 of the License, or
        (at your option) any later version.
    
        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.
    
        You should have received a copy of the GNU General Public License
        along with this program.  If not, see <http://www.gnu.org/licenses/>. 
    **********************************************************************************/
    
    /* Include files */
    #include <stdio.h>
    #include <stdlib.h>
    #include <ctype.h>
    #include <time.h>
    
    /* Definitions */
    #define BOARD_SIZE 6
    #define TRUE 0
    #define FALSE 1
    
    /* Global Variables */
    //-------------------------------------------------------------
    // I refuse to have to read in the gameboard for every
    // function that calls it.. 
    // 
    // Global "lost" variable is kind of stupid, but, it works...
    //-------------------------------------------------------------
    char board[BOARD_SIZE][BOARD_SIZE];
    char game_board[BOARD_SIZE][BOARD_SIZE];
    int lost = 0;
    
    /* Function prototypes */
    void display_welcome();
    void build_board();
    void build_gboard();
    void create_mines();
    void print_board();
    void print_fullboard();
    void start();
    int play_game();
    void play_again();
    int check_win_game();
    void check_for_mine(int, int);
    int check_for_nearby_mines(int, int);
    
    // Main function
    int main ()
    {
        display_welcome();
        printf("\nAny time you're ready... Just press ENTER. :)");
    
        // Get rid of welcome screen
        getchar();
        system("cls");
    
        start();
    
        return 0;
    
    }
    
    /* Build board used for created random mines */
    void build_board()
    {
    
        int i, j;
    
        //--------------------------------
        // Assign char for board elements
        //--------------------------------
        for(i = 0; i < BOARD_SIZE; i++)
            for(j = 0; j < BOARD_SIZE; j++)
                board[i][j] = 'o';
    
        // Place mines in this board, it remains
        // hidden from user until the game has
        // finished.
        create_mines();
    }
    
    /* Build game board for user input */
    void build_gboard()
    {
    
        int i, j;
        int row, col, cur = 4;
        printf("Creating game board....\nReady..set..\nPLAY!\n\n");
        //----------------------------------------
        // Assign char 'o' for all board elements
        //----------------------------------------
        for(i = 0; i < BOARD_SIZE; i++)
            for(j = 0; j < BOARD_SIZE; j++)
                game_board[i][j] = 'o';
        
        //--------------------------------
        // Print board
        //--------------------------------
        for(col = 0; col < BOARD_SIZE; col++)
            printf("%d ", col + 1);
        
        printf("\n\n");
    
        for(row = 0; row < BOARD_SIZE; row++)
        {
            for(col = 0; col < BOARD_SIZE; col++)
            {
                printf("%c ", game_board[row][col]);
            }
            printf(" %d ", row + 1);
            printf("\n");
        }
    }
    
    /* Create random places in the array for mines */
    void create_mines()
    {
        int i, random;
    
        // Seeding srand() with time(0) so that
        // mine locations aren't the same every
        // time the game is played.
        srand(time(0));
        
        for (i = 0; i < BOARD_SIZE; i++)
        {
            random = rand() % (BOARD_SIZE);
            board[random][i] = '*';
        }
    
    }
    
    /* Print the game board */    
    void print_board()
    {
        int row, col;
    
        system("cls");
        for(col = 0; col < BOARD_SIZE; col++)
            printf("%d ", col + 1);
        
        printf("\n\n");
            for(row = 0; row < BOARD_SIZE; row++)
        {
            for(col = 0; col < BOARD_SIZE; col++)
            {
                printf("%c ", game_board[row][col]);
            }
            printf(" %d ", row + 1);
            printf("\n");
        }
    }
    
    /* Print the full board showing mines */
    void print_fullboard()
    {
        int row, col;
    
        system("cls");
        for(col = 0; col < BOARD_SIZE; col++)
            printf("%d ", col + 1);
        
        printf("\n\n");
            for(row = 0; row < BOARD_SIZE; row++)
        {
            for(col = 0; col < BOARD_SIZE; col++)
            {
                printf("%c ", board[row][col]);
            }
            printf(" %d ", row + 1);
            printf("\n");
        }
    }
    
    /* Take user input for playing of the game */
    int play_game()
    {
        int r_selection = 0, c_selection = 0, 
            nearbymines = 0, nearbymines2 = 0,
            nearbymines3 = 0, nearbymines4 = 0,
            nearbymines5 = 0, nearbymines6 = 0,
            nearbymines7 = 0, nearbymines8 = 0,
            i = 0;
    
        //----------------------------------------------
        // Recieves data from the user, first the row
        // number, then the column number...
        // I could think of other ways to do it, but
        // this one seemed easiest.
        //----------------------------------------------
        do {
        printf("\nMake a selection (ie. row [ENTER] col): \n");
        printf("Row--> ");
        scanf("%d", &r_selection);
        printf("Col--> ");
        scanf("%d", &c_selection);
        
        } while(r_selection < 1 || r_selection > BOARD_SIZE || c_selection < 1 || r_selection > BOARD_SIZE);
        // ^ Checks for any invalid input statements from user.
    
        check_for_mine(r_selection - 1, c_selection - 1);
    
        if(lost == 1)
            return -1;
        
        // Checks for nearby mines at every direction from user
        // input location. Assigns that location the number
        // of mines found nearby, updating the board.
        nearbymines = check_for_nearby_mines(r_selection - 1, c_selection - 1);
        game_board[r_selection - 1][c_selection - 1] = (char)( ((int)'0') + nearbymines );
    
        //--------------------------------------------------
        // The following checks for mines nearby elements
        // in the array with no mines.. it's a continuous
        // loop until either a mine is found, or we
        // reach the end of the array & it cannot be checked
        // any further. It's big, clunky... but it works..
        //
    
        // It also changes the game_board[] with '0' if no
        // mines are found. Very useful piece of code.
        // It checks all elements left, right, up, down,
        // and all diagonal directions.. by running a function
        // that checks these same directions. A bit much
        // to follow, though. I'm sure there's a much better
        // way. I just don't know it yet.
        //---------------------------------------------------
        if(nearbymines == 0)
        {
            if(c_selection != BOARD_SIZE)
            {
                i = 0;
                while(nearbymines == 0 && (c_selection - 1 + i) < BOARD_SIZE)
                {
                    // This is checking elements to the right
                    nearbymines = check_for_nearby_mines(r_selection - 1, (c_selection - 1 + i));
                    if(nearbymines != -1)
                    {
                    game_board[r_selection - 1][(c_selection - 1) + i] = (char) ( ((int)'0') + nearbymines );
                    i++;
                    }
                }
                    if(r_selection != 1)
                    {
                        i = 0;
                        while(nearbymines5 == 0 && (c_selection - 1 + i) < BOARD_SIZE && (r_selection - 1 - i) > 0)
                        {
                            // This is checking elements to the diagonal-uright
                            nearbymines5 = check_for_nearby_mines((r_selection - 1 - i), (c_selection - 1 + i));
                            if(nearbymines5 != -1)
                            {
                            game_board[(r_selection - 1) - i][(c_selection - 1) + i] = (char) ( ((int)'0') + nearbymines5);
                            i++;
                            }
                        }
                    }
                    if(r_selection != BOARD_SIZE)
                    {
                        i = 0;
                        while(nearbymines6 == 0 && (r_selection - 1 + i) < BOARD_SIZE && (c_selection - 1 + i) < BOARD_SIZE )
                        {
                            // This is checking elements to the diagonal-dright
                            nearbymines6 = check_for_nearby_mines((r_selection - 1 + i), (c_selection - 1 + i));
                            if(nearbymines != -1)
                            {
                            game_board[(r_selection - 1) + i][(c_selection - 1) + i] = (char) ( ((int)'0') + nearbymines6);
                            i++;
                            }
                        }
                    }
            }
    
            if(r_selection != BOARD_SIZE)
            {
                i = 0;
                while(nearbymines2 == 0 && (r_selection - 1 + i) < BOARD_SIZE)
                {
                    // This is checking elements heading down
                    nearbymines2 = check_for_nearby_mines((r_selection - 1 + i), c_selection - 1);
                    if(nearbymines2 != -1)
                    {
                    game_board[(r_selection - 1) + i][c_selection - 1] = (char) ( ((int)'0') + nearbymines2 );
                    i++;
                    }
                }
    
                if(c_selection != BOARD_SIZE)
                {
                    i = 0;
                    while(nearbymines7 == 0 && (r_selection - 1 + i) < BOARD_SIZE && (c_selection - 1 - i) > 0)
                    {
                        // This is checking elements to the diagonal-dleft
                        nearbymines7 = check_for_nearby_mines((r_selection - 1 + i), (c_selection - 1 - i));
                        if(nearbymines != -1)
                        {
                        game_board[(r_selection - 1) + i][(c_selection - 1) - i] = (char) ( ((int)'0') + nearbymines7);
                        i++;
                        }
                    }
                }
            }
    
            if(r_selection != 1)
            {
                i = 0;
                while(nearbymines3 == 0 && (r_selection - i) > 0)
                {
                    // This is checking elements heading up
                    nearbymines3 = check_for_nearby_mines((r_selection - 1 - i), c_selection - 1);
                    if(nearbymines3 != -1)
                    {
                    game_board[(r_selection - 1) - i][c_selection - 1] = (char) ( ((int)'0') + nearbymines3 );
                    i++;
                    }
                }
                if(c_selection != BOARD_SIZE)
                {
                    while(nearbymines8 == 0 && (c_selection - 1 - i) > 0 && (r_selection - 1 - i) > 0)
                    {
                        // This is checking elements to the diagonal-uleft
                        nearbymines8 = check_for_nearby_mines((r_selection - 1 - i), (c_selection - 1 - i));
                        if(nearbymines8 != -1)
                        {
                        game_board[(r_selection - 1) - i][(c_selection - 1) - i] = (char) ( ((int)'0') + nearbymines8);
                        i++;
                        }
                    }    
                }
            }
    
            if(c_selection != 1)
            {
                i = 0;
                while(nearbymines4 == 0 && (c_selection - i) > 0)
                {
                    // This is checking elements to the left
                    nearbymines4 = check_for_nearby_mines(r_selection - 1, (c_selection - 1 - i));
                    if(nearbymines4 != -1)
                    {
                    game_board[r_selection - 1][(c_selection - 1) - i] = (char) ( ((int)'0') + nearbymines4 );
                    i++;
                    }
                }
            }
        }
    
    
    
        // Handles a player winning.
        if(check_win_game() == TRUE)
        {
            system("cls");
            print_fullboard();
            printf("\n\nYou've won the game!! Congrats!!\n\n");
            play_again();
        }
    
        return 0;
    }
    
    /* Check whether user input has selected a mine */
    void check_for_mine(int r_select, int c_select)
    {
        if(board[r_select][c_select] == '*')
        {
            printf("\nYou've hit a mine! You lose!\n");
            getchar(); getchar();
            lost = 1;
        }
    }
    
    /* Another ridiculous function to find nearby mines.
     * I know, I know...it's messy, and needs a rewrite. */
    int check_for_nearby_mines(int r_select, int c_select)
    {
        int nearby_mine_count = 0;
        
        if(board[r_select][c_select] == '*')
        {
            return -1;
        }
        // Check for mines below and to the right.
        if(r_select < (BOARD_SIZE - 1) && c_select < (BOARD_SIZE - 1))
        {
            // Check for mine below
            if(board[r_select + 1][c_select] == '*')
                nearby_mine_count++;
            // Check for mine to the right.
            if(board[r_select][c_select + 1] == '*')
                nearby_mine_count++;
            // Check for mine diagonal-dright.
            if(board[r_select + 1][c_select + 1] == '*')
                nearby_mine_count++;
    
            // Check whether the columns to the left can be checked
            if(c_select != 0)
            {
                // Check for mine diagonal-dleft
                if(board[r_select + 1][c_select - 1] == '*')
                    nearby_mine_count++;
                // Check for mine to the left
                if(board[r_select][c_select - 1] == '*')
                    nearby_mine_count++;
            }
            // Check whether the rows above can be checked
            if(r_select != 0)
            {
                // Check for mine above
                if(board[r_select - 1][c_select] == '*')
                    nearby_mine_count++;
                // Check for mine diagonal-uright
                if(board[r_select - 1][c_select + 1] == '*')
                    nearby_mine_count++;
                // Check whether columns to the left can be checked
                if(c_select != 0)
                {
                    // Check for mine diagonal-uleft
                    if(board[r_select - 1][c_select - 1] == '*')
                        nearby_mine_count++;
                }
            }
        }
        // Check if selection is in last row
        if(r_select == (BOARD_SIZE - 1) && c_select != (BOARD_SIZE - 1))
        {
            // Check for mine above
                if(board[r_select - 1][c_select] == '*')
                    nearby_mine_count++;
            // Check for mine diagonal-uright
                if(board[r_select - 1][c_select + 1] == '*')
                    nearby_mine_count++;
        }
        // Check if selection is in last column
        if(c_select == (BOARD_SIZE - 1) && r_select != (BOARD_SIZE - 1))
        {
            // Check for mine to the left
                if(board[r_select][c_select - 1] == '*')
                    nearby_mine_count++;
            // Check for mine diagonal-dleft
                if(board[r_select + 1][c_select - 1] == '*')
                    nearby_mine_count++;
        }
        // Check whether selection is last in element
        if(r_select == (BOARD_SIZE - 1) && c_select == (BOARD_SIZE - 1))
        {
            // Check for mine to the left
                if(board[r_select][c_select - 1] == '*')
                    nearby_mine_count++;
            // Check for mine diagonal-dleft
                if(board[r_select - 1][c_select - 1] == '*')
                    nearby_mine_count++;
            // Check for mine above
                if(board[r_select - 1][c_select] == '*')
                    nearby_mine_count++;
        }
    
        return nearby_mine_count;
    }
    
    /* Check if user has won game */
    int check_win_game()
    {
        int row, col;
    
        for(row = 0; row < BOARD_SIZE; row++)
            for(col = 0; col < BOARD_SIZE; col++)
            {
                if(game_board[row][col] == 'o' && board[row][col] != '*')
                    return FALSE;
            }
    
        return TRUE;
    }
    // Ask user if they wish to play again.
    void play_again()
    {
        char ans;
    
        printf("\n\nWould you like to play again? (y/n) --> ");
        scanf(" %c", &ans);
    
        if(toupper(ans) == 'Y')
        {
            system("cls");
            start();
        }
    
        else
        {
            printf("\n\nThanks for playing! Bye.");
            (void) getchar();
            exit(EXIT_SUCCESS);
        }
    }
    // Displays the welcome message, and the GNU License
    void display_welcome()
    {
        puts("-----------------------Welcome to Minesweeper!---------------------------");
        puts("Version: 1.01");
        puts("\n");
        puts("Copyright (C) <2012>  <Samuel Joseph>\n");
        printf("This program is free software: you can redistribute it and/or modify\n"
        "it under the terms of the GNU General Public License as published by\n"
        "the Free Software Foundation, either version 3 of the License, or\n"
        "(at your option) any later version.");
        puts("\n\n");
    }
    
    void start()
    {
        lost = 0;    // User hasn't lost yet
        // Build both game boards (one for the user to see,
        // and the one with the mines).
        build_board();
        build_gboard();
        
        // Start playing game
        do
        {
        play_game();
        print_board();
        } while(lost != 1);    // While the user hasn't lost, loop.
    
        // Once user is lost, print the board with all the mines.
        print_fullboard();
    
        // Play again?
        play_again();
    }

  2. #2
    Registered User
    Join Date
    Jun 2011
    Posts
    4,513
    In your "check_for_nearby_mines()" function, you do some extra work to check the selected square for boundary conditions.

    There is a method that will allow you to have one algorithm to check for nearby mines, without taking special cases (edge conditions) into account.

    1. Create your game board with an extra two rows and columns
    2. Make all squares around the edge of the game board "invisible" and always to have "no mines"

    The user will never see the outer layer of "invisible" squares, and whenever a square is checked for surrounding mines, there will always be a full 8 squares available to be checked (hence, no boundary limitations exist, which means a single algorithm in your "check for mines" function).

    Code:
    // Example 1:
    // 3x3 game board (3x3 array), which requires boundary conditions to be checked:
    
      ...
      ...
      ...
    
    // '.' means a legal square with a possible mine
    Code:
    // Example 2:
    // 3x3 game board (5x5 array), with an extra layer around it to avoid having to check for boundary conditions
    
      xxxxx
      x...x
      x...x
      x...x
      xxxxx
    
    // '.' means a legal square with a possible mine
    // 'x' means an "invisible" square with no mines possible
    Last edited by Matticus; 11-26-2012 at 07:53 PM.

  3. #3
    Registered User
    Join Date
    Nov 2012
    Posts
    3
    Ahh, I see.. Yeah, that sounds like a much better way to do things. Now, I feel like "/face-palm/ why didn't I think of that?" .. haha. It all comes with practice, I guess. Thanks for the tip!
    I'll get to work on it tomorrow after class...

  4. #4
    Registered User
    Join Date
    Nov 2012
    Posts
    3
    Okay, I'm no longer checking for boundary conditions, so the "findnearbymines()" function is MUCH cleaner. But, there's still some work to be done, because it's not flushing out all the spaces without mines near the space selected by the user.. In other words, if a space is set to '0' meaning there's no nearby mines, it should check the spaces around it for nearby mines.. if the user selects a space set with a '0' however, sometimes there are more spaces flushed out not containing mines, spaces which should have already been flushed.. I'm still looking for a solution. But, here's the code, maybe someone has an idea.

    Code:
    /*********************************************************************************
        Console-based version of Minesweeper 2.0.1
        Copyright (C) <2012>  <Samuel Joseph>
    
        Email: [email protected]
    
        To-do list:
        1. Create a function where user can select levels {easy, medium, hard}
    
        OTHER NOTES:
        I have to fix the way nearby mines are found, STILL.. because, if the
        player selects a space with a '0', more spaces are flushed out (which
        should have already been flushed).
    
        This program is free software: you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation, either version 3 of the License, or
        (at your option) any later version.
    
        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.
    
        You should have received a copy of the GNU General Public License
        along with this program.  If not, see <http://www.gnu.org/licenses/>. 
    **********************************************************************************/
    
    // Include files
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    #include <ctype.h>
    
    // Definitions
    #define BOARDSIZE 8
    #define TRUE 1
    #define FALSE 0
    
    // Global variables
    char board[BOARDSIZE][BOARDSIZE];
    char gboard[BOARDSIZE][BOARDSIZE];
    
    // Function prototypes
    void build_board();
    void build_gboard();
    void print_board();
    void print_gboard();
    int findnearbymines(int, int);
    void flushoutnearbymines(int, int);
    void loss();
    void win();
    int checkforwin();
    void playagain();
    void display_welcome();
    void start_game();
    
    /**********************************************
     * Main function. Handles gameplay.
     **********************************************/
    int main()
    {
    
        display_welcome();
        puts("\n");
        system("pause");
        start_game();
    
    
        return 0;
    }
    
    /******************************************
     * Simply prints the full board with mines.
     ******************************************/
    void print_board()
    {
        int i, j;
    
        // Print the first row of numbers.
        printf("  ");
        for(i = 1; i < BOARDSIZE - 1; i++)
            printf("%d ", i);
        printf("\n");
    
        // Print actual board w/ column numbers.
        for(i = 0; i < BOARDSIZE; i++)
        {
            for(j = 0; j < BOARDSIZE; j++)
                printf("%c ", board[i][j]);
            if(i > 0 &&  i < BOARDSIZE - 1)
                printf("%d", i);
            printf("\n");
        } 
    }
    
    /*********************************************
     * Prints the board used for most in-game
     * functions.
     *********************************************/
    void print_gboard()
    {
        int i, j;
    
        system("cls");
        // Print the first row of numbers.
        printf("  ");
        for(i = 1; i < BOARDSIZE - 1; i++)
            printf("%d ", i);
        printf("\n");
    
        // Hide the first and last rows along
        // with the first and last columns.
        for(i = 0; i < BOARDSIZE; i++)
            for(j = 0; j < BOARDSIZE; j++)
                if(i == 0 || i == BOARDSIZE - 1)
                    gboard[i][j] = ' ';
    
        for(j = 0; j < BOARDSIZE; j++)
            for(i = 0; i < BOARDSIZE; i++)
                if(j == 0 || j == BOARDSIZE - 1)
                    gboard[i][j] = ' ';
    
        // Print the actual board w/ column numbers.
        for(i = 0; i < BOARDSIZE; i++)
        {
            for(j = 0; j < BOARDSIZE; j++)
            {
                printf("%c ", gboard[i][j]);
            }
            if(i > 0 &&  i < BOARDSIZE - 1)
                printf("%d", i);
            printf("\n");
        }
    }
    
    /**********************************************
     * Builds the board with the mines. Uses two
     * extra rows and two extra columns with no
     * mines for checks performed later.
     **********************************************/
    void build_board()
    {
        int i, j;
    
        // Set all elements in the board to '-'
        for(i = 0; i < BOARDSIZE; i++)
            for(j = 0; j < BOARDSIZE; j++)
                board[i][j] = '-';
    
        // Seed srand() with time()
        srand(time(NULL));
    
        // Place random mines (marked with '*')
        for(j = 0; j < BOARDSIZE; j++)
        {
            int random = rand() % (BOARDSIZE - 1) + 1;
            board[random][j] = '*';
        }
    
        // Make sure the first & last row, along with
        // the first and last column contain no mines.
        for(i = 0; i < BOARDSIZE; i++)
            for(j = 0; j < BOARDSIZE; j++)
                if(i == 0 || i == BOARDSIZE - 1)
                    board[i][j] = ' ';
    
        for(j = 0; j < BOARDSIZE; j++)
            for(i = 0; i < BOARDSIZE; i++)
                if(j == 0 || j == BOARDSIZE - 1)
                    board[i][j] = ' ';
    }
    
    /**********************************************
     * Builds the board for user interaction. Same 
     * dimensions as the first board, just without
     * the mines. Every element will be a '-' 
     * character except for the extra rows and cols.
     ************************************************/
    void build_gboard()
    {
        int i, j;
    
        // Set all elements in the board to '-'
        for(i = 0; i < BOARDSIZE; i++)
            for(j = 0; j < BOARDSIZE; j++)
                gboard[i][j] = '-';
    
    
        // Make sure the first & last row, along with
        // the first and last column contain no mines.
        for(i = 0; i < BOARDSIZE; i++)
            for(j = 0; j < BOARDSIZE; j++)
                if(i == 0 || i == BOARDSIZE - 1)
                    gboard[i][j] = ' ';
    
        for(j = 0; j < BOARDSIZE; j++)
            for(i = 0; i < BOARDSIZE; i++)
                if(j == 0 || j == BOARDSIZE - 1)
                    gboard[i][j] = ' ';
    }
    
    /************************************************
     * Finds nearby mines, checks in all 8 directions.
     * Returns the number of nearby mines found.
     *************************************************/
    int findnearbymines(int row, int col)
    {
        int mines = 0;
    
        // Check up, down, left, right.
        if(board[row - 1][col] == '*')
            mines++;
        if(board[row + 1][col] == '*')
            mines++;
        if(board[row][col - 1] == '*')
            mines++;
        if(board[row][col + 1] == '*')
            mines++;
    
        // Check all diagonal directions
        if(board[row - 1][col + 1] == '*')
            mines++;
        if(board[row - 1][col - 1] == '*')
            mines++;
        if(board[row + 1][col + 1] == '*')
            mines++;
        if(board[row + 1][col - 1] == '*')
            mines++;
    
        return mines;
    }
    
    /************************************************
     * Handles a loss and asks if the user wishes
     * to play again..
     ************************************************/
    void loss()
    {
        char ans;
    
        printf("\nYou've lost the game!");
        printf("\nWould you like to play again? (y/n)--> ");
        scanf(" %c", &ans);
    
        if(toupper(ans) == 'Y')
        {
            system("cls");
            start_game();
        }
    
        else
            exit(0);
    }
    /************************************************
     * Handles a winning game, asks user if they
     * wish to play again..
     ************************************************/
    void win()
    {
        char ans;
    
        printf("\nYou've won the game!");
        printf("\nWould you like to play again? (y/n)--> ");
        scanf(" %c", &ans);
    
        if(toupper(ans) == 'Y')
        {
            system("cls");
            start_game();
        }
    
        else
            exit(0);
    }
    
    /*************************************************
     * Flushes out all the nearby mines. First checks
     * the current user position for nearby mines, 
     * then checks in all eight directions for other
     * locations without nearby mines until it finds
     * a position with a mine touching that position.
     *
     * It updates the game board with the number of 
     * mines touching that position.
     *************************************************/
    void flushoutnearbymines(int row, int col)
    {
        int nearbymines = 0;
        int i = 0;
    
            nearbymines = findnearbymines(row, col);
            gboard[row][col] = (char)(((int)'0') + nearbymines);
    
            nearbymines = 0;
            // Checking nearby mines going up
            while(nearbymines < 1 && i < row)
            {
                nearbymines = findnearbymines(row - i, col);
                gboard[row - i][col] = (char)(((int)'0') + nearbymines);
                i++;
            }
            i = 0;
            nearbymines = 0;
            // Checking nearby mines going down
            while(nearbymines < 1 && row + i < BOARDSIZE - 2)
            {
                nearbymines = findnearbymines(row + i, col);
                gboard[row + i][col] = (char)(((int)'0') + nearbymines);
                i++;
            }
            i = 0;
            nearbymines = 0;
            // Checking nearby mines going left
            while(nearbymines < 1 && i < col)
            {
                nearbymines = findnearbymines(row, col - i);
                gboard[row][col - i] = (char)(((int)'0') + nearbymines);
                i++;
            }
            i = 0;
            nearbymines = 0;
            // Checking nearby mines going right
            while(nearbymines < 1 && col + i < BOARDSIZE - 2)
            {
                nearbymines = findnearbymines(row, col + i);
                gboard[row][col + i] = (char)(((int)'0') + nearbymines);
                i++;
            }
            i = 0;
            nearbymines = 0;
            // Checking nearby mines going up-right
            while(nearbymines < 1 && col + i < BOARDSIZE - 2 && i < row)
            {
                nearbymines = findnearbymines(row - i, col + i);
                gboard[row + i][col + i] = (char)(((int)'0') + nearbymines);
                i++;
            }
            i = 0;
            nearbymines = 0;
            // Checking nearby mines going up-left
            while(nearbymines < 1 && i < row && i < row && i < col)
            {
                nearbymines = findnearbymines(row - i, col - i);
                gboard[row - i][col - i] = (char)(((int)'0') + nearbymines);
                i++;
            }
            i = 0;
            nearbymines = 0;
            // Checking nearby mines going down-right
            while(nearbymines < 1 && row + i < BOARDSIZE - 2 && col + i < BOARDSIZE - 2)
            {
                nearbymines = findnearbymines(row + i, col + i);
                gboard[row + i][col + i] = (char)(((int)'0') + nearbymines);
                i++;
            }
            i = 0;
            nearbymines = 0;
            // Checking nearby mines going down-left
            while(nearbymines < 1 && row + i < BOARDSIZE - 2 && i < col)
            {
                nearbymines = findnearbymines(row + i, col - i);
                gboard[row + i][col - i] = (char)(((int)'0') + nearbymines);
                i++;
            }
    }
    
    /*************************************************
     * Checks for a game that has been won. Searches
     * the entire game board for a position without a
     * mine that still has a '-' symbol indicating
     * that the user still has plays to make. If there
     * are no locations with a '-' symbol that does
     * not contain a mine at that cooresponding position, 
     * the player has won.
     **************************************************/
    int checkforwin()
    {
        int i, j;
    
        for(i = 1; i < BOARDSIZE - 1; i++)
            for(j = 1; j < BOARDSIZE - 1; j++) {
                if(gboard[i][j] == '-' && board[i][j] != '*')
                    return FALSE;
            }
    
        return TRUE;
    }
    
    /***********************************************
     * Starts the game and handles the loop to 
     * either continue playing or quitting.
     ***********************************************/
    void start_game()
    {
        int row, col;
    
        // Build both game boards
        build_board();
        build_gboard();
        print_gboard();
    
        for(;;)
        {
            do {
            printf("Enter selection:\n");
            printf("Row--> ");
            scanf("%d", &row);
            printf("Col--> ");
            scanf("%d", &col);
            } while(row < 1 || row > BOARDSIZE - 2 || col < 1 || col > BOARDSIZE - 2);
    
    
            if(board[row][col] == '*')
            {
                printf("You hit a MINE!\n");
                print_board();
                loss();
            }
            else    
                flushoutnearbymines(row, col);
                                
            print_gboard();
    
            if(checkforwin() == TRUE)
                win();
    
    
            //-----------[DEBUG]----------------
            // Prints the full board with mines
            // after every turn.
            // [For debugging only]. Comment out
            // for actual gameplay.
            //----------------------------------
    
            // printf("\n[DEBUG]\n");
            // print_board();
        }
    }
    
    // Displays the welcome message, and the GNU License
    void display_welcome()
    {
        puts("-----------------------Welcome to Minesweeper!---------------------------");
        puts("Version: 2.0.1");
        puts("\n");
        puts("Copyright (C) <2012>  <Samuel Joseph>\n");
        printf("This program is free software: you can redistribute it and/or modify\n"
        "it under the terms of the GNU General Public License as published by\n"
        "the Free Software Foundation, either version 3 of the License, or\n"
        "(at your option) any later version.");
        puts("\n\n");
    }

  5. #5
    Registered User MacNilly's Avatar
    Join Date
    Oct 2005
    Location
    CA, USA
    Posts
    466
    Try the flood fill algorithm. This will be good practice using recursion and much more elegant than what you have now. In terms of minesweeper, when the user selects a square, the flood fill algorithm clears all squares NOT containing a mine until hitting the edge of the board.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Minesweeper
    By NessValdez in forum C Programming
    Replies: 4
    Last Post: 10-14-2012, 02:43 PM
  2. minesweeper
    By mark69 in forum C Programming
    Replies: 2
    Last Post: 11-26-2007, 10:28 AM
  3. Minesweeper AI
    By Shakti in forum Contests Board
    Replies: 34
    Last Post: 05-13-2005, 07:24 PM
  4. Minesweeper
    By PJYelton in forum Game Programming
    Replies: 2
    Last Post: 12-22-2002, 10:58 AM
  5. minesweeper...
    By jk81 in forum C Programming
    Replies: 1
    Last Post: 10-24-2002, 05:23 PM

Tags for this Thread