Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

linesboard.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002                           linesboard.cpp  -  description
00003                              -------------------
00004     begin                : Fri May 19 2000
00005     copyright            : (C) 2000 by Roman Merzlyakov
00006     email                : roman@sbrf.barrt.ru
00007     copyright            : (C) 2000 by Roman Razilov
00008     email                : Roman.Razilov@gmx.de
00009  ***************************************************************************/
00010 
00011 /***************************************************************************
00012  *                                                                         *
00013  *   This program is free software; you can redistribute it and/or modify  *
00014  *   it under the terms of the GNU General Public License as published by  *
00015  *   the Free Software Foundation; either version 2 of the License, or     *
00016  *   (at your option) any later version.                                   *
00017  *                                                                         *
00018  ***************************************************************************/
00019 #include <qpainter.h>
00020 #include <stdlib.h>
00021 
00022 #include "linesboard.h"
00023 
00024 /*
00025    Constructs a LinesBoard widget.
00026 */
00027 
00028 LinesBoard::LinesBoard( BallPainter * abPainter, QWidget* parent, const char* name )
00029     : Field( parent, name )
00030 {
00031   anim = ANIM_NO;
00032 //  waypos = 0;
00033 //  waylen = 0;
00034 //  jumpingRow = -1;
00035 //  jumpingCol = -1;
00036   painting = 0;
00037   way = new Waypoints[NUMCELLSW*NUMCELLSH];
00038 
00039   bPainter = abPainter;
00040 
00041   setFocusPolicy( NoFocus );
00042   setBackgroundColor( gray );
00043 
00044   setMouseTracking( FALSE );
00045   setFixedSize(wHint(), hHint());
00046 
00047   timer = new QTimer(this);
00048   connect( timer, SIGNAL(timeout()), SLOT(timerSlot()) );
00049   timer->start( TIMERCLOCK, FALSE );
00050 
00051 }
00052 
00053 /*
00054    Destructor: deallocates memory for contents
00055 */
00056 
00057 LinesBoard::~LinesBoard()
00058 {
00059   // debug("stop");
00060   timer->stop();
00061   delete timer;
00062   delete []way;
00063 }
00064 
00065 
00066 void LinesBoard::placeBalls(int pnextBalls[BALLSDROP])
00067 {
00068     debug("LinesBoard::placeBalls( )");
00069     for(int i=0; i < BALLSDROP; i++){
00070       nextBalls[i] = pnextBalls[i];
00071     }
00072     nextBallToPlace = 0;
00073     placeBall();
00074     debug("LinesBoard::placeBalls End ");
00075 }
00076 void LinesBoard::placeBall(  )
00077 {
00078                 int color = nextBalls[nextBallToPlace];
00079     debug("LinesBoard::placeBall( ) color=%i, nextBallToPlace = %i", color, nextBallToPlace);
00080     char* xx = (char*)malloc( sizeof(char)*NUMCELLSW*NUMCELLSH );
00081     char* yy = (char*)malloc( sizeof(char)*NUMCELLSW*NUMCELLSH );
00082 //    int nb=3;
00083 //    if( freeSpace() < 3) nb = freeSpace();
00084     int empty=0;
00085     for(int y=0; y<NUMCELLSH; y++)
00086       for(int x=0; x<NUMCELLSW; x++)
00087         if( getBall(x,y) == NOBALL )
00088         {
00089           xx[empty] = x;
00090           yy[empty] = y;
00091           empty++;
00092         };
00093 //      debug("empty = %i",empty);
00094     if ( empty >  0)
00095     {
00096       int pos = rand()%empty;
00097       putBall( xx[pos], yy[pos], color );
00098       clearAnim();
00099       setAnim( xx[pos], yy[pos], ANIM_BORN );
00100                         nextBallToPlace++;
00101       AnimStart(ANIM_BORN);
00102       free(xx);
00103       free(yy);
00104     }
00105     else
00106     {
00107       free(xx);
00108       free(yy);
00109       emit endGame();
00110     }
00111     debug("LinesBoard::placeBall END");
00112 }
00113 
00114 
00115 /*id LinesBoard::doAfterBalls() {
00116   erase5Balls();
00117   repaint(FALSE);
00118 }
00119 */
00120 /*
00121    Sets the size of the table
00122 */
00123 
00124 int LinesBoard::width() { return CELLSIZE * NUMCELLSW; }
00125 int LinesBoard::height() { return CELLSIZE * NUMCELLSH; }
00126 int LinesBoard::wHint() { return width(); }
00127 int LinesBoard::hHint() { return height(); }
00128 
00129 
00130 
00131 void LinesBoard::paintEvent( QPaintEvent* )
00132 {
00133 //  debug("LinesBoard::paintEvent ");
00134         QPixmap pixmap(width(), height());
00135         QPainter paint(&pixmap, this);
00136 
00137     for( int y=0; y < NUMCELLSH; y++ ){
00138         for( int x=0; x < NUMCELLSW; x++ ){
00139           if( getBall(x,y) == NOBALL )
00140                                         {
00141 //            debug("draw empty  %i %i", x, y );
00142             paint.drawPixmap(x*CELLSIZE, y*CELLSIZE, *(bPainter->GetBackgroundPix()) );
00143                                         }
00144           else
00145           {
00146 //            debug("draw empty  %i %i %c", x, y, getBall(x,y) );
00147             paint.drawPixmap(x*CELLSIZE, y*CELLSIZE,
00148               *(bPainter->GetBall(getBall(x,y),animstep,getAnim(x,y))));
00149           }
00150         }
00151     }
00152 
00153         bitBlt(this, 0,0, &pixmap, 0,0, width(), height(), CopyROP);
00154 }
00155 
00156 /*
00157    Handles mouse press events for the LinesBoard widget.
00158 */
00159 void LinesBoard::mousePressEvent( QMouseEvent* e )
00160 {
00161   debug("LinesBoard::mousePressEvent START");
00162   int curRow = e->y() / CELLSIZE;
00163   int curCol = e->x() / CELLSIZE;
00164   //debug
00165   debug("Mouse pressed: curRow=%i, curCol=%i", curRow, curCol);
00166 
00167   //check range
00168   if (!checkBounds( curCol, curRow ) )
00169     return;
00170 //    if( running || anim != ANIM_NO )  return;
00171   if(anim != ANIM_JUMP && anim != ANIM_NO) return;
00172   if ( anim == ANIM_JUMP )
00173   {
00174     if ( getBall(curCol,curRow) == NOBALL )
00175     {
00176       if(existPath(jumpingCol, jumpingRow, curCol, curRow))
00177                         {
00178                                 saveUndo();
00179         AnimStart(ANIM_RUN);
00180                         }
00181     }
00182     else
00183       AnimJump(curCol,curRow);
00184   }
00185   else
00186     AnimJump(curCol,curRow);
00187   debug("LinesBoard::mousePressEvent END");
00188 }
00189 void LinesBoard::AnimJump(int x, int y ) {
00190   debug("LinesBoard::AnimJump( %i,%i)", x,y );
00191   if ( getBall(x,y) != NOBALL )
00192     if (!( anim == ANIM_JUMP &&  jumpingCol == x && jumpingRow == y ))
00193       if ( AnimEnd() )
00194       {
00195         clearAnim();
00196         setAnim(x,y,ANIM_JUMP);
00197         jumpingCol = x;
00198         jumpingRow = y;
00199         AnimStart(ANIM_JUMP);
00200       }
00201   debug("LinesBoard::AnimJump END");
00202 }
00203 void LinesBoard::AnimStart(int panim) {
00204   debug("LinesBoard::AnimStart( %i )", panim);
00205   if (anim != ANIM_NO)
00206     AnimEnd();
00207   animstep = 0;
00208   animdelaystart = 1;
00209   switch(panim) {
00210     case ANIM_NO:
00211         break;
00212     case ANIM_BORN:
00213         debug("LinesBoard::AnimStart( ANIM_BORN )");
00214         animdelaystart=1;
00215         animmax = BOOMBALLS;
00216         break;
00217     case ANIM_JUMP:
00218         direction = -1;
00219         animstep = 4;
00220         animmax = PIXTIME -1;
00221         break;
00222     case ANIM_RUN:
00223         animdelaystart=3;
00224         // do first step on next timer;
00225         animdelaycount = 0;
00226         // animmax already set
00227         break;
00228     case ANIM_BURN:
00229         animdelaystart=1;
00230         animmax = FIREBALLS + FIREPIX - 1;
00231         break;
00232     default:
00233       ;
00234   }
00235   anim = panim;
00236   animdelaycount = animdelaystart;
00237   debug("LinesBoard::AnimStart END");
00238 }
00239 int LinesBoard::AnimEnd( )
00240 {
00241   debug("LinesBoard::AnimEnd( %i )",anim );
00242   if (anim == ANIM_NO ) return true;
00243   int oldanim = anim;
00244   anim = ANIM_NO;
00245   if (oldanim == ANIM_RUN) {
00246     if (animstep != animmax) {
00247       moveBall(way[animstep].x,way[animstep].y,way[animmax].x,way[animmax].y);
00248           }
00249           if ( erase5Balls() == 0 ) {
00250             // debug("end turn");
00251             emit endTurn();
00252                   debug("LinesBoard::AnimEnd END true 1");
00253             return true;
00254           }
00255           else
00256                   debug("LinesBoard::AnimEnd END false 2");
00257             return false;
00258         } else if ( oldanim == ANIM_BURN )
00259         {
00260     emit eraseLine( deleteAnimatedBalls() );
00261     repaint(FALSE);
00262     if ( nextBallToPlace < BALLSDROP )
00263     {
00264       placeBall();
00265       // continue with born
00266                   debug("LinesBoard::AnimEnd END false 3");
00267       return false;
00268     }
00269     else
00270     {
00271       // emit endTurn();
00272                   debug("LinesBoard::AnimEnd END true 4");
00273       return true;
00274     }
00275   } else if ( oldanim == ANIM_BORN )
00276   {
00277           if ( erase5Balls() == 0 )
00278           {
00279             if ( freeSpace() > 0)
00280             {
00281         if ( nextBallToPlace < BALLSDROP )
00282         {
00283           placeBall();
00284                           debug("LinesBoard::AnimEnd END false 5");
00285           return false;
00286         }
00287         else
00288         {
00289                           debug("LinesBoard::AnimEnd END true 6");
00290           return true;
00291         }
00292       }
00293       else
00294       {
00295                           debug("emit endGame");
00296         emit endGame();
00297                           debug("LinesBoard::AnimEnd END false 7");
00298         return false;
00299       }
00300     }
00301     else
00302     {
00303       // wait for user input
00304                   debug("LinesBoard::AnimEnd END true 8");
00305       return true;
00306     }
00307   }
00308   else
00309   {
00310           debug("LinesBoard::AnimEnd END true");
00311     return true;
00312   }
00313   return true;
00314 }
00315 void LinesBoard::AnimNext() {
00316   if ( anim != ANIM_NO )
00317   {
00318     debug("LinesBoard::AnimNext( ) anim %i animstep %i",anim,animstep);
00319     if ( anim == ANIM_JUMP ) {
00320       if ( (direction > 0 && animstep == animmax) || ( direction < 0 && animstep == 0))
00321         direction = -direction;
00322       animstep += direction;
00323       repaint(FALSE);
00324     } else {
00325       if ( animstep >= animmax )
00326         AnimEnd();
00327       else {
00328         animdelaycount--;
00329         if (animdelaycount <= 0) {
00330           debug("LinesBoard::AnimNext step %i", animstep);
00331           if ( anim == ANIM_RUN )
00332             moveBall(way[animstep].x,way[animstep].y,way[animstep+1].x,way[animstep+1].y);
00333           animstep++;
00334           animdelaycount = animdelaystart;
00335           repaint( FALSE );
00336         }
00337       }
00338     }
00339     debug("LinesBoard::AnimNext END");
00340   }
00341 }
00342 int LinesBoard::getAnim( int x, int y )
00343 {
00344 //   debug("LinesBoard::getAnim( %i,%i )",x,y);
00345   return (( Field::getAnim(x,y) != ANIM_NO )? anim : ANIM_NO);
00346 }
00347 
00348 void LinesBoard::timerSlot()
00349 {
00350 //  debug("LinesBoard::Timer()  anim = %i",anim );
00351   AnimNext();
00352 }
00353 
00354 int LinesBoard::erase5Balls()
00355 {
00356     //debug
00357     debug("LinesBoard::erase5Balls()");
00358 
00359     int nb=5;  // minimum balls for erasure
00360 
00361     bool bit_erase[NUMCELLSH][NUMCELLSW]; //bool array for balls, that must be erased
00362     for(int y=0; y<NUMCELLSH; y++)
00363       for(int x=0; x<NUMCELLSW; x++)
00364         bit_erase[y][x] = false;
00365 
00366     int color,newcolor;
00367     int count;
00368     //for horisontal
00369     //debug("entering to horiz");
00370 
00371     for(int y=0; y<NUMCELLSH; y++) {
00372       count = 1;
00373       color = NOBALL;
00374       for(int x=0; x<NUMCELLSW; x++){
00375         if ( (newcolor = getBall(x,y)) == color) {
00376             if ( color != NOBALL) {
00377                 count++;
00378                 if ( count >= nb )
00379                     if ( count == nb )
00380                         for (int i = 0; i < nb; i++)
00381                             bit_erase[y][x-i] = true;
00382                     else bit_erase[y][x] = true;
00383             }
00384         } else {
00385             color = newcolor;
00386             count = 1;
00387         }
00388       }
00389     }
00390 
00391     //for vertical
00392     //debug("entering to vert");
00393     for(int x=0; x<NUMCELLSW; x++) {
00394       count = 0;
00395       color = NOBALL;
00396       for(int y=0; y<NUMCELLSH; y++){
00397         if ( (newcolor = getBall(x,y)) == color) {
00398             if ( color != NOBALL) {
00399                 count++;
00400                 if ( count >= nb )
00401                     if ( count == nb )
00402                         for (int i = 0; i < nb; i++)
00403                             bit_erase[y-i][x] = true;
00404                     else bit_erase[y][x] = true;
00405             }
00406         } else {
00407             color = newcolor;
00408             count = 1;
00409         }
00410       }
00411     }
00412 
00413 
00414     //  debug("entering to diag1");
00415     //for left-down to rigth-up diagonal
00416     for ( int xs = NUMCELLSW-1,ys = NUMCELLSH-nb; xs >= nb-1; ) {
00417         count = 0;
00418         color = NOBALL;
00419         for ( int x = xs, y = ys; x >= 0 && y < NUMCELLSH; x--, y++ ) {
00420             if ( (newcolor = getBall(x,y)) == color) {
00421                 if ( color != NOBALL) {
00422                     count++;
00423                     if ( count >= nb )
00424                         if ( count == nb )
00425                             for (int i = 0; i < nb; i++)
00426                                 bit_erase[y-i][x+i] = true;
00427                         else bit_erase[y][x] = true;
00428                 }
00429             } else {
00430                 color = newcolor;
00431                 count = 1;
00432             }
00433         }
00434         if ( ys > 0 ) ys--; else xs--;
00435     }
00436 
00437     //debug("entering to diag2");
00438 
00439     //for left-up to rigth-down diagonal
00440     for ( int xs = 0,ys = NUMCELLSH-nb; xs <= NUMCELLSW-nb; )
00441     {
00442         count = 0;
00443         color = NOBALL;
00444         for ( int x = xs, y = ys; x < NUMCELLSW && y < NUMCELLSH; x++, y++ )
00445         {
00446             if ( (newcolor = getBall(x,y)) == color)
00447             {
00448                 if ( color != NOBALL)
00449                 {
00450                     count++;
00451                     if ( count >= nb )
00452                         if ( count == nb )
00453                             for (int i = 0; i < nb; i++)
00454                                 bit_erase[y-i][x-i] = true;
00455                         else
00456                           bit_erase[y][x] = true;
00457                 }
00458             }
00459             else
00460             {
00461                 color = newcolor;
00462                 count = 1;
00463             }
00464         }
00465         if ( ys > 0 ) ys--; else xs++;
00466     }
00467 
00468     //remove all lines balls, that more than nb
00469     int cb=0;
00470     for(int y=0; y < NUMCELLSH; y++)
00471       for(int x=0; x < NUMCELLSW; x++)
00472       {
00473                                 if (bit_erase[y][x])
00474                                 {
00475                 setAnim(x,y,ANIM_YES);
00476                 cb++;
00477                                 }
00478                                 else
00479                                 {
00480                 setAnim(x,y,ANIM_NO);
00481         }
00482       }
00483     //debug
00484     debug("LinesBoard::erase5Balls marked %i balls", cb);
00485     if ( cb > 0 )
00486     {
00487       AnimStart(ANIM_BURN);
00488       //emit eraseLine(cb);
00489     }
00490 
00491     //debug
00492     debug("LinesBoard::erase5Balls END");
00493     return cb;
00494 }
00495 
00496 
00497 #define GO_EMPTY    4
00498 #define GO_A        5
00499 #define GO_B        6
00500 #define GO_BALL     7
00501 
00502 bool LinesBoard::existPath(int bx, int by, int ax, int ay)
00503 {
00504   debug("LinesBoard::existPath( %i, %i, %i, %i )", bx, by, ax, ay);
00505   int dx[4]={1,-1, 0, 0};
00506   int dy[4]={0, 0, 1,-1};
00507 
00508   // debug("path %i %i %i %i",bx,by,ax,ay);
00509   if (getBall(ax,ay) != NOBALL)
00510     return false;
00511 
00512   char pf[NUMCELLSH][NUMCELLSW];
00513   for(int y=0; y<NUMCELLSH; y++)
00514     for(int x=0; x<NUMCELLSW; x++)
00515       pf[y][x] = (getBall(x,y) == NOBALL) ? GO_EMPTY:GO_BALL;
00516 
00517   Waypoints lastchanged[2][NUMCELLSH*NUMCELLSW];
00518 
00519   int lastChangedCount[2];
00520   int currentchanged = 0;
00521   int nextchanged = 1;
00522   lastchanged[currentchanged][0].x = ax;
00523   lastchanged[currentchanged][0].y = ay;
00524   lastChangedCount[currentchanged] = 1;
00525   pf[ay][ax]=GO_A;
00526   pf[by][bx]=GO_B;
00527 
00528   // int expanded;
00529   bool B_reached = false;
00530 
00531   do
00532   {
00533     lastChangedCount[nextchanged] = 0;
00534     for(int dir=0; dir<4; dir++)
00535     {
00536       for ( int i = 0 ; i < lastChangedCount[currentchanged]; i++ )
00537       {
00538         int nx = lastchanged[currentchanged][i].x + dx[dir];
00539         int ny = lastchanged[currentchanged][i].y + dy[dir];
00540         if( (nx>=0) && (nx<NUMCELLSW) && (ny>=0) && (ny<NUMCELLSH) )
00541         {
00542           if( pf[ny][nx]==GO_EMPTY ||( nx==bx && ny==by ))
00543           {
00544             pf[ny][nx] = dir;
00545             lastchanged[nextchanged][lastChangedCount[nextchanged]].x = nx;
00546             lastchanged[nextchanged][lastChangedCount[nextchanged]].y = ny;
00547             lastChangedCount[nextchanged]++;
00548           };
00549           if( (nx==bx) && (ny==by) )
00550           {
00551             B_reached = true;
00552             break;
00553           }
00554         }
00555       }
00556     }
00557     nextchanged = nextchanged ^ 1;
00558     currentchanged = nextchanged ^ 1;
00559     //      debug("currentchanged %i lastChangedCount[currentchanged] %i",
00560     //      currentchanged,lastChangedCount[currentchanged]);
00561   } while(!B_reached && lastChangedCount[currentchanged] != 0);
00562   //debug("B_reached %i ", B_reached );
00563 
00564   if (B_reached) {
00565     AnimStart( ANIM_BLOCK);
00566     animmax = 0;
00567 //    waypos = 0;
00568     int x, y,dir;
00569     for( x = bx, y = by,dir; (dir = pf[y][x]) != GO_A;x -=dx[dir],y -= dy[dir]) {
00570         way[animmax].x = x;
00571         way[animmax].y = y;
00572         //debug("%i %i %i %i",dir,waylen,x,y);
00573         animmax++;
00574     }
00575     way[animmax].x = x;
00576     way[animmax].y = y;
00577   }
00578   debug("LinesBoard::existPath END %s", B_reached?"true":"false" );
00579   return B_reached;
00580 }
00581 
00582 void LinesBoard::undo()
00583 {
00584         AnimEnd();
00585         restoreUndo();
00586         repaint( FALSE );
00587 }
00588 

Generated on Sat Nov 5 16:17:28 2005 for OPIE by  doxygen 1.4.2