summaryrefslogtreecommitdiff
path: root/noncore/games/minesweep/minefield.cpp
authorerik <erik>2007-01-22 23:01:41 (UTC)
committer erik <erik>2007-01-22 23:01:41 (UTC)
commitadcf6075db477909dd8170a74862a6ef91a5127f (patch) (side-by-side diff)
treeda0a1e35c5d392271bce29e84d3af5c30a864f56 /noncore/games/minesweep/minefield.cpp
parent9b4871054d01a47b4c546952a0948553413840d6 (diff)
downloadopie-adcf6075db477909dd8170a74862a6ef91a5127f.zip
opie-adcf6075db477909dd8170a74862a6ef91a5127f.tar.gz
opie-adcf6075db477909dd8170a74862a6ef91a5127f.tar.bz2
Each file in this commit had a problem where a function might return
a null value for a pointer and that null value was not checked.
Diffstat (limited to 'noncore/games/minesweep/minefield.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/games/minesweep/minefield.cpp4
1 files changed, 3 insertions, 1 deletions
diff --git a/noncore/games/minesweep/minefield.cpp b/noncore/games/minesweep/minefield.cpp
index 72c05b0..1987ea5 100644
--- a/noncore/games/minesweep/minefield.cpp
+++ b/noncore/games/minesweep/minefield.cpp
@@ -323,425 +323,427 @@ void MineField::setState( State st )
}
void MineField::setup( int level )
{
lev = level;
setState( Waiting );
//viewport()->setUpdatesEnabled( FALSE );
int i;
for ( i = 0; i < numCols*numRows; i++ )
delete mines[i];
delete[] mines;
switch( lev ) {
case 1:
numRows = 9 ;
numCols = 9 ;
minecount = 12;
break;
case 2:
numRows = 13;
numCols = 13;
minecount = 33;
break;
case 3:
numCols = 18;
numRows = 18;
minecount = 66 ;
break;
}
mines = new Mine* [numRows*numCols];
for ( i = 0; i < numCols*numRows; i++ )
mines[i] = new Mine( this );
nonminecount = numRows*numCols - minecount;
mineguess = minecount;
emit mineCount( mineguess );
Mine::paletteChange();
if ( availableRect.isValid() )
setCellSize(findCellSize());
// viewport()->setUpdatesEnabled( TRUE );
//viewport()->repaint( TRUE );
updateContents( 0, 0, numCols*cellSize, numRows*cellSize );
updateGeometry();
}
void MineField::drawContents( QPainter * p, int clipx, int clipy, int clipw, int cliph )
{
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 (!m)
+ continue;
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 )
+ if ( m && 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);
}