主要实现了设置大小,雷的数目以及查看结果的功能。
完成后界面:
MineSweeper类主要是负责总体界面的显示。
MineSquare主要负责每个小方框的显示。
Data负责数据的生成。
感觉没啥好介绍的,如果有需要改进或者疑问的地方请告诉我~~
#ifndef MINEDATAGENERATOR_H
#define MINEDATAGENERATOR_H
#include <vector>
#include <string>
using namespace std;
class MineDataGenerator {
public:
enum State{
FLAG = 0,
UNCERTAIN,
NORMAL,
SWEEPED
};
class MineData{
public:
int digits;//0~8,9 means mine self
State state;
MineData() :
state(NORMAL) ,
digits(0)
{
}
};
MineDataGenerator(int rows = 9, int cols = 9, int mineCounts = 64);
~MineDataGenerator()
{
for ( int i=0; i<mRows; ++i)
delete mMineData[i];
delete [] mMineData;
}
void getRoundSquare(int col, int row, vector<int> &rows, vector<int> &cols);
bool isMine(int row, int col)
{
return (mMineData[row][col].digits==9);
}
bool isSweeped(int row, int col)
{
return (getState(row,col)==SWEEPED);
}
State getState(int row, int col)
{
return mMineData[row][col].state;
}
void setState(int row, int col, State s)
{
mMineData[row][col].state = s;
}
int getDigit(int row, int col)
{
return mMineData[row][col].digits;
}
string getText(int row, int col)
{
switch(getState(row,col)) {
case FLAG :
return ">";
break;
case UNCERTAIN:
return "?";
break;
case NORMAL:
return "";
case SWEEPED:
if (mMineData[row][col].digits!=9)
if (mMineData[row][col].digits==0)
return string();
else
return string(1,'0'+mMineData[row][col].digits);
else
return "*";
}
}
void print();
//private:
void generateMineData();
bool check()
{
for ( int i=0; i<mRows; ++i)
for ( int j=0; j<mColumns; ++j)
if (((mMineData[i][j].digits==9)&&(mMineData[i][j].state!=FLAG)) ||
((mMineData[i][j].digits!=9)&&(mMineData[i][j].state!=SWEEPED)))
return false;
return true;
}
private:
int mColumns;
int mRows;
int mMineCounts;
MineData **mMineData;
};
#endif//MINEDATAGENERATOR_H
#ifndef MINESQUARE_H
#define MINESQUARE_H
#include <QPushButton>
#include <QMouseEvent>
class MineSquare : public QPushButton {
Q_OBJECT
public:
MineSquare(int i = 0, int j = 0, QWidget *parent = 0);
void setIndex(int i, int j)
{
mRowIndex = i;
mColIndex = j;
}
void setMined(bool r=true) { mined = r; }
signals:
void maskChanged(int i, int j);
void mineSweeped(int i, int j);
protected:
virtual void paintEvent(QPaintEvent *event);
virtual void mousePressEvent(QMouseEvent *event);
private:
int mRowIndex;
int mColIndex;
bool mined;
};
#endif//MINESQUARE_H
#ifndef MINESWEEPER_H
#define MINESWEEPER_H
#include <QWidget>
#include <QIntValidator>
using namespace std;
class MineSquare;
class QLineEdit;
class QPushButton;
class MineDataGenerator;
typedef MineSquare* MineSquarePtr;
class MineSweeper : public QWidget {
Q_OBJECT
public:
MineSweeper(int rows = 9, int cols = 9, int mineCounts = 64, int max = 30, QWidget *parent = 0);
private slots:
void changeMask(int,int);
void sweepMine(int,int);
void showAllMines(int m ,int n);
void showAllMines();
void reset();
private:
void resetSize();
private:
int mRows;
int mCols;
int mMineCounts;
const int maxSide;
MineSquarePtr **mMineSquare;
QLineEdit *mRowsEdit;
QIntValidator *mRowsVa;
QLineEdit *mColsEdit;
QIntValidator *mColsVa;
QLineEdit *mMineCountsEdit;
QPushButton *mCheckButton;
QPushButton *mAgainButton;
QPushButton *mSetButton;
MineDataGenerator *mMineDataGenerator;
};
#endif//MINESWEEPER_H
#include <stdlib.h>
#include <time.h>
#include <iostream>
#include "MineDataGenerator.h"
MineDataGenerator::MineDataGenerator(int rows, int cols, int mineCounts) :
mRows(rows) ,
mColumns(cols) ,
mMineCounts(mineCounts)
{
if (mMineCounts>mRows*mColumns) {
mRows = 9;
mColumns = 9;
mMineCounts = 64;
}
generateMineData();
}
void MineDataGenerator::generateMineData()
{
mMineData = new MineData*[mRows];
for ( int i=0; i<mRows; ++i)
mMineData[i] = new MineData[mColumns];
//generate mines
int i = 0;
while (i<mMineCounts) {
int r = rand()%mRows;
int c = rand()%mColumns;
if (mMineData[r][c].digits!=9) {
mMineData[r][c].digits = 9;
++i;
}
}
//cout << __FUNCTION__ << "\tL:" << __LINE__ << endl;
//cal digits for else
for ( int i=0; i<mRows; ++i)
for ( int j=0; j<mColumns; ++j) {
if (!isMine(i,j)) {
vector<int> roundRows,roundCols;
getRoundSquare(i,j,roundRows,roundCols);
if (roundRows.size()!=roundCols.size()) {
return;
}
for ( size_t m=0; m<roundRows.size(); ++m) {
if (isMine(roundRows[m],roundCols[m]))
mMineData[i][j].digits++;
}
}
}
}
void MineDataGenerator::getRoundSquare(int row, int col, vector<int> &rows, vector<int> &cols)
{
//cout << __FUNCTION__ << "\trow = " << row << "\tcol = " << col << endl;
rows.clear();
cols.clear();
for ( int m=row-1; m<=row+1; ++m)
for ( int n=col-1; n<=col+1; ++n) {
if ((m>=0)&&(m<mRows)&&(n>=0)&&(n<mColumns)) {
if ((m==row)&&(n==col))
continue;
rows.push_back(m);
cols.push_back(n);
}
}
}
void MineDataGenerator::print()
{
for ( int i=0; i<mRows; ++i) {
for ( int j=0; j<mColumns; ++j) {
cout << mMineData[i][j].digits << " ";
}
cout << endl;
}
}
#include <QPainter>
#include "MineSquare.h"
MineSquare::MineSquare(int i, int j, QWidget *parent) :
QPushButton(parent) ,
mRowIndex(i) ,
mColIndex(j) ,
mined(false)
{
setFixedSize(30,30);
setWindowOpacity(0.1);
}
void MineSquare::mousePressEvent(QMouseEvent *event)
{
QPushButton::mousePressEvent(event);
if (event->button()==Qt::LeftButton)
emit mineSweeped(mRowIndex, mColIndex);
else if (event->button()==Qt::RightButton)
emit maskChanged(mRowIndex, mColIndex);
}
void MineSquare::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.drawRect(1,1,width()-2,height()-2);
if (!isFlat()) {
QLinearGradient grad(QPointF(0,0),QPointF(width(),height()));
grad.setColorAt(0,Qt::blue);
grad.setColorAt(1,Qt::green);
painter.fillRect(1,1,width()-2,height()-2,QBrush(grad));
}
if (mined) {
painter.fillRect(1,1,width()-2,height()-2,QBrush(Qt::red));
}
QPushButton::paintEvent(event);
}
#include <QDebug>
#include <QLineEdit>
#include <QPushButton>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QGridLayout>
#include <QMessageBox>
#include "MineSquare.h"
#include "MineDataGenerator.h"
#include "MineSweeper.h"
MineSweeper::MineSweeper(int rows, int cols, int mineCounts, int max, QWidget *parent) :
QWidget(parent) ,
mRows(rows) ,
mCols(cols) ,
maxSide(max) ,
mMineCounts(mineCounts)
{
QGridLayout *mineLayout = new QGridLayout;
mMineSquare = new MineSquarePtr*[maxSide];
for ( int i=0; i<maxSide; ++i) {
mMineSquare[i] = new MineSquarePtr[maxSide];
}
for ( int i=0; i<maxSide; ++i)
for ( int j=0; j<maxSide; ++j) {
mMineSquare[i][j] = NULL;
}
for ( int i=0; i<maxSide; ++i) {
for (int j=0; j<maxSide; ++j) {
mMineSquare[i][j] = new MineSquare(i,j,this);
mMineSquare[i][j]->hide();
mineLayout->addWidget(mMineSquare[i][j],i,j);
connect(mMineSquare[i][j],SIGNAL(maskChanged(int,int)),this,SLOT(changeMask(int,int)));
connect(mMineSquare[i][j],SIGNAL(mineSweeped(int,int)),this,SLOT(sweepMine(int,int)));
}
}
mineLayout->setSpacing(0);
mMineDataGenerator = new MineDataGenerator(mRows, mCols, mMineCounts);
mMineDataGenerator->print();
mRowsEdit = new QLineEdit("9",this);
mColsEdit = new QLineEdit("9",this);
mMineCountsEdit = new QLineEdit("10",this);
mAgainButton = new QPushButton("&Again",this);
mCheckButton = new QPushButton("&Check",this);
connect(mCheckButton,SIGNAL(clicked()),this,SLOT(showAllMines()));
connect(mAgainButton,SIGNAL(clicked()),this,SLOT(reset()));
QVBoxLayout *rightLayout= new QVBoxLayout;
rightLayout->addWidget(mRowsEdit);
rightLayout->addWidget(mColsEdit);
rightLayout->addWidget(mMineCountsEdit);
rightLayout->addWidget(mAgainButton);
rightLayout->addWidget(mCheckButton);
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addLayout(mineLayout);
mainLayout->addLayout(rightLayout);
setLayout(mainLayout);
mRowsVa = new QIntValidator(1,maxSide,this);
mColsVa = new QIntValidator(1,maxSide,this);
mRowsEdit->setValidator(mRowsVa);
mColsEdit->setValidator(mColsVa);
resetSize();
}
void MineSweeper::resetSize()
{
for ( int i=0; i<maxSide; ++i)
for ( int j=0; j<maxSide; ++j)
if ((i>=0&&i<mRows)&&(j>=0&&j<mCols)) {
if (mMineSquare[i][j]->isHidden())
mMineSquare[i][j]->show();
} else{
if (mMineSquare[i][j]->isVisible())
mMineSquare[i][j]->hide();
}
update();
}
void MineSweeper::changeMask(int i, int j)
{
if (mMineDataGenerator->isSweeped(i,j))
return;
MineDataGenerator::State s = mMineDataGenerator->getState(i,j);
if (s==MineDataGenerator::FLAG)
s = MineDataGenerator::UNCERTAIN;
else if (s==MineDataGenerator::UNCERTAIN)
s = MineDataGenerator::NORMAL;
else if (s==MineDataGenerator::NORMAL)
s = MineDataGenerator::FLAG;
else
return;
mMineDataGenerator->setState(i,j,s);
mMineSquare[i][j]->setText(mMineDataGenerator->getText(i,j).c_str());
update();
if (mMineDataGenerator->check())
QMessageBox::information(this,"Tips","W");
}
void MineSweeper::sweepMine(int i, int j)
{
if (mMineDataGenerator->isSweeped(i,j))
return;
MineDataGenerator::State s = mMineDataGenerator->getState(i,j);
if (s==MineDataGenerator::FLAG)
return;
if (mMineDataGenerator->isMine(i,j)) {
showAllMines(i, j);
update();
return;
}
mMineDataGenerator->setState(i,j,MineDataGenerator::SWEEPED);
mMineSquare[i][j]->setFlat(true);
mMineSquare[i][j]->setText(mMineDataGenerator->getText(i,j).c_str());
int digit = mMineDataGenerator->getDigit(i,j);
if (digit==0) {
vector<int> roundRows;
vector<int> roundCols;
mMineDataGenerator->getRoundSquare(i,j,roundRows,roundCols);
for (size_t m=0; m<roundRows.size(); ++m) {
sweepMine(roundRows[m],roundCols[m]);
}
}
update();
if (mMineDataGenerator->check())
QMessageBox::information(this,"Tips","W");
}
void MineSweeper::showAllMines()
{
for ( int i=0; i<mRows; ++i)
for ( int j=0; j<mCols; ++j) {
if (mMineDataGenerator->isMine(i,j) &&
mMineDataGenerator->getState(i,j)!=MineDataGenerator::FLAG) {
mMineDataGenerator->setState(i,j,MineDataGenerator::SWEEPED);
mMineSquare[i][j]->setFlat(true);
mMineSquare[i][j]->setText(mMineDataGenerator->getText(i,j).c_str());
}
}
}
void MineSweeper::showAllMines(int m, int n)
{
mMineSquare[m][n]->setMined();
showAllMines();
}
void MineSweeper::reset()
{
mRows = mRowsEdit->text().toInt();
mCols = mColsEdit->text().toInt();
mMineCounts = mMineCountsEdit->text().toInt();
if (mMineCounts=1) {
mMineCountsEdit->setText("1");
mMineCounts>mRows*mCols;
}
delete mMineDataGenerator;
mMineDataGenerator = new MineDataGenerator(mRows, mCols, mMineCounts);
resetSize();
for ( int i=0; i<mRows; ++i)
for ( int j=0; j<mCols; ++j) {
mMineSquare[i][j]->setFlat(false);
mMineSquare[i][j]->setMined(false);
mMineSquare[i][j]->setText("");
}
}