patterncppMinor
Simple Minesweeper using OpenGL / GLUT
Viewed 0 times
simpleglutusingopenglminesweeper
Problem
I'm trying to make minesweeper similar to windows 3.1 minesweeper by using OpenGL / GLUT. The game still in early stage but playable. I would like to know, how can I improve it.
EDIT 1:
i added additional draw functions and fixed drawing order when player step on mine tile.
here image for latest update:
Edit 2:
i have added timer class for animating when player is win or lose to demo and fixed index coordinate from mouse input. also, i added option to restart game at any time by click on game icon "smiley face"
Edit 3):
added drawing functions for primitive shapes (rect, circle) to avoid duplicated.
added Color for readability.
finally, anti-alias is working perfectly under GLUT context.
Edit 4):
removed the old window time with the c++11 std::chrono
```
#include
#include
#include
#include
#include
enum { MINE = 9 };
enum { TILE_SIZE = 20 };
enum { MARGIN = 40 };
enum { PADDING = 10 };
enum { BOARD_SIZE = 9 };
enum { MINE_COUNT = 10 };
enum Color {
RED,
DARKRED,
BLUE,
DARKBLUE,
GREEN,
DARKGREEN,
CYAN,
DARKCYAN,
YELLOW,
DARKYELLOW,
WHITE,
MAGENTA,
BLACK,
DARKGRAY,
LIGHTGRAY,
ULTRALIGHTGRAY
};
static const struct
{
float r, g, b;
} colors[] =
{
{ 1, 0, 0 },// red
{ 0.5f, 0, 0 },// dark red
{ 0, 0, 1 }, // blue
{ 0, 0, 0.5f }, // dark blue
{ 0, 1, 0 }, // green
{ 0, 0.5f, 0 }, // dark green
{ 0, 1, 1 }, // cyan
{ 0, 0.5f, 0.5f }, // dark cyan
{ 1, 1, 0 },//yellow
{ 0.5f, 0.5f, 0 },//dark yellow
{ 1, 1, 1 },// White
{ 1, 0, 1 }, // magenta
{ 0, 0, 0 }, // black
{ 0.25, 0.25, 0.25 }, // dark gray
{ 0.5, 0.5, 0.5 }, // light gray
{ 0.75, 0.75, 0.75 }, // ultra-light gray
};
class Clock
{
typedef std::chrono::time_point time_point;
public:
Clock()
: m_startTime(getCurrentTime())
, m_lastTime()
{
}
double getElapsedTime() const
{
std::chrono::duration elapsed = getCurre
EDIT 1:
i added additional draw functions and fixed drawing order when player step on mine tile.
here image for latest update:
Edit 2:
i have added timer class for animating when player is win or lose to demo and fixed index coordinate from mouse input. also, i added option to restart game at any time by click on game icon "smiley face"
Edit 3):
added drawing functions for primitive shapes (rect, circle) to avoid duplicated.
added Color for readability.
finally, anti-alias is working perfectly under GLUT context.
Edit 4):
removed the old window time with the c++11 std::chrono
```
#include
#include
#include
#include
#include
enum { MINE = 9 };
enum { TILE_SIZE = 20 };
enum { MARGIN = 40 };
enum { PADDING = 10 };
enum { BOARD_SIZE = 9 };
enum { MINE_COUNT = 10 };
enum Color {
RED,
DARKRED,
BLUE,
DARKBLUE,
GREEN,
DARKGREEN,
CYAN,
DARKCYAN,
YELLOW,
DARKYELLOW,
WHITE,
MAGENTA,
BLACK,
DARKGRAY,
LIGHTGRAY,
ULTRALIGHTGRAY
};
static const struct
{
float r, g, b;
} colors[] =
{
{ 1, 0, 0 },// red
{ 0.5f, 0, 0 },// dark red
{ 0, 0, 1 }, // blue
{ 0, 0, 0.5f }, // dark blue
{ 0, 1, 0 }, // green
{ 0, 0.5f, 0 }, // dark green
{ 0, 1, 1 }, // cyan
{ 0, 0.5f, 0.5f }, // dark cyan
{ 1, 1, 0 },//yellow
{ 0.5f, 0.5f, 0 },//dark yellow
{ 1, 1, 1 },// White
{ 1, 0, 1 }, // magenta
{ 0, 0, 0 }, // black
{ 0.25, 0.25, 0.25 }, // dark gray
{ 0.5, 0.5, 0.5 }, // light gray
{ 0.75, 0.75, 0.75 }, // ultra-light gray
};
class Clock
{
typedef std::chrono::time_point time_point;
public:
Clock()
: m_startTime(getCurrentTime())
, m_lastTime()
{
}
double getElapsedTime() const
{
std::chrono::duration elapsed = getCurre
Solution
your scientists were so preoccupied with whether or not they could that they didn't stop to think if they should.
– Dr. Ian Malcolm in Jurassic Park
Use the Tools Available to You
This code exhibits some utterly bizarre constructs that while perfectly legal are so abhorrent I would hope to never see them again in my lifetime. It's hard to know where to begin, so I'll just start from the beginning.
If you're creating constants, make named constants rather than enumerations:
The
You should use proper named types for variables. The idea of directly declaring (a global!) variable after its anonymous type is pretty awful. For one thing, it means you have to manually type the entire type if you ever want to use it again. You manage not to ever use the type for an RGB value again anywhere in the code, but it's just lurking there waiting for you to need it somewhere. For another it's so unusual that other readers of the code will likely either trip over it or not even notice it because they'll think they couldn't possibly have seen something so bizarre.
In most of your methods you don't change the value of the variables you pass in. In that case, you should mark them as
Don't Use Global Variables
By using global variables, it becomes very difficult to figure out where they are modified. When they are encapsulated properly in classes you can much more easily understand how the data is modified and by whom. There's a very obvious class structure for this code staring you in the face where most of the globals are declared:
All of your
Simplify
Lots of things in this code seem more complicated than they need to be. You declare what should be a 2-dimensional array as a single dimensional array and then have to write a special function to properly index into it. I have recommended this method myself when there is a performance reason to do it. But with this 9 x 9 game board, there's no reason to do it. Just use a 2-dimensional array:
If you do that then the
The
I would personally recommend removing all of the drawing code. It's complicated, uses deprecated OpenGL calls and is inefficient. Instead of drawing things manually with lines and rectangles you should be drawing them with textures.
Your
– Dr. Ian Malcolm in Jurassic Park
Use the Tools Available to You
This code exhibits some utterly bizarre constructs that while perfectly legal are so abhorrent I would hope to never see them again in my lifetime. It's hard to know where to begin, so I'll just start from the beginning.
If you're creating constants, make named constants rather than enumerations:
const int MINE = 9;
const int TILE_SIZE = 20;
// … etc.The
enum for Color is just fine.You should use proper named types for variables. The idea of directly declaring (a global!) variable after its anonymous type is pretty awful. For one thing, it means you have to manually type the entire type if you ever want to use it again. You manage not to ever use the type for an RGB value again anywhere in the code, but it's just lurking there waiting for you to need it somewhere. For another it's so unusual that other readers of the code will likely either trip over it or not even notice it because they'll think they couldn't possibly have seen something so bizarre.
In most of your methods you don't change the value of the variables you pass in. In that case, you should mark them as
const so someone reading your code knows at a glance that the variables will not change.Don't Use Global Variables
By using global variables, it becomes very difficult to figure out where they are modified. When they are encapsulated properly in classes you can much more easily understand how the data is modified and by whom. There's a very obvious class structure for this code staring you in the face where most of the globals are declared:
class MineSweeper {
public:
// whatever public methods you need
private:
cell board[BOARD_SIZE * BOARD_SIZE];
int death;
int width;
int height;
bool clicked;
int num_opened;
};All of your
draw methods could go into a Render class, or something similar.Simplify
Lots of things in this code seem more complicated than they need to be. You declare what should be a 2-dimensional array as a single dimensional array and then have to write a special function to properly index into it. I have recommended this method myself when there is a performance reason to do it. But with this 9 x 9 game board, there's no reason to do it. Just use a 2-dimensional array:
cell board[BOARD_SIZE][BOARD_SIZE];If you do that then the
isOpen(), getType(), setType(), and isFlag() functions go away.The
isMine() function can be simplified to the boundary checks and this line:return (getType(x,y) == MINE);I would personally recommend removing all of the drawing code. It's complicated, uses deprecated OpenGL calls and is inefficient. Instead of drawing things manually with lines and rectangles you should be drawing them with textures.
Your
drawNum() method is using bare numbers in a case statement that then reads values out of an array. It could be simplified to 3 lines by doing this:void drawNum(int x, int y, int v)
{
glColor3f(colors[v].r, colors[v].g, colors[v].b);
glRasterPos2i((x + 0)*TILE_SIZE + PADDING + 6, (y + 0)*TILE_SIZE + PADDING + 5);
glutBitmapCharacter(GLUT_BITMAP_9_BY_15, '0' + v);
}Code Snippets
const int MINE = 9;
const int TILE_SIZE = 20;
// … etc.class MineSweeper {
public:
// whatever public methods you need
private:
cell board[BOARD_SIZE * BOARD_SIZE];
int death;
int width;
int height;
bool clicked;
int num_opened;
};cell board[BOARD_SIZE][BOARD_SIZE];return (getType(x,y) == MINE);void drawNum(int x, int y, int v)
{
glColor3f(colors[v].r, colors[v].g, colors[v].b);
glRasterPos2i((x + 0)*TILE_SIZE + PADDING + 6, (y + 0)*TILE_SIZE + PADDING + 5);
glutBitmapCharacter(GLUT_BITMAP_9_BY_15, '0' + v);
}Context
StackExchange Code Review Q#158957, answer score: 2
Revisions (0)
No revisions yet.