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

tictac.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002  ** tictac.cpp,v 1.3.8.1 2003/08/29 06:50:40 harlekin Exp
00003  **
00004  ** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
00005  **
00006  ** This file is part of an example program for Qt.  This example
00007  ** program may be used, distributed and modified without limitation.
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>       // rand() function
00018 
00019 
00020 //***************************************************************************
00021 //* TicTacButton member functions
00022 //***************************************************************************
00023 
00024 // --------------------------------------------------------------------------
00025 // Creates a TicTacButton
00026 //
00027 
00028 TicTacButton::TicTacButton( QWidget *parent ) : QPushButton( parent )
00029 {
00030     t = Blank;          // initial type
00031 }
00032 
00033 // --------------------------------------------------------------------------
00034 // Paints TicTacButton
00035 //
00036 
00037 void TicTacButton::drawButtonLabel( QPainter *p )
00038 {
00039     QRect r = rect();
00040     p->setPen( QPen( white,2 ) );   // set fat pen
00041     if ( t == Circle ) {
00042         p->drawEllipse( r.left()+4, r.top()+4, r.width()-8, r.height()-8 );
00043     } else if ( t == Cross ) {      // draw 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 //* TicTacGameBoard member functions
00052 //***************************************************************************
00053 
00054 // --------------------------------------------------------------------------
00055 // Creates a game board with N x N buttons and connects the "clicked()"
00056 // signal of all buttons to the "buttonClicked()" slot.
00057 //
00058 
00059 TicTacGameBoard::TicTacGameBoard( int n, QWidget *parent, const char *name )
00060         : QWidget( parent, name )
00061 {
00062     QPEApplication::showWidget( this );
00063     st = Init;          // initial state
00064     nBoard = n;
00065     n *= n;         // make square
00066     comp_starts = FALSE;      // human starts
00067     buttons = new TicTacButtons(n);   // create real buttons
00068     btArray = new TicTacArray(n);   // create button model
00069     QGridLayout * grid = new QGridLayout( this, 3, 3, 4 );
00070     QPalette p( blue );
00071     for ( int i=0; i<n; i++ ) {     // create and connect buttons
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; // initial button type
00079     }
00080     QTime t = QTime::currentTime();   // set random seed
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 // TicTacGameBoard::computerStarts( bool v )
00094 //
00095 // Computer starts if v=TRUE. The human starts by default.
00096 //
00097 
00098 void TicTacGameBoard::computerStarts( bool v )
00099 {
00100     comp_starts = v;
00101 }
00102 
00103 
00104 // --------------------------------------------------------------------------
00105 // TicTacGameBoard::newGame()
00106 //
00107 // Clears the game board and prepares for a new game
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 // TicTacGameBoard::buttonClicked()   - SLOT
00124 //
00125 // This slot is activated when a TicTacButton emits the signal "clicked()",
00126 // i.e. the user has clicked on a TicTacButton.
00127 //
00128 
00129 void TicTacGameBoard::buttonClicked()
00130 {
00131     if ( st != HumansTurn )     // not ready
00132         return;
00133     int i = buttons->findRef( (TicTacButton*)sender() );
00134     TicTacButton *b = buttons->at(i);   // get piece that was pressed
00135     if ( b->type() == TicTacButton::Blank ) { // empty piece?
00136         btArray->at(i) = TicTacButton::Circle;
00137         updateButtons();
00138         if ( checkBoard( btArray ) == 0 ) // not a winning move?
00139             computerMove();
00140         int s = checkBoard( btArray );
00141         if ( s ) {        // any winners yet?
00142             st = s == TicTacButton::Circle ? HumanWon : ComputerWon;
00143             emit finished();
00144         }
00145     }
00146 }
00147 
00148 
00149 // --------------------------------------------------------------------------
00150 // TicTacGameBoard::updateButtons()
00151 //
00152 // Updates all buttons that have changed state
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 // TicTacGameBoard::checkBoard()
00168 //
00169 // Checks if one of the players won the game, works for any board size.
00170 //
00171 // Returns:
00172 //  - TicTacButton::Cross  if the player with X buttons won
00173 //  - TicTacButton::Circle if the player with O buttons won
00174 //  - Zero (0) if there is no winner yet
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++ ) {  // check horizontal
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++ ) {  // check vertical
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 ) {       // check diagonal top left
00203         t = a->at(0);       //   to bottom right
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 ) {       // check diagonal bottom left
00213         int j = nBoard-1;     //   to top right
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 )         // no winner
00226         t = 0;
00227     return t;
00228 }
00229 
00230 
00231 // --------------------------------------------------------------------------
00232 // TicTacGameBoard::computerMove()
00233 //
00234 // Puts a piece on the game board. Very, very simple.
00235 //
00236 
00237 void TicTacGameBoard::computerMove()
00238 {
00239     int numButtons = nBoard*nBoard;
00240     int *altv = new int[numButtons];    // buttons alternatives
00241     int altc = 0;
00242     int stopHuman = -1;
00243     TicTacArray a = btArray->copy();
00244     int i;
00245     for ( i=0; i<numButtons; i++ ) {    // try all positions
00246         if ( a[i] != TicTacButton::Blank )  // already a piece there
00247             continue;
00248         a[i] = TicTacButton::Cross;   // test if computer wins
00249         if ( checkBoard(&a) == a[i] ) {   // computer will win
00250             st = ComputerWon;
00251             stopHuman = -1;
00252             break;
00253         }
00254         a[i] = TicTacButton::Circle;    // test if human wins
00255         if ( checkBoard(&a) == a[i] ) {   // oops...
00256             stopHuman = i;      // remember position
00257             a[i] = TicTacButton::Blank;   // restore button
00258             continue;       // computer still might win
00259         }
00260         a[i] = TicTacButton::Blank;   // restore button
00261         altv[altc++] = i;     // remember alternative
00262     }
00263     if ( stopHuman >= 0 )     // must stop human from winning
00264         a[stopHuman] = TicTacButton::Cross;
00265     else if ( i == numButtons ) {   // tried all alternatives
00266         if ( altc > 0 )       // set random piece
00267             a[altv[rand()%(altc--)]] = TicTacButton::Cross;
00268         if ( altc == 0 ) {      // no more blanks
00269             st = NobodyWon;
00270             emit finished();
00271         }
00272     }
00273     *btArray = a;       // update model
00274     updateButtons();        // update buttons
00275     delete[] altv;
00276 }
00277 
00278 
00279 //***************************************************************************
00280 //* TicTacToe member functions
00281 //***************************************************************************
00282 
00283 // --------------------------------------------------------------------------
00284 // Creates a game widget with a game board and two push buttons, and connects
00285 // signals of child widgets to slots.
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       // Create a message label
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       // Create the game board and connect the signal finished() to this
00302       // gameOver() slot
00303 
00304     board = new TicTacGameBoard( boardSize, this );
00305     connect( board, SIGNAL(finished()), SLOT(gameOver()) );
00306     l->addWidget( board );
00307 
00308       // Create a horizontal frame line
00309 
00310     QFrame *line = new QFrame( this );
00311     line->setFrameStyle( QFrame::HLine | QFrame::Sunken );
00312     l->addWidget( line );
00313 
00314       // Create the combo box for deciding who should start, and
00315       // connect its clicked() signals to the buttonClicked() slot
00316 
00317     whoStarts = new QComboBox( this );
00318     whoStarts->insertItem( tr( "Computer starts" ) );
00319     whoStarts->insertItem( tr( "Human starts" ) );
00320     l->addWidget( whoStarts );
00321 
00322       // Create the push buttons and connect their clicked() signals
00323       // to this right slots.
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 // TicTacToe::newGameClicked()      - SLOT
00341 //
00342 // This slot is activated when the new game button is clicked.
00343 //
00344 
00345 void TicTacToe::newGameClicked()
00346 {
00347     board->computerStarts( whoStarts->currentItem() == 0 );
00348     board->newGame();
00349     newState();
00350 }
00351 
00352 
00353 // --------------------------------------------------------------------------
00354 // TicTacToe::gameOver()      - SLOT
00355 //
00356 // This slot is activated when the TicTacGameBoard emits the signal
00357 // "finished()", i.e. when a player has won or when it is a draw.
00358 //
00359 
00360 void TicTacToe::gameOver()
00361 {
00362     newState();         // update text box
00363 }
00364 
00365 
00366 // --------------------------------------------------------------------------
00367 // Updates the message to reflect a new state.
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 }

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