Viadeo Twitter Google Bookmarks ! Facebook Digg del.icio.us MySpace Yahoo MyWeb Blinklist Netvouz Reddit Simpy StumbleUpon Bookmarks Windows Live Favorites 
Logo Documentation Qt ·  Page d'accueil  ·  Toutes les classes  ·  Classes principales  ·  Annotées  ·  Classes groupées  ·  Fonctions  · 

Tic Tac Toe

This is an implementation of the Tic-tac-toe game.

We didn't put much effort in making a clever algorithm so it's not a challenge to play against the computer. Instead, study the source code to see how you can make reusable components such as the TicTacGameBoard widget.


Header file:

/****************************************************************************
** $Id:  qt/tictac.h   3.0.6   edited Oct 12 2001 $
**
** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#ifndef TICTAC_H
#define TICTAC_H


#include <qpushbutton.h>
#include <qptrvector.h>

class QComboBox;
class QLabel;


// --------------------------------------------------------------------------
// TicTacButton implements a single tic-tac-toe button
//

class TicTacButton : public QPushButton
{
    Q_OBJECT
public:
    TicTacButton( QWidget *parent );
    enum Type { Blank, Circle, Cross };
    Type        type() const            { return t; }
    void        setType( Type type )    { t = type; repaint(); }
    QSizePolicy sizePolicy() const
    { return QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ); }
    QSize sizeHint() const { return QSize( 32, 32 ); }
    QSize minimumSizeHint() const { return QSize( 10, 10 ); }
protected:
    void        drawButtonLabel( QPainter * );
private:
    Type t;
};

// Using template vector to make vector-class of TicTacButton.
// This vector is used by the TicTacGameBoard class defined below.

typedef QPtrVector<TicTacButton>        TicTacButtons;
typedef QMemArray<int>          TicTacArray;


// --------------------------------------------------------------------------
// TicTacGameBoard implements the tic-tac-toe game board.
// TicTacGameBoard is a composite widget that contains N x N TicTacButtons.
// N is specified in the constructor.
//

class TicTacGameBoard : public QWidget
{
    Q_OBJECT
public:
    TicTacGameBoard( int n, QWidget *parent=0, const char *name=0 );
   ~TicTacGameBoard();
    enum        State { Init, HumansTurn, HumanWon, ComputerWon, NobodyWon };
    State       state() const           { return st; }
    void        computerStarts( bool v );
    void        newGame();
signals:
    void        finished();                     // game finished
private slots:
    void        buttonClicked();
private:
    void        setState( State state ) { st = state; }
    void        updateButtons();
    int checkBoard( TicTacArray * );
    void        computerMove();
    State       st;
    int         nBoard;
    bool        comp_starts;
    TicTacArray *btArray;
    TicTacButtons *buttons;
};


// --------------------------------------------------------------------------
// TicTacToe implements the complete game.
// TicTacToe is a composite widget that contains a TicTacGameBoard and
// two push buttons for starting the game and quitting.
//

class TicTacToe : public QWidget
{
    Q_OBJECT
public:
    TicTacToe( int boardSize=3, QWidget *parent=0, const char *name=0 );
private slots:
    void        newGameClicked();
    void        gameOver();
private:
    void        newState();
    QComboBox   *whoStarts;
    QPushButton *newGame;
    QPushButton *quit;
    QLabel      *message;
    TicTacGameBoard *board;
};


#endif // TICTAC_H


Implementation:

/****************************************************************************
** $Id:  qt/tictac.cpp   3.0.6   edited Nov 14 2001 $
**
** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#include "tictac.h"
#include <qapplication.h>
#include <qpainter.h>
#include <qdrawutil.h>
#include <qcombobox.h>
#include <qcheckbox.h>
#include <qlabel.h>
#include <qlayout.h>
#include <stdlib.h>                             // rand() function
#include <qdatetime.h>                          // seed for rand()


//***************************************************************************
//* TicTacButton member functions
//***************************************************************************

// --------------------------------------------------------------------------
// Creates a TicTacButton
//

TicTacButton::TicTacButton( QWidget *parent ) : QPushButton( parent )
{
    t = Blank;                                  // initial type
}

// --------------------------------------------------------------------------
// Paints TicTacButton
//

void TicTacButton::drawButtonLabel( QPainter *p )
{
    QRect r = rect();
    p->setPen( QPen( white,2 ) );               // set fat pen
    if ( t == Circle ) {
        p->drawEllipse( r.left()+4, r.top()+4, r.width()-8, r.height()-8 );
    } else if ( t == Cross ) {                  // draw cross
        p->drawLine( r.topLeft()   +QPoint(4,4), r.bottomRight()-QPoint(4,4));
        p->drawLine( r.bottomLeft()+QPoint(4,-4),r.topRight()   -QPoint(4,-4));
    }
}


//***************************************************************************
//* TicTacGameBoard member functions
//***************************************************************************

// --------------------------------------------------------------------------
// Creates a game board with N x N buttons and connects the "clicked()"
// signal of all buttons to the "buttonClicked()" slot.
//

TicTacGameBoard::TicTacGameBoard( int n, QWidget *parent, const char *name )
    : QWidget( parent, name )
{
    st = Init;                                  // initial state
    nBoard = n;
    n *= n;                                     // make square
    comp_starts = FALSE;                        // human starts
    buttons = new TicTacButtons(n);             // create real buttons
    btArray = new TicTacArray(n);               // create button model
    QGridLayout * grid = new QGridLayout( this, nBoard, nBoard, 4 );
    QPalette p( blue );
    for ( int i=0; i<n; i++ ) {                 // create and connect buttons
        TicTacButton *ttb = new TicTacButton( this );
        ttb->setPalette( p );
        ttb->setEnabled( FALSE );
        connect( ttb, SIGNAL(clicked()), SLOT(buttonClicked()) );
        grid->addWidget( ttb, i%nBoard, i/nBoard );
        buttons->insert( i, ttb );
        btArray->at(i) = TicTacButton::Blank;   // initial button type
    }
    QTime t = QTime::currentTime();             // set random seed
    srand( t.hour()*12+t.minute()*60+t.second()*60 );
}

TicTacGameBoard::~TicTacGameBoard()
{
    delete buttons;
    delete btArray;
}


// --------------------------------------------------------------------------
// TicTacGameBoard::computerStarts( bool v )
//
// Computer starts if v=TRUE. The human starts by default.
//

void TicTacGameBoard::computerStarts( bool v )
{
    comp_starts = v;
}


// --------------------------------------------------------------------------
// TicTacGameBoard::newGame()
//
// Clears the game board and prepares for a new game
//

void TicTacGameBoard::newGame()
{
    st = HumansTurn;
    for ( int i=0; i<nBoard*nBoard; i++ )
        btArray->at(i) = TicTacButton::Blank;
    if ( comp_starts )
        computerMove();
    else
        updateButtons();
}


// --------------------------------------------------------------------------
// TicTacGameBoard::buttonClicked()             - SLOT
//
// This slot is activated when a TicTacButton emits the signal "clicked()",
// i.e. the user has clicked on a TicTacButton.
//

void TicTacGameBoard::buttonClicked()
{
    if ( st != HumansTurn )                     // not ready
        return;
    int i = buttons->findRef( (TicTacButton*)sender() );
    TicTacButton *b = buttons->at(i);           // get piece that was pressed
    if ( b->type() == TicTacButton::Blank ) {   // empty piece?
        btArray->at(i) = TicTacButton::Circle;
        updateButtons();
        if ( checkBoard( btArray ) == 0 )       // not a winning move?
            computerMove();
        int s = checkBoard( btArray );
        if ( s ) {                              // any winners yet?
            st = s == TicTacButton::Circle ? HumanWon : ComputerWon;
            emit finished();
        }
    }
}


// --------------------------------------------------------------------------
// TicTacGameBoard::updateButtons()
//
// Updates all buttons that have changed state
//

void TicTacGameBoard::updateButtons()
{
    for ( int i=0; i<nBoard*nBoard; i++ ) {
        if ( buttons->at(i)->type() != btArray->at(i) )
            buttons->at(i)->setType( (TicTacButton::Type)btArray->at(i) );
        buttons->at(i)->setEnabled( buttons->at(i)->type() ==
                                    TicTacButton::Blank );
    }
}


// --------------------------------------------------------------------------
// TicTacGameBoard::checkBoard()
//
// Checks if one of the players won the game, works for any board size.
//
// Returns:
//  - TicTacButton::Cross  if the player with X buttons won
//  - TicTacButton::Circle if the player with O buttons won
//  - Zero (0) if there is no winner yet
//

int TicTacGameBoard::checkBoard( TicTacArray *a )
{
    int  t = 0;
    int  row, col;
    bool won = FALSE;
    for ( row=0; row<nBoard && !won; row++ ) {  // check horizontal
        t = a->at(row*nBoard);
        if ( t == TicTacButton::Blank )
            continue;
        col = 1;
        while ( col<nBoard && a->at(row*nBoard+col) == t )
            col++;
        if ( col == nBoard )
            won = TRUE;
    }
    for ( col=0; col<nBoard && !won; col++ ) {  // check vertical
        t = a->at(col);
        if ( t == TicTacButton::Blank )
            continue;
        row = 1;
        while ( row<nBoard && a->at(row*nBoard+col) == t )
            row++;
        if ( row == nBoard )
            won = TRUE;
    }
    if ( !won ) {                               // check diagonal top left
        t = a->at(0);                           //   to bottom right
        if ( t != TicTacButton::Blank ) {
            int i = 1;
            while ( i<nBoard && a->at(i*nBoard+i) == t )
                i++;
            if ( i == nBoard )
                won = TRUE;
        }
    }
    if ( !won ) {                               // check diagonal bottom left
        int j = nBoard-1;                       //   to top right
        int i = 0;
        t = a->at(i+j*nBoard);
        if ( t != TicTacButton::Blank ) {
            i++; j--;
            while ( i<nBoard && a->at(i+j*nBoard) == t ) {
                i++; j--;
            }
            if ( i == nBoard )
                won = TRUE;
        }
    }
    if ( !won )                                 // no winner
        t = 0;
    return t;
}


// --------------------------------------------------------------------------
// TicTacGameBoard::computerMove()
//
// Puts a piece on the game board. Very, very simple.
//

void TicTacGameBoard::computerMove()
{
    int numButtons = nBoard*nBoard;
    int *altv = new int[numButtons];            // buttons alternatives
    int altc = 0;
    int stopHuman = -1;
    TicTacArray a = btArray->copy();
    int i;
    for ( i=0; i<numButtons; i++ ) {            // try all positions
        if ( a[i] != TicTacButton::Blank )      // already a piece there
            continue;
        a[i] = TicTacButton::Cross;             // test if computer wins
        if ( checkBoard(&a) == a[i] ) {         // computer will win
            st = ComputerWon;
            stopHuman = -1;
            break;
        }
        a[i] = TicTacButton::Circle;            // test if human wins
        if ( checkBoard(&a) == a[i] ) {         // oops...
            stopHuman = i;                      // remember position
            a[i] = TicTacButton::Blank;         // restore button
            continue;                           // computer still might win
        }
        a[i] = TicTacButton::Blank;             // restore button
        altv[altc++] = i;                       // remember alternative
    }
    if ( stopHuman >= 0 )                       // must stop human from winning
        a[stopHuman] = TicTacButton::Cross;
    else if ( i == numButtons ) {               // tried all alternatives
        if ( altc > 0 )                         // set random piece
            a[altv[rand()%(altc--)]] = TicTacButton::Cross;
        if ( altc == 0 ) {                      // no more blanks
            st = NobodyWon;
            emit finished();
        }
    }
    *btArray = a;                               // update model
    updateButtons();                            // update buttons
    delete[] altv;
}


//***************************************************************************
//* TicTacToe member functions
//***************************************************************************

// --------------------------------------------------------------------------
// Creates a game widget with a game board and two push buttons, and connects
// signals of child widgets to slots.
//

TicTacToe::TicTacToe( int boardSize, QWidget *parent, const char *name )
    : QWidget( parent, name )
{
    QVBoxLayout * l = new QVBoxLayout( this, 6 );

    // Create a message label

    message = new QLabel( this );
    message->setFrameStyle( QFrame::WinPanel | QFrame::Sunken );
    message->setAlignment( AlignCenter );
    l->addWidget( message );

    // Create the game board and connect the signal finished() to this
    // gameOver() slot

    board = new TicTacGameBoard( boardSize, this );
    connect( board, SIGNAL(finished()), SLOT(gameOver()) );
    l->addWidget( board );

    // Create a horizontal frame line

    QFrame *line = new QFrame( this );
    line->setFrameStyle( QFrame::HLine | QFrame::Sunken );
    l->addWidget( line );

    // Create the combo box for deciding who should start, and
    // connect its clicked() signals to the buttonClicked() slot

    whoStarts = new QComboBox( this );
    whoStarts->insertItem( "Computer starts" );
    whoStarts->insertItem( "Human starts" );
    l->addWidget( whoStarts );

    // Create the push buttons and connect their clicked() signals
    // to this right slots.

    newGame = new QPushButton( "Play!", this );
    connect( newGame, SIGNAL(clicked()), SLOT(newGameClicked()) );
    quit = new QPushButton( "Quit", this );
    connect( quit, SIGNAL(clicked()), qApp, SLOT(quit()) );
    QHBoxLayout * b = new QHBoxLayout;
    l->addLayout( b );
    b->addWidget( newGame );
    b->addWidget( quit );

    newState();
}


// --------------------------------------------------------------------------
// TicTacToe::newGameClicked()                  - SLOT
//
// This slot is activated when the new game button is clicked.
//

void TicTacToe::newGameClicked()
{
    board->computerStarts( whoStarts->currentItem() == 0 );
    board->newGame();
    newState();
}


// --------------------------------------------------------------------------
// TicTacToe::gameOver()                        - SLOT
//
// This slot is activated when the TicTacGameBoard emits the signal
// "finished()", i.e. when a player has won or when it is a draw.
//

void TicTacToe::gameOver()
{
    newState();                                 // update text box
}


// --------------------------------------------------------------------------
// Updates the message to reflect a new state.
//

void TicTacToe::newState()
{
    static const char *msg[] = {                // TicTacGameBoard::State texts
        "Click Play to start", "Make your move",
        "You won!", "Computer won!", "It's a draw" };
    message->setText( msg[board->state()] );
    return;
}


Main:

/****************************************************************************
** $Id:  qt/main.cpp   3.0.6   edited Oct 12 2001 $
**
** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#include <qapplication.h>
#include <stdlib.h>
#include "tictac.h"


int main( int argc, char **argv )
{
    QApplication a( argc, argv );
    int n = 3;
    if ( argc == 2 )                            // get board size n
        n = atoi(argv[1]);
    if ( n < 3 || n > 10 ) {                    // out of range
        qWarning( "%s: Board size must be from 3x3 to 10x10", argv[0] );
        return 1;
    }
    TicTacToe ttt( n );                         // create game
    a.setMainWidget( &ttt );
    ttt.setCaption("Qt Example - TicTac");
    ttt.show();                                 // show widget
    return a.exec();                            // go
}

See also Examples.

Publicité

Best Of

Actualités les plus lues

Semaine
Mois
Année
  1. « Quelque chose ne va vraiment pas avec les développeurs "modernes" », un développeur à "l'ancienne" critique la multiplication des bibliothèques 94
  2. Apercevoir la troisième dimension ou l'utilisation multithreadée d'OpenGL dans Qt, un article des Qt Quarterly traduit par Guillaume Belz 0
  3. Les développeurs ignorent-ils trop les failles découvertes dans leur code ? Prenez-vous en compte les remarques des autres ? 17
  4. Pourquoi les programmeurs sont-ils moins payés que les gestionnaires de programmes ? Manquent-ils de pouvoir de négociation ? 42
  5. Quelles nouveautés de C++11 Visual C++ doit-il rapidement intégrer ? Donnez-nous votre avis 10
  6. Adieu qmake, bienvenue qbs : Qt Building Suite, un outil déclaratif et extensible pour la compilation de projets Qt 17
  7. 2017 : un quinquennat pour une nouvelle version du C++ ? Possible, selon Herb Sutter 7
Page suivante

Le Qt Labs au hasard

Logo

Vue d'ensemble

Les Qt Labs sont les laboratoires des développeurs de Qt, où ils peuvent partager des impressions sur le framework, son utilisation, ce que pourrait être son futur. Lire l'article.

Communauté

Ressources

Liens utiles

Contact

  • Vous souhaitez rejoindre la rédaction ou proposer un tutoriel, une traduction, une question... ? Postez dans le forum Contribuez ou contactez-nous par MP ou par email (voir en bas de page).

Qt dans le magazine

Cette page est une traduction d'une page de la documentation de Qt, écrite par Nokia Corporation and/or its subsidiary(-ies). Les éventuels problèmes résultant d'une mauvaise traduction ne sont pas imputables à Nokia. Qt 3.0
Copyright © 2012 Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon, vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts. Cette page est déposée à la SACD.
Vous avez déniché une erreur ? Un bug ? Une redirection cassée ? Ou tout autre problème, quel qu'il soit ? Ou bien vous désirez participer à ce projet de traduction ? N'hésitez pas à nous contacter ou par MP !
 
 
 
 
Partenaires

Hébergement Web