00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "tictac.h"
00012 #include <qpe/qpeapplication.h>
00013 #include <qdrawutil.h>
00014 #include <qcombobox.h>
00015 #include <qlabel.h>
00016 #include <qlayout.h>
00017 #include <stdlib.h>
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 TicTacButton::TicTacButton( QWidget *parent ) : QPushButton( parent )
00029 {
00030 t = Blank;
00031 }
00032
00033
00034
00035
00036
00037 void TicTacButton::drawButtonLabel( QPainter *p )
00038 {
00039 QRect r = rect();
00040 p->setPen( QPen( white,2 ) );
00041 if ( t == Circle ) {
00042 p->drawEllipse( r.left()+4, r.top()+4, r.width()-8, r.height()-8 );
00043 } else if ( t == Cross ) {
00044 p->drawLine( r.topLeft() +QPoint(4,4), r.bottomRight()-QPoint(4,4));
00045 p->drawLine( r.bottomLeft()+QPoint(4,-4),r.topRight() -QPoint(4,-4));
00046 }
00047 }
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059 TicTacGameBoard::TicTacGameBoard( int n, QWidget *parent, const char *name )
00060 : QWidget( parent, name )
00061 {
00062 QPEApplication::showWidget( this );
00063 st = Init;
00064 nBoard = n;
00065 n *= n;
00066 comp_starts = FALSE;
00067 buttons = new TicTacButtons(n);
00068 btArray = new TicTacArray(n);
00069 QGridLayout * grid = new QGridLayout( this, 3, 3, 4 );
00070 QPalette p( blue );
00071 for ( int i=0; i<n; i++ ) {
00072 TicTacButton *ttb = new TicTacButton( this );
00073 ttb->setPalette( p );
00074 ttb->setEnabled( FALSE );
00075 connect( ttb, SIGNAL(clicked()), SLOT(buttonClicked()) );
00076 grid->addWidget( ttb, i%3, i/3 );
00077 buttons->insert( i, ttb );
00078 btArray->at(i) = TicTacButton::Blank;
00079 }
00080 QTime t = QTime::currentTime();
00081 srand( t.hour()*12+t.minute()*60+t.second()*60 );
00082
00083 }
00084
00085 TicTacGameBoard::~TicTacGameBoard()
00086 {
00087 delete buttons;
00088 delete btArray;
00089 }
00090
00091
00092
00093
00094
00095
00096
00097
00098 void TicTacGameBoard::computerStarts( bool v )
00099 {
00100 comp_starts = v;
00101 }
00102
00103
00104
00105
00106
00107
00108
00109
00110 void TicTacGameBoard::newGame()
00111 {
00112 st = HumansTurn;
00113 for ( int i=0; i<nBoard*nBoard; i++ )
00114 btArray->at(i) = TicTacButton::Blank;
00115 if ( comp_starts )
00116 computerMove();
00117 else
00118 updateButtons();
00119 }
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129 void TicTacGameBoard::buttonClicked()
00130 {
00131 if ( st != HumansTurn )
00132 return;
00133 int i = buttons->findRef( (TicTacButton*)sender() );
00134 TicTacButton *b = buttons->at(i);
00135 if ( b->type() == TicTacButton::Blank ) {
00136 btArray->at(i) = TicTacButton::Circle;
00137 updateButtons();
00138 if ( checkBoard( btArray ) == 0 )
00139 computerMove();
00140 int s = checkBoard( btArray );
00141 if ( s ) {
00142 st = s == TicTacButton::Circle ? HumanWon : ComputerWon;
00143 emit finished();
00144 }
00145 }
00146 }
00147
00148
00149
00150
00151
00152
00153
00154
00155 void TicTacGameBoard::updateButtons()
00156 {
00157 for ( int i=0; i<nBoard*nBoard; i++ ) {
00158 if ( buttons->at(i)->type() != btArray->at(i) )
00159 buttons->at(i)->setType( (TicTacButton::Type)btArray->at(i) );
00160 buttons->at(i)->setEnabled( buttons->at(i)->type() ==
00161 TicTacButton::Blank );
00162 }
00163 }
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177 int TicTacGameBoard::checkBoard( TicTacArray *a )
00178 {
00179 int t = 0;
00180 int row, col;
00181 bool won = FALSE;
00182 for ( row=0; row<nBoard && !won; row++ ) {
00183 t = a->at(row*nBoard);
00184 if ( t == TicTacButton::Blank )
00185 continue;
00186 col = 1;
00187 while ( col<nBoard && a->at(row*nBoard+col) == t )
00188 col++;
00189 if ( col == nBoard )
00190 won = TRUE;
00191 }
00192 for ( col=0; col<nBoard && !won; col++ ) {
00193 t = a->at(col);
00194 if ( t == TicTacButton::Blank )
00195 continue;
00196 row = 1;
00197 while ( row<nBoard && a->at(row*nBoard+col) == t )
00198 row++;
00199 if ( row == nBoard )
00200 won = TRUE;
00201 }
00202 if ( !won ) {
00203 t = a->at(0);
00204 if ( t != TicTacButton::Blank ) {
00205 int i = 1;
00206 while ( i<nBoard && a->at(i*nBoard+i) == t )
00207 i++;
00208 if ( i == nBoard )
00209 won = TRUE;
00210 }
00211 }
00212 if ( !won ) {
00213 int j = nBoard-1;
00214 int i = 0;
00215 t = a->at(i+j*nBoard);
00216 if ( t != TicTacButton::Blank ) {
00217 i++; j--;
00218 while ( i<nBoard && a->at(i+j*nBoard) == t ) {
00219 i++; j--;
00220 }
00221 if ( i == nBoard )
00222 won = TRUE;
00223 }
00224 }
00225 if ( !won )
00226 t = 0;
00227 return t;
00228 }
00229
00230
00231
00232
00233
00234
00235
00236
00237 void TicTacGameBoard::computerMove()
00238 {
00239 int numButtons = nBoard*nBoard;
00240 int *altv = new int[numButtons];
00241 int altc = 0;
00242 int stopHuman = -1;
00243 TicTacArray a = btArray->copy();
00244 int i;
00245 for ( i=0; i<numButtons; i++ ) {
00246 if ( a[i] != TicTacButton::Blank )
00247 continue;
00248 a[i] = TicTacButton::Cross;
00249 if ( checkBoard(&a) == a[i] ) {
00250 st = ComputerWon;
00251 stopHuman = -1;
00252 break;
00253 }
00254 a[i] = TicTacButton::Circle;
00255 if ( checkBoard(&a) == a[i] ) {
00256 stopHuman = i;
00257 a[i] = TicTacButton::Blank;
00258 continue;
00259 }
00260 a[i] = TicTacButton::Blank;
00261 altv[altc++] = i;
00262 }
00263 if ( stopHuman >= 0 )
00264 a[stopHuman] = TicTacButton::Cross;
00265 else if ( i == numButtons ) {
00266 if ( altc > 0 )
00267 a[altv[rand()%(altc--)]] = TicTacButton::Cross;
00268 if ( altc == 0 ) {
00269 st = NobodyWon;
00270 emit finished();
00271 }
00272 }
00273 *btArray = a;
00274 updateButtons();
00275 delete[] altv;
00276 }
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288 TicTacToe::TicTacToe( QWidget *parent, const char *name, WFlags fl )
00289 : QWidget( parent, name, fl )
00290 {
00291 QVBoxLayout * l = new QVBoxLayout( this, 6 );
00292
00293
00294 boardSize = 3;
00295
00296 message = new QLabel( this );
00297 message->setFrameStyle( QFrame::WinPanel | QFrame::Sunken );
00298 message->setAlignment( AlignCenter );
00299 l->addWidget( message );
00300
00301
00302
00303
00304 board = new TicTacGameBoard( boardSize, this );
00305 connect( board, SIGNAL(finished()), SLOT(gameOver()) );
00306 l->addWidget( board );
00307
00308
00309
00310 QFrame *line = new QFrame( this );
00311 line->setFrameStyle( QFrame::HLine | QFrame::Sunken );
00312 l->addWidget( line );
00313
00314
00315
00316
00317 whoStarts = new QComboBox( this );
00318 whoStarts->insertItem( tr( "Computer starts" ) );
00319 whoStarts->insertItem( tr( "Human starts" ) );
00320 l->addWidget( whoStarts );
00321
00322
00323
00324
00325 newGame = new QPushButton( tr( "Play!" ), this );
00326 connect( newGame, SIGNAL(clicked()), SLOT(newGameClicked()) );
00327 quit = new QPushButton( tr( "Quit" ), this );
00328 connect( quit, SIGNAL(clicked()), qApp, SLOT(quit()) );
00329 QHBoxLayout * b = new QHBoxLayout;
00330 l->addLayout( b );
00331 b->addWidget( newGame );
00332 b->addWidget( quit );
00333 move(0,0);
00334 QPEApplication::showWidget( this );
00335 newState();
00336 }
00337
00338
00339
00340
00341
00342
00343
00344
00345 void TicTacToe::newGameClicked()
00346 {
00347 board->computerStarts( whoStarts->currentItem() == 0 );
00348 board->newGame();
00349 newState();
00350 }
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360 void TicTacToe::gameOver()
00361 {
00362 newState();
00363 }
00364
00365
00366
00367
00368
00369
00370 void TicTacToe::newState()
00371 {
00372 QStringList msg;
00373 msg << tr( "Click Play to start")
00374 << tr("Make your move")
00375 << tr("You won!")
00376 << tr("Computer won!")
00377 << tr("It's a draw");
00378 message->setText( msg[board->state()] );
00379 return;
00380 }