#include "qmlbindablevalue.h" #include "qmlengine.h" #include "qmlcontext.h" #include "qml.h" #include #include #include #include #include #include #include #include #include QString fileName = "minehunt.qml"; class Tile : public QObject { Q_OBJECT public: Tile() : _hasFlag(false), _hasMine(false), _hint(-1), _flipped(false) {} Q_PROPERTY(bool hasFlag READ hasFlag WRITE setHasFlag NOTIFY hasFlagChanged); bool hasFlag() const { return _hasFlag; } Q_PROPERTY(bool hasMine READ hasMine NOTIFY hasMineChanged); bool hasMine() const { return _hasMine; } Q_PROPERTY(int hint READ hint NOTIFY hintChanged); int hint() const { return _hint; } Q_PROPERTY(bool flipped READ flipped NOTIFY flippedChanged()); bool flipped() const { return _flipped; } void setHasFlag(bool flag) {if(flag==_hasFlag) return; _hasFlag = flag; emit hasFlagChanged();} void setHasMine(bool mine) {if(mine==_hasMine) return; _hasMine = mine; emit hasMineChanged();} void setHint(int hint) { if(hint == _hint) return; _hint = hint; emit hintChanged(); } void flip() { if (_flipped) return; _flipped = true; emit flippedChanged(); } void unflip() { if(!_flipped) return; _flipped = false; emit flippedChanged(); } signals: void flippedChanged(); void hasFlagChanged(); void hintChanged(); void hasMineChanged(); private: bool _hasFlag; bool _hasMine; int _hint; bool _flipped; }; QML_DECLARE_TYPE(Tile); QML_DEFINE_TYPE(Tile,Tile); class MyWidget : public QWidget { Q_OBJECT public: MyWidget(int = 370, int = 480, QWidget *parent=0, Qt::WindowFlags flags=0); ~MyWidget(); Q_PROPERTY(QList *tiles READ tiles); QList *tiles() { return &_tiles; } Q_PROPERTY(bool isPlaying READ isPlaying NOTIFY isPlayingChanged); bool isPlaying() {return playing;} Q_PROPERTY(bool hasWon READ hasWon NOTIFY hasWonChanged); bool hasWon() {return won;} Q_PROPERTY(int numMines READ numMines NOTIFY numMinesChanged); int numMines() const{return nMines;} Q_PROPERTY(int numFlags READ numFlags NOTIFY numFlagsChanged); int numFlags() const{return nFlags;} public slots: Q_INVOKABLE void flip(int row, int col); Q_INVOKABLE void flag(int row, int col); void setBoard(); void reset(); signals: void isPlayingChanged(); void hasWonChanged(); void numMinesChanged(); void numFlagsChanged(); private: bool onBoard( int r, int c ) const { return r >= 0 && r < numRows && c >= 0 && c < numCols; } Tile *tile( int row, int col ) { return onBoard(row, col) ? _tiles[col+numRows*row] : 0; } int getHint(int row, int col); void setPlaying(bool b){if(b==playing) return; playing=b; emit isPlayingChanged();} QFxView *canvas; QList _tiles; int numCols; int numRows; bool playing; bool won; int remaining; int nMines; int nFlags; }; MyWidget::MyWidget(int width, int height, QWidget *parent, Qt::WindowFlags flags) : QWidget(parent, flags), canvas(0), numCols(9), numRows(9), playing(true), won(false) { setObjectName("mainWidget"); srand(QTime(0,0,0).secsTo(QTime::currentTime())); //initialize array for(int ii = 0; ii < numRows * numCols; ++ii) { _tiles << new Tile; } reset(); QVBoxLayout *vbox = new QVBoxLayout; vbox->setMargin(0); setLayout(vbox); canvas = new QFxView(this); canvas->setFixedSize(width, height); vbox->addWidget(canvas); QFile file(fileName); file.open(QFile::ReadOnly); QString xml = file.readAll(); canvas->setXml(xml, fileName); QmlContext *ctxt = canvas->rootContext(); ctxt->activate(); ctxt->addDefaultObject(this); ctxt->deactivate(); canvas->execute(); } MyWidget::~MyWidget() { } void MyWidget::setBoard() { foreach(Tile* t, _tiles){ t->setHasMine(false); t->setHint(-1); } //place mines int mines = nMines; remaining = numRows*numCols-mines; while ( mines ) { int col = int((double(rand()) / double(RAND_MAX)) * numCols); int row = int((double(rand()) / double(RAND_MAX)) * numRows); Tile* t = tile( row, col ); if (t && !t->hasMine()) { t->setHasMine( true ); mines--; } } //set hints for (int r = 0; r < numRows; r++) for (int c = 0; c < numCols; c++) { Tile* t = tile(r, c); if (t && !t->hasMine()) { int hint = getHint(r,c); t->setHint(hint); } } setPlaying(true); } void MyWidget::reset() { foreach(Tile* t, _tiles){ t->unflip(); t->setHasFlag(false); } nMines = 12; nFlags = 0; setPlaying(false); QTimer::singleShot(900,this, SLOT(setBoard())); } int MyWidget::getHint(int row, int col) { int hint = 0; for (int c = col-1; c <= col+1; c++) for (int r = row-1; r <= row+1; r++) { Tile* t = tile(r, c); if (t && t->hasMine()) hint++; } return hint; } void MyWidget::flip(int row, int col) { if(!playing) return; Tile *t = tile(row, col); if (!t || t->hasFlag()) return; if(t->flipped()){ int flags = 0; for (int c = col-1; c <= col+1; c++) for (int r = row-1; r <= row+1; r++) { Tile *nearT = tile(r, c); if(!nearT || nearT == t) continue; if(nearT->hasFlag()) flags++; } if(!t->hint() || t->hint() != flags) return; for (int c = col-1; c <= col+1; c++) for (int r = row-1; r <= row+1; r++) { Tile *nearT = tile(r, c); if (nearT && !nearT->flipped() && !nearT->hasFlag()) { flip( r, c ); } } return; } t->flip(); if (t->hint() == 0) { for (int c = col-1; c <= col+1; c++) for (int r = row-1; r <= row+1; r++) { Tile* t = tile(r, c); if (t && !t->flipped()) { flip( r, c ); } } } if(t->hasMine()){ for (int r = 0; r < numRows; r++)//Flip all other mines for (int c = 0; c < numCols; c++) { Tile* t = tile(r, c); if (t && t->hasMine()) { flip(r, c); } } won = false; hasWonChanged(); setPlaying(false); } remaining--; if(!remaining){ won = true; hasWonChanged(); setPlaying(false); } } void MyWidget::flag(int row, int col) { Tile *t = tile(row, col); if(!t) return; t->setHasFlag(!t->hasFlag()); nFlags += (t->hasFlag()?1:-1); emit numFlagsChanged(); } ///////////////////////////////////////////////////////// int main(int argc, char ** argv) { QApplication app(argc, argv); bool frameless = false; int width = 370; int height = 480; for (int i = 1; i < argc; ++i) { QString arg = argv[i]; if (arg == "-frameless") { frameless = true; } else if(arg == "-width" && i < (argc - 1)) { ++i; width = ::atoi(argv[i]); } else if(arg == "-height" && i < (argc - 1)) { ++i; height = ::atoi(argv[i]); } else if (arg[0] != '-') { fileName = arg; } } MyWidget wid(width, height, 0, frameless ? Qt::FramelessWindowHint : Qt::Widget); wid.show(); return app.exec(); } #include "main.moc"