00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "gowidget.h"
00022
00023
00024 #include <opie2/odebug.h>
00025 #include <opie2/oresource.h>
00026 #include <qpe/config.h>
00027 using namespace Opie::Core;
00028
00029
00030 #include <qpainter.h>
00031 #include <qtoolbar.h>
00032 #include <qmenubar.h>
00033 #include <qaction.h>
00034 #include <qapplication.h>
00035 #include <qlabel.h>
00036
00037 static const enum bVal computer_color = BLACK;
00038
00039 static int current_handicap = 1;
00040
00041 static QBrush *goBrush;
00042 static QPixmap *newBlackStone;
00043 static QPixmap *blackStone;
00044 static QPixmap *whiteStone;
00045
00046 static bool smallStones = FALSE;
00047
00048 GoMainWidget::GoMainWidget( QWidget *parent, const char* name, WFlags fl) :
00049 QMainWindow( parent, name, fl )
00050 {
00051 setCaption( tr( "Go" ) );
00052 setToolBarsMovable( FALSE );
00053 GoWidget *go = new GoWidget(this);
00054
00055 setCentralWidget(go);
00056 toolbar = new QToolBar(this);
00057 toolbar->setHorizontalStretchable( TRUE );
00058 addToolBar(toolbar);
00059
00060 QMenuBar *mb = new QMenuBar( toolbar );
00061 mb->setMargin(0);
00062 QPopupMenu *file = new QPopupMenu( this );
00063
00064 QAction *a = new QAction( tr( "New Game" ), QString::null, 0, this, 0 );
00065 connect( a, SIGNAL( activated() ), go, SLOT( newGame() ) );
00066 a->addTo( file );
00067
00068 a = new QAction( tr( "Pass" ), Opie::Core::OResource::loadPixmap( "pass", Opie::Core::OResource::SmallIcon ),
00069 QString::null, 0, this, 0 );
00070 connect( a, SIGNAL( activated() ), go, SLOT( pass() ) );
00071 a->addTo( file );
00072 a->addTo( toolbar );
00073
00074
00075 a = new QAction( tr( "Resign" ), Opie::Core::OResource::loadPixmap( "reset", Opie::Core::OResource::SmallIcon ),
00076 QString::null, 0, this, 0 );
00077 connect( a, SIGNAL( activated() ), go, SLOT( resign() ) );
00078 a->addTo( file );
00079
00080 a = new QAction( tr( "Two player option" ), QString::null, 0, this, 0 );
00081 a->setToggleAction( TRUE );
00082 connect( a, SIGNAL( toggled(bool) ), go, SLOT( setTwoplayer(bool) ) );
00083 a->addTo( file );
00084
00085 mb->insertItem( tr( "Game" ), file );
00086
00087 QLabel *turnLabel = new QLabel( toolbar );
00088 turnLabel->setBackgroundMode( PaletteButton );
00089 connect( go, SIGNAL(showTurn(const QPixmap&)),
00090 turnLabel, SLOT(setPixmap(const QPixmap&)) );
00091
00092
00093 QLabel * scoreLabel = new QLabel( toolbar );
00094 scoreLabel->setBackgroundMode( PaletteButton );
00095 connect( go, SIGNAL(showScore(const QString&)),
00096 scoreLabel, SLOT(setText(const QString&)) );
00097
00098 toolbar->setStretchableWidget( scoreLabel );
00099
00100 go->readConfig();
00101 }
00102
00103 void GoMainWidget::resizeEvent( QResizeEvent * )
00104 {
00105
00106
00107
00108
00109
00110
00111
00112 }
00113
00114 GoWidget *GoWidget::self = 0;
00115
00116 GoWidget::GoWidget( QWidget *parent, const char* name) :
00117 QWidget( parent, name )
00118 {
00119 if ( self )
00120 fatal( "Only one Go widget allowed" );
00121 self = this;
00122 twoplayer = FALSE;
00123
00124
00125 d = bx = by = 1;
00126
00127 QPixmap pix = Opie::Core::OResource::loadPixmap( "go/pine" );
00128 goBrush = new QBrush( black, pix );
00129 blackStone = new QPixmap(Opie::Core::OResource::loadPixmap( "Go-black" ));
00130 whiteStone = new QPixmap(Opie::Core::OResource::loadPixmap( "Go-white" ));
00131 newBlackStone = new QPixmap(Opie::Core::OResource::loadPixmap( "Go-black-highlight" ));
00132
00133 init();
00134 }
00135
00136 GoWidget::~GoWidget()
00137 {
00138 writeConfig();
00139 }
00140
00141 void GoWidget::writeConfig()
00142 {
00143 Config cfg("Go");
00144 cfg.setGroup("Game");
00145 cfg.writeEntry("TwoPlayer", twoplayer);
00146 cfg.writeEntry("CurrentPlayer", currentPlayer);
00147 cfg.writeEntry("NPassed", nPassed);
00148 QString b;
00149 for (int i=0; i<19; i++)
00150 for (int j=0; j<19; j++)
00151 b += board[i][j] == BLACK ? 'B' : board[i][j] == WHITE ? 'W' : '.';
00152 cfg.writeEntry("Board", b);
00153 cfg.writeEntry("LastX", lastX);
00154 cfg.writeEntry("LastY", lastY);
00155 extern int blackPrisoners, whitePrisoners;
00156 cfg.writeEntry("BlackPrisoners", blackPrisoners);
00157 cfg.writeEntry("WhitePrisoners", whitePrisoners);
00158 }
00159
00160 void GoWidget::readConfig()
00161 {
00162 init();
00163 Config cfg("Go");
00164 cfg.setGroup("Game");
00165 twoplayer = cfg.readBoolEntry("TwoPlayer");
00166 currentPlayer = (bVal)cfg.readNumEntry("CurrentPlayer",1);
00167 nPassed = cfg.readNumEntry("NPassed",0);
00168 QString b = cfg.readEntry("Board");
00169 if ( b.length() == 19*19 )
00170 for (int i=0; i<19; i++)
00171 for (int j=0; j<19; j++) {
00172 QChar ch = b[j+19*i];
00173 if ( ch != '.' )
00174 GoPlaceStone( ch == 'B' ? BLACK : WHITE, i, j );
00175 }
00176 lastX = cfg.readNumEntry("LastX");
00177 lastY = cfg.readNumEntry("LastY");
00178 extern int blackPrisoners, whitePrisoners;
00179 blackPrisoners = cfg.readNumEntry("BlackPrisoners",0);
00180 whitePrisoners = cfg.readNumEntry("WhitePrisoners",0);
00181 reportPrisoners(blackPrisoners,whitePrisoners);
00182 emit showTurn( currentPlayer == WHITE ? *whiteStone : *blackStone );
00183 }
00184
00185 void GoWidget::resizeEvent( QResizeEvent * )
00186 {
00187 d = QMIN(width(),height())/19;
00188
00189 bx = (width() - 18*d)/2 ;
00190 by = (height() - 18*d)/2 ;
00191
00192 if ( d < 10 && !smallStones ) {
00193 blackStone->convertFromImage( blackStone->convertToImage().smoothScale(8,8) );
00194 whiteStone->convertFromImage( whiteStone->convertToImage().smoothScale(8,8) );
00195 newBlackStone->convertFromImage( newBlackStone->convertToImage().smoothScale(8,8) );
00196
00197 smallStones = TRUE;
00198 } else if ( d >= 10 && smallStones ) {
00199 blackStone = new QPixmap(Opie::Core::OResource::loadPixmap( "Go-black" ));
00200 whiteStone = new QPixmap(Opie::Core::OResource::loadPixmap( "Go-white" ));
00201 newBlackStone = new QPixmap(Opie::Core::OResource::loadPixmap( "Go-black-highlight" ));
00202 smallStones = FALSE;
00203 }
00204 }
00205
00206 void GoWidget::init()
00207 {
00208 lastX = lastY = newX = newY = -1;
00209 nPassed = 0;
00210 for ( int i = 0; i < 19; i++ )
00211 for ( int j = 0; j < 19; j++ )
00212 board[i][j]=-1;
00213 gameActive = TRUE;
00214 goRestart(current_handicap);
00215
00216 if ( twoplayer ) {
00217 currentPlayer = BLACK;
00218 } else {
00219 doComputerMove();
00220 currentPlayer = WHITE;
00221 }
00222 emit showTurn( currentPlayer == WHITE ? *whiteStone : *blackStone );
00223 }
00224
00225 void GoWidget::paintEvent( QPaintEvent *e )
00226 {
00227 int i,j;
00228
00229 int r = whiteStone->width()/2;
00230
00231 QPainter p(this);
00232 p.fillRect( bx - d/2, by - d/2, 19*d, 19*d, *goBrush );
00233
00234 int xMin = QMAX( x2board(e->rect().left()), 0 );
00235 int xMax = QMIN( x2board(e->rect().right()), 18 );
00236 int yMin = QMAX( y2board(e->rect().top()), 0 );
00237 int yMax = QMIN( y2board(e->rect().bottom()), 18 );
00238
00239 QColor pine( 255, 186, 89 );
00240 p.setPen( pine.dark() );
00241
00242 for ( i = xMin; i < xMax+1 ; i ++ ) {
00243 p.drawLine( bx+i*d, by, bx+i*d, by+18*d );
00244 }
00245 for ( j = yMin; j < yMax+1 ; j ++ ) {
00246 p.drawLine( bx, by+j*d, bx+18*d, by+j*d);
00247 }
00248
00249
00250 p.setBrush( black );
00251 for ( i = 3; i < xMax+1; i+=6 )
00252 for ( j = 3; j < yMax+1; j+=6 )
00253 p.drawEllipse( bx+i*d-2, by+j*d-2, 5, 5 );
00254
00255
00256 for ( i = xMin; i < xMax+1; i++ )
00257 for ( j = yMin; j < yMax+1; j++ ) {
00258 if ( board[i][j] == WHITE ||
00259 currentPlayer==WHITE && newX == i && newY == j )
00260 p.drawPixmap( bx+i*d - r, by+j*d - r, *whiteStone );
00261 else if ( i == lastX && j == lastY )
00262 p.drawPixmap( bx+i*d - r, by+j*d - r, *newBlackStone );
00263 else if ( board[i][j] == BLACK ||
00264 currentPlayer==BLACK && newX == i && newY == j)
00265 p.drawPixmap( bx+i*d - r, by+j*d - r, *blackStone );
00266 }
00267 }
00268
00269 void GoWidget::doMove( int x, int y )
00270 {
00271
00272 if ( !GoPlaceStone( currentPlayer, x, y ) ) {
00273
00274 return;
00275 }
00276
00277 nPassed = 0;
00278 if ( twoplayer )
00279 currentPlayer = (currentPlayer==WHITE) ? BLACK : WHITE;
00280 else
00281 doComputerMove();
00282
00283 emit showTurn( currentPlayer == WHITE ? *whiteStone : *blackStone );
00284
00285 }
00286
00287 void GoWidget::pass()
00288 {
00289 if ( !gameActive )
00290 return;
00291 nPassed++;
00292 if ( nPassed >= 2 )
00293 endGame();
00294 else if ( !twoplayer )
00295 doComputerMove();
00296 }
00297
00298 void GoWidget::resign()
00299 {
00300 if ( gameActive )
00301 endGame();
00302 }
00303
00304
00305 void GoWidget::newGame()
00306 {
00307 init();
00308 update();
00309 }
00310
00311
00312 void GoWidget::endGame()
00313 {
00314 gameActive = FALSE;
00315
00316 int w,b;
00317 CountUp( &w, &b);
00318 QString s = tr("White %1, Black %2. ").arg(w).arg(b);
00319 if ( w > b )
00320 s += tr("White wins.");
00321 else if ( w < b )
00322 s += tr("Black wins.");
00323 else
00324 s += tr("A draw.");
00325 emit showScore( s );
00326 }
00327
00328 void GoWidget::doComputerMove()
00329 {
00330 int ox = lastX;
00331 int oy = lastY;
00332 lastX = lastY = -1;
00333 emit showTurn( *blackStone );
00334 refresh( ox, oy);
00335 qApp->processEvents();
00336 short int x,y;
00337 if ( genMove( computer_color, &x, &y ) ) {
00338 lastX = x;
00339 lastY = y;
00340
00341 GoPlaceStone(computer_color,x,y);
00342 nPassed = 0;
00343 } else {
00344 emit showScore( tr("I pass") );
00345 nPassed++;
00346 if ( nPassed >= 2 )
00347 endGame();
00348 }
00349 }
00350
00351 void GoWidget::mousePressEvent( QMouseEvent *me )
00352 {
00353 if ( !gameActive )
00354 return;
00355 int x = x2board(me->x());
00356 int y = y2board(me->y());
00357 showStone(x,y,currentPlayer);
00358 }
00359
00360 void GoWidget::mouseMoveEvent( QMouseEvent *me )
00361 {
00362 if ( !gameActive )
00363 return;
00364 int x = x2board(me->x());
00365 int y = y2board(me->y());
00366 if ( x != newX || y != newY )
00367 showStone(x,y,currentPlayer);
00368 }
00369
00370 void GoWidget::showStone( int x, int y, enum bVal c )
00371 {
00372
00373 if ( newX > -1 ) {
00374 refresh( newX, newY );
00375 newY = newX = -1;
00376 }
00377 if ( x < 0 || x > 18 || y < 0 || y > 18 ) {
00378 newX = newY = -1;
00379 return;
00380 }
00381 if ( board[x][y] == -1 && !Suicide( c, x, y ) ) {
00382 newX = x;
00383 newY = y;
00384 refresh(x,y);
00385 }
00386
00387 }
00388
00389 void GoWidget::mouseReleaseEvent( QMouseEvent * )
00390 {
00391 if ( gameActive && newX > -1 )
00392 doMove( newX, newY );
00393 newX = newY = -1;
00394 }
00395
00396 void GoWidget::refresh( int x, int y )
00397 {
00398 update( bx+d*x-d/2-1, by+d*y-d/2-1, d+2, d+2 );
00399 }
00400
00401 void GoWidget::removeStone(short x, short y)
00402 {
00403 board[x][y]=-1;
00404 refresh( x, y );
00405 }
00406
00407 void GoWidget::placeStone (enum bVal c, short x, short y )
00408 {
00409 board[x][y]=c;
00410 refresh( x, y );
00411 }
00412
00413 void GoWidget::reportPrisoners( int blackcnt, int whitecnt )
00414 {
00415 QString s = tr( "Prisoners: black %1, white %2" ).arg(blackcnt).arg(whitecnt);
00416 emit showScore( s );
00417 }
00418
00419 void GoWidget::setTwoplayer( bool b )
00420 {
00421 twoplayer = b;
00422 }
00423
00424 void GoWidget::setHandicap( int h )
00425 {
00426 current_handicap = h;
00427 }
00428
00429
00430 extern "C" {
00431
00432 void removestone(short x, short y)
00433 {
00434 GoWidget::self->removeStone(x,y);
00435 }
00436
00437 void placestone (enum bVal c, short x, short y )
00438 {
00439 GoWidget::self->placeStone(c,x,y);
00440 }
00441
00442 void intrMoveReport(enum bVal c ,char *coord ,char *reason )
00443 {
00444 odebug << "intrMoveReport colour " << c << ", " << coord << " " << reason << "" << oendl;
00445 }
00446
00447 void intrPrisonerReport( short blackcnt, short whitecnt )
00448 {
00449 GoWidget::self->reportPrisoners(blackcnt,whitecnt);
00450 }
00451
00452 }
00453