Minesweeper - using OpenGl with C++

Minesweeper is a very popular computer game on Windows and other platforms. The board is divided into a grid of 10 X 10 tiles. Each of the tile is covered in the begining. Ten of these tiles
contain mines. Your aim is to uncover all the tiles without mines and detonate all the mines.

This minesweeper game [tutorial] has been coded in ANSI C++ (using MingW through CodeBlocks) and uses OpenGL graphicsTo avoid problems we suggest you to use the above tools only.

General installation procedure is described in the readme file. Here we tell you the procedure to install it in codeblocks.


Installing the OpenGl library in Codeblocks

Extract the file below into a directory 
freeglut

Copy the files in the include folder into
C:\Program Files\CodeBlocks\MinGW\include\GL

(you might need to overwrite existing files)

Copy the files in the lib folder into
C:\Program Files\CodeBlocks\MinGW\lib

Copy the file freeglut.dll into the directory whre your EXE file will be placed or alternatively you can place it your system path

(C:\Windows ,C:\ ,C:\windows\system32)
(assuming a windows install in C drive)
 

In codeblocks
Go to Settings>Compiler and Debugger
Under the "Linker Settings" Tab click on the Add option on the link libraries box
Now browse for the library libfreeglut.a(which you just added) in your codeblocks installation
Repeat the above step for another library libopengl32.a  in the same folder
(the order is important)
Click OK
Now OpenGL has been set up. compile and enjoy the game.
 

Source Code in C++

#include<GL/glut.h>
#include<iostream>
#include<time.h>
#include<stdlib.h>
#include<iomanip>
 
 
using namespace std;
enum {FLAG=-1,UNCOVER,COVER,};
enum {MINE=-1,BLANK,ADJACENT};
enum {LOSE=-1,UNKNOWN,WIN};
enum {IN_PROGRESS,GAME_OVER};
const int dim=10,mines=10;
const int max_x=100,max_y=100,xint=max_x/dim,yint=max_y/dim;

class cell
        {
          public :
          int content ;
        //0 blank,1-8 adjacent mines,-1 mine
        int status;
        //0 uncovered ,1 covered, -1 flagged
        cell()
          {
          content=BLANK;status=COVER;

          }
        };
cell board[dim][dim];
class GAMEPLAY
            {

            public:
                int flagged,uncovered,covered,status,result;
                time_t start_time,end_time,total_time;
                int mine_pos[mines][2],mine_count;
                GAMEPLAY()
                {
                flagged=0;
                uncovered=0;
                covered=dim*dim;
                status=IN_PROGRESS;
                result=UNKNOWN;
                start_time=time(NULL);
                mine_count=0;

                for(int i=0;i<mines;i++)
                for(int j=0;j<2;j++)
                mine_pos[i][j]=-1;

                }
                void add_mine(int i,int j)
                {

                mine_pos[mine_count][0]=i;
                mine_pos[mine_count][1]=j;
                mine_count++;
                }
                int check()
                {

                if(result!=UNKNOWN)
                return result;

                //cout<<covered<<"  "<<flagged;
                if(covered==0&&flagged==mines)
                    {
                        status=GAME_OVER;
                        result=WIN;
                        end_time=time(NULL);
                        total_time=end_time-start_time;
                        cout<<"\""<<total_time<<"\"";
                        return WIN;
                    }


                for(int i=0;i<mines;i++)
                {
                    if(UNCOVER==board[mine_pos[i][0]][mine_pos[i][1]].status)
                        {
                            status=GAME_OVER;
                            result=LOSE;
                            end_time=time(NULL);
                            total_time=end_time-start_time;
                            cout<<"\""<<total_time<<"\"";
                            return LOSE;
                        }

                }
                return UNKNOWN;
                }

            };

 


GAMEPLAY game_stats;

void initiate_board();
void draw_board();
void init_mines(int num,int dim);
void init_mines_adjacent(int num, int dim);
void calc_adjacent_mines(int i,int j,int dim);
void uncover_cell(int i, int j);
void uncover_area(int i, int j);
void uncover_area_check_cell(int k, int l);
void left_click(int i,int j);
void right_click(int i,int j);
void game_over(int result);

void draw_square(int x,int y,int color);
void user_input(int button,int state,int x,int y);
void show_content(int i,int j);


void gl_init();
void display();
void reshape(int w, int h);
void printMessage(char *msg);
void printString(char *s);
void makeRasterFont(void);

/**************************main************************/
int main(int argc, char *argv[])
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutInitWindowSize(400,400);
glutInitWindowPosition(50,50);
glutCreateWindow("Minesweeper");
glutReshapeFunc(reshape);
glutDisplayFunc(display);
glutMouseFunc(user_input);

gl_init();
initiate_board();

glutMainLoop();
return 1;
}

 


/*********init_mines********/
void init_mines(int num,int dim)
{
srand(time(NULL));
int i=0,j=0,count=0;
    while(count!=num)
    {

    i=rand()%dim;
    j=rand()%dim;

    if(board[i][j].content!=MINE)
    {
        board[i][j].content=MINE;
        count++;
        game_stats.add_mine(i,j);
        //cout<<i<<"  "<<j<<"  "<<count<<endl;
    }

    }

}

/********init_mine_adjacent*********/

void init_mines_adjacent(int num, int dim)
{

int i,j,count;
for(i=0;i<dim;i++)
for(j=0;j<dim;j++)
    {

    if(board[i][j].content!=MINE)
    {calc_adjacent_mines(i,j,dim);
    count++;}
    }
}

/********calc_adjacent_mines*********/
void calc_adjacent_mines(int i,int j,int dim)
{
    //row above mines
    if(i-1>=0)
    {
      if(j-1>=0)
      if(board[i-1][j-1].content==MINE)
            board[i][j].content++;
      if(board[i-1][j].content==MINE)
            board[i][j].content++;

      if(j+1<dim)
      if(board[i-1][j+1].content==MINE)
            board[i][j].content++;


    }
       if(j-1>=0)
      if(board[i][j-1].content==MINE)
            board[i][j].content++;
      if(j+1<dim)
      if(board[i][j+1].content==MINE)
            board[i][j].content++;

     if(i+1<dim)
    {
      if(j-1>=0)
      if(board[i+1][j-1].content==MINE)
            board[i][j].content++;
      if(board[i+1][j].content==MINE)
            board[i][j].content++;

      if(j+1<dim)
      if(board[i+1][j+1].content==MINE)
            board[i][j].content++;


    }


}


/**********initiate_board***********/
void initiate_board()
{

init_mines(mines,dim);
init_mines_adjacent(mines,dim);
draw_board();
//game_stats.start=time(NULL);


}

 

 

/***************uncover_cell*******************/
void uncover_cell(int i , int j)
{

switch(board[i][j].content)
    {
            case MINE       :   show_content(i,j);
                                break;
            case BLANK      :   show_content(i,j);
                                uncover_area(i,j);
                                break;
            case 1          :   show_content(i,j);
                                break;
            case 2          :   show_content(i,j);
                                break;
            case 3          :   show_content(i,j);
                                break;
            case 4          :   show_content(i,j);
                                break;
            case 5          :   show_content(i,j);
                                break;
            case 6          :   show_content(i,j);
                                break;
            case 7          :   show_content(i,j);
                                break;

            case 8          :   show_content(i,j);
                                break;
            default         :   break;


    }
}

/**********uncover_area_check_cell******************/
void uncover_area_check_cell(int k, int l)
{
    if(board[k][l].status==COVER)
{
    if(board[k][l].content!=MINE)
    {
    board[k][l].status=UNCOVER;
    game_stats.covered--;
    game_stats.uncovered++;
    draw_square(k,l,UNCOVER);
    show_content(k,l);
    if(board[k][l].content==BLANK)
    uncover_area(k,l);
    }

}
}

/**********uncover_area******************/
void uncover_area(int i, int j)
{

int k=i,l=j;

if(i-1>=0)
uncover_area_check_cell(i-1,j);
if(i+1<dim)
uncover_area_check_cell(i+1,j);
if(j-1>=0)
uncover_area_check_cell(i,j-1);
if(j+1<dim)
uncover_area_check_cell(i,j+1);
}

/************left_click*****************/
void left_click(int i,int j)
{
 if(board[i][j].status==COVER)
        {
                if(UNKNOWN!=game_stats.check())
                {
                game_over(game_stats.check());
                return;
                }

        board[i][j].status=UNCOVER;
        game_stats.covered--;
        game_stats.uncovered++;
        draw_square(i,j,UNCOVER);
        uncover_cell(i,j);
                if(UNKNOWN!=game_stats.check())
                {
                game_over(game_stats.check());
                return;
                }
        }
}

/**********right_click******************/
void right_click(int i, int j)
{

 char end_msg[]="YOU HAVE ALREADY FLAGGED 10 MINES";
 if(board[i][j].status==FLAG)
        {
                if(UNKNOWN!=game_stats.check())
                {
                game_over(game_stats.check());
                return;
                }
            board[i][j].status=COVER;
            game_stats.flagged--;
            game_stats.covered++;
                if(UNKNOWN!=game_stats.check())
                {
                game_over(game_stats.check());
                return;
                }
        }
        else if(board[i][j].status==COVER)
        {
            if(game_stats.flagged<10)
            {
                if(UNKNOWN!=game_stats.check())
                {
                game_over(game_stats.check());
                return;
                }
            board[i][j].status=FLAG;
            game_stats.covered--;
            game_stats.flagged++;
                if(UNKNOWN!=game_stats.check())
                {
                game_over(game_stats.check());
                return;
                }
            }
                        else
            printMessage(end_msg);

        }
  draw_square(i,j,board[i][j].status);

}
/*************game_over*******************/
void game_over(int result)
{

if(result!=UNKNOWN)
        {
        glutMouseFunc(NULL);

        if(result==WIN)

        printMessage("YOU WIN");
        else
        //printMessage(game_stats.total_time);
        printMessage("YOU LOSE");
        }

}

 

/**************************************************
                                    Graphic routines
                                  *********************************************/

 

/**********user_input***********/

void user_input(int button,int state,int x,int y)
{
int square_x=x/40;
int square_y=(400-y)/40;

if(button==GLUT_LEFT_BUTTON&&state==GLUT_UP)
    {
        left_click(square_x,square_y);
    }
else if(button==GLUT_RIGHT_BUTTON&&state==GLUT_UP)
    {
        right_click(square_x,square_y);
    }
}


/***********************draw_board**********************/
void draw_board()
{

int x_coord=0,y_coord=0;

//x==glutGet(GLUT_WINDOW_WIDTH);
//y==glutGet(GLUT_WINDOW_HEIGHT);

glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.5,0.5,0.5);
glBegin(GL_LINES);
for(x_coord=0;x_coord<=max_x;x_coord+=xint)
    {

        glVertex3i(x_coord,0,0);
        glVertex3i(x_coord,max_y,0);
    }
for(y_coord=0;y_coord<=max_y;y_coord+=yint)
    {
        glVertex3i(0,y_coord,0);
        glVertex3i(max_x,y_coord,0);
    }
for(int i=0;i<dim;i++)
  {
    for(int j=0;j<dim;j++)
        {

        draw_square(i,j,board[i][j].status);
        if(board[i][j].status==UNCOVER)
            show_content(i,j);

        }
  }

glEnd();
glFlush();

}
/**********draw_square************/
void draw_square(int i,int j,int color)
{
int x,y;
if(color==FLAG)
glColor3f(0.8,0,0);
else if(color==COVER)
glColor3f(0.2,0.9,0.4);
else if(color==UNCOVER)
glColor3f(0,0.5,0.5);
else glColor3f(1,1,1);
x=i*xint;
y=j*yint;
glBegin(GL_POLYGON);
    glVertex3i(x+1,y+1,0);
    glVertex3i(x+1,y+yint-1,0);
    glVertex3i(x+xint-1,y+yint-1,0);
    glVertex3i(x+xint-1,y+1,0);

//printString("Nitesh");
glEnd();
glFlush();

}
/************************print_message********************/
void printMessage(char *msg)
{
glColor3f(0.0,0.0,0.0);
glRasterPos2i(xint*4,yint*4);
printString(msg);
glFlush();
}

/*************************show_content****************/
void show_content(int i,int j)
{
char temp=board[i][j].content+48;
if(board[i][j].content==MINE)
temp=77;
if(board[i][j].content==BLANK)
temp=32;

glColor3f(0.0,0.0,0.0);
glRasterPos2i(i*xint+2,j*yint+2);
printString(&temp);
glFlush();

}

 

/**********gl-init*************/
void gl_init()
{
glClearColor(0.0,0.0,0.0,0);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glOrtho(0.0,100.0,0.0,100.0,-100.0,100.0);
glMatrixMode(GL_MODELVIEW);
glClear(GL_COLOR_BUFFER_BIT);

glFlush();
makeRasterFont();

}
/**********************reshape *************************/
void reshape(int w, int h)
{
/*
   glViewport(0, 0, (GLsizei) w, (GLsizei) h);
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   glOrtho (0.0, w, 0.0, h, -1.0, 1.0);
   glMatrixMode(GL_MODELVIEW);
*/

}
/**********************display *************************/
void display()
{
static int i=0;
draw_board();

game_over(game_stats.check());
}

/*************************Font_display_list*************************/
GLubyte space[] =
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
GLubyte letters[][13] = {
    {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18},
    {0x00, 0x00, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe},
    {0x00, 0x00, 0x7e, 0xe7, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e},
    {0x00, 0x00, 0xfc, 0xce, 0xc7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc7, 0xce, 0xfc},
    {0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0, 0xff},
    {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xff},
    {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xcf, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e},
    {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3},
    {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e},
    {0x00, 0x00, 0x7c, 0xee, 0xc6, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06},
    {0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xe0, 0xf0, 0xd8, 0xcc, 0xc6, 0xc3},
    {0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0},
    {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xff, 0xff, 0xe7, 0xc3},
    {0x00, 0x00, 0xc7, 0xc7, 0xcf, 0xcf, 0xdf, 0xdb, 0xfb, 0xf3, 0xf3, 0xe3, 0xe3},
    {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xe7, 0x7e},
    {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe},
    {0x00, 0x00, 0x3f, 0x6e, 0xdf, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c},
    {0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe},
    {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0xe0, 0xc0, 0xc0, 0xe7, 0x7e},
    {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff},
    {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3},
    {0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3},
    {0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3},
    {0x00, 0x00, 0xc3, 0x66, 0x66, 0x3c, 0x3c, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3},
    {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3},
    {0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x7e, 0x0c, 0x06, 0x03, 0x03, 0xff}
};
GLubyte digits[][13] = {
    {0xff, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xff},
    {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80},
    {0xff, 0x80, 0x80, 0x80, 0x80, 0x80, 0xff, 0x01, 0x01, 0x01, 0x01, 0x01, 0xff},
    {0xff, 0x01, 0x01, 0x01, 0x01, 0x01, 0xff, 0x01, 0x01, 0x01, 0x01, 0x01, 0xff},
    {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xff, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81},
    {0xff, 0x01, 0x01, 0x01, 0x01, 0x01, 0xff, 0x80, 0x80, 0x80, 0x80, 0x80, 0xff},
    {0xff, 0x81, 0x81, 0x81, 0x81, 0x81, 0xff, 0x80, 0x80, 0x80, 0x80, 0x80, 0xff},
    {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xff},
    {0xff, 0x81, 0x81, 0x81, 0x81, 0x81, 0xff, 0x81, 0x81, 0x81, 0x81, 0x81, 0xff},
    {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xff, 0x81, 0x81, 0x81, 0x81, 0x81, 0xff}
    };
GLuint fontOffset;

void makeRasterFont(void)
{
   GLuint i, j;
   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

   fontOffset = glGenLists (128);
   for (i = 0,j = 'A'; i < 26; i++,j++) {
      glNewList(fontOffset + j, GL_COMPILE);
      glBitmap(8, 13, 0.0, 2.0, 10.0, 0.0, letters[i]);
      glEndList();
   }
   for (i = 0,j = '0'; i < 10; i++,j++) {
      glNewList(fontOffset + j, GL_COMPILE);
      glBitmap(8, 13, 0.0, 2.0, 10.0, 0.0, digits[i]);
      glEndList();
   }
   glNewList(fontOffset + ' ', GL_COMPILE);
   glBitmap(8, 13, 0.0, 2.0, 10.0, 0.0, space);
   glEndList();
}
void printString(char *s)
{
   glPushAttrib (GL_LIST_BIT);
   glListBase(fontOffset);
   glCallLists(strlen(s), GL_UNSIGNED_BYTE, (GLubyte *) s);
   glPopAttrib ();
}

Download Source Code

Download EXE file

 

No code can be free of bugs. Please don't hesitate to post your doubts and suggestions in on our discussion forum