📄 minefield.cpp
字号:
int c1 = clipx / cellSize; int c2 = ( clipx + clipw - 1 ) / cellSize; int r1 = clipy / cellSize; int r2 = ( clipy + cliph - 1 ) / cellSize; for ( int c = c1; c <= c2 ; c++ ) { for ( int r = r1; r <= r2 ; r++ ) { int x = c * cellSize; int y = r * cellSize; Mine *m = mine( r, c ); if ( m ) m->paint( p, colorGroup(), QRect(x, y, cellSize, cellSize ) ); } }}// Chicken and egg problem: We need to know how big the parent is// before we can decide how big to make the table.void MineField::setAvailableRect( const QRect &r ){ availableRect = r; int newCellSize = findCellSize(); if ( newCellSize == cellSize ) { setCellSize( cellSize ); } else { viewport()->setUpdatesEnabled( FALSE ); setCellSize( newCellSize ); viewport()->setUpdatesEnabled( TRUE ); viewport()->repaint( TRUE ); }}int MineField::findCellSize(){ int w = availableRect.width() - 2; int h = availableRect.height() - 2; int cellsize; cellsize = QMIN( w/numCols, h/numRows ); cellsize = QMIN( QMAX( cellsize, minGrid ), maxGrid ); return cellsize;}void MineField::setCellSize( int cellsize ){ int b = 2; int w2 = cellsize*numCols; int h2 = cellsize*numRows; int w = QMIN( availableRect.width(), w2+b ); int h = QMIN( availableRect.height(), h2+b ); // // Don't rely on the change in cellsize to force a resize, // as it's possible to have the same size cells when going // from a large play area to a small one. // resizeContents(w2, h2); if ( availableRect.height() < h2 && availableRect.width() - w > style().scrollBarExtent().width() ) { w += style().scrollBarExtent().width(); } setGeometry( availableRect.x() + (availableRect.width()-w)/2, availableRect.y() + (availableRect.height()-h)/2, w, h ); cellSize = cellsize;}void MineField::placeMines(){ int mines = minecount; while ( mines ) { int col = int((double(rand()) / double(RAND_MAX)) * numCols); int row = int((double(rand()) / double(RAND_MAX)) * numRows); Mine* m = mine( row, col ); if ( m && !m->isMined() && m->state() == Mine::Hidden ) { m->setMined( TRUE ); mines--; } }}void MineField::updateCell( int r, int c ){ updateContents( c*cellSize, r*cellSize, cellSize, cellSize );}void MineField::contentsMousePressEvent( QMouseEvent* e ){ int c = e->pos().x() / cellSize; int r = e->pos().y() / cellSize; if ( onBoard( r, c ) ) cellPressed( r, c ); else currCol = currRow = -1;}void MineField::contentsMouseReleaseEvent( QMouseEvent* e ){ int c = e->pos().x() / cellSize; int r = e->pos().y() / cellSize; if ( onBoard( r, c ) && c == currCol && r == currRow ) cellClicked( r, c ); if ( flagAction == FlagNext ) { flagAction = NoAction; }}/* state == Waiting means no "hold" */void MineField::cellPressed( int row, int col ){ if ( state() == GameOver ) return; currRow = row; currCol = col; if ( state() == Playing ) holdTimer->start( 150, TRUE );}void MineField::held(){ flagAction = FlagNext; updateMine( currRow, currCol ); ignoreClick = TRUE;}void MineField::keyPressEvent( QKeyEvent* e ){#if defined(Q_WS_QWS) || defined(_WS_QWS_) flagAction = ( e->key() == Key_Up ) ? FlagOn : NoAction;#else flagAction = ( ( e->state() & ShiftButton ) == ShiftButton ) ? FlagOn : NoAction;#endif}void MineField::keyReleaseEvent( QKeyEvent* ){ flagAction = NoAction;}int MineField::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++ ) { Mine* m = mine( r, c ); if ( m && m->isMined() ) hint++; } return hint;}void MineField::setHint( int row, int col ){ Mine *m = mine( row, col ); if ( !m ) return; int hint = getHint( row, col ); if ( !hint ) { for ( int c = col-1; c <= col+1; c++ ) for ( int r = row-1; r <= row+1; r++ ) { Mine* m = mine( r, c ); if ( m && m->state() == Mine::Hidden ) { m->activate( TRUE ); nonminecount--; setHint( r, c ); updateCell( r, c ); } } } m->setHint( hint ); updateCell( row, col );}/* Only place mines after first click, since it is pointless to kill the player before the game has started.*/void MineField::cellClicked( int row, int col ){ if ( state() == GameOver ) return; if ( state() == Waiting ) { Mine* m = mine( row, col ); if ( !m ) return; m->setState( Mine::Empty ); nonminecount--; placeMines(); setState( Playing ); emit gameStarted(); updateMine( row, col ); } else { // state() == Playing holdTimer->stop(); if ( ignoreClick ) ignoreClick = FALSE; else updateMine( row, col ); }}void MineField::updateMine( int row, int col ){ Mine* m = mine( row, col ); if ( !m ) return; bool wasFlagged = m->state() == Mine::Flagged; bool wasEmpty = m->state() == Mine::Empty; m->activate( flagAction == NoAction ); if ( m->state() == Mine::Exploded ) { emit gameOver( FALSE ); setState( GameOver ); return; } else if ( m->state() == Mine::Empty ) { setHint( row, col ); if ( !wasEmpty ) nonminecount--; } if ( flagAction != NoAction ) { if ( m->state() == Mine::Flagged ) { if (mineguess > 0) { --mineguess; emit mineCount( mineguess ); if ( m->isMined() ) --minecount; } else { m->setState(Mine::Hidden); } } else if ( wasFlagged ) { ++mineguess; emit mineCount( mineguess ); if ( m->isMined() ) ++minecount; } } updateCell( row, col ); if ( !minecount && !mineguess || !nonminecount ) { emit gameOver( TRUE ); setState( GameOver ); }}void MineField::showMines(){ for ( int c = 0; c < numCols; c++ ) for ( int r = 0; r < numRows; r++ ) { Mine* m = mine( r, c ); if ( !m ) continue; if ( m->isMined() && m->state() == Mine::Hidden ) m->setState( Mine::Mined ); if ( !m->isMined() && m->state() == Mine::Flagged ) m->setState( Mine::Wrong ); updateCell( r, c ); }}void MineField::paletteChange( const QPalette &o ){ Mine::paletteChange(); QScrollView::paletteChange( o );}void MineField::writeConfig(Config& cfg) const{ cfg.setGroup("Field"); cfg.writeEntry("Level",lev); QString grid=""; if ( stat == Playing ) { for ( int x = 0; x < numCols; x++ ) for ( int y = 0; y < numRows; y++ ) { char code='A'+(x*17+y*101)%21; // Reduce the urge to cheat const Mine* m = mine( y, x ); int st = (int)m->state(); if ( m->isMined() ) st+=5; grid += code + st; } } cfg.writeEntry("Grid",grid);}void MineField::readConfig(Config& cfg){ cfg.setGroup("Field"); lev = cfg.readNumEntry("Level",1); setup(lev); flagAction = NoAction; ignoreClick = FALSE; currRow = currCol = 0; QString grid = cfg.readEntry("Grid"); int x; if ( !grid.isEmpty() ) { int i=0; minecount=0; mineguess=0; for ( x = 0; x < numCols; x++ ) { for ( int y = 0; y < numRows; y++ ) { char code='A'+(x*17+y*101)%21; // Reduce the urge to cheat int st = (char)(QChar)grid[i++]-code; Mine* m = mine( y, x ); if ( st >= 5 ) { st-=5; m->setMined(TRUE); minecount++; mineguess++; } m->setState((Mine::MineState)st); switch ( m->state() ) { case Mine::Flagged: if (m->isMined()) minecount--; mineguess--; break; case Mine::Empty: --nonminecount; break; default: break; } } } for ( x = 0; x < numCols; x++ ) { for ( int y = 0; y < numRows; y++ ) { Mine* m = mine( y, x ); if ( m->state() == Mine::Empty ) m->setHint(getHint(y,x)); } } } setState( Playing ); emit mineCount( mineguess );}QSize MineField::sizeHint() const{ if ( qApp->desktop()->width() >= 240 ) return QSize(200,200); else return QSize(160, 160);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -