在中断期间,我决定在这里重新讨论井字游戏中的一些问题。我创建了一个简单的Tic-Tac-Toe GUI游戏,然后想到了做终极Tic-Tac-Toe挑战。

我正在寻找重构代码的方法。特别是在MainWindow.cpp中。

我认为这是一团糟。我花了很少的时间在这个项目上,然后开始黑客入侵。但是,计算机确实可以玩“完美”游戏。

这是Github仓库。我已经上传了Linux的编译二进制文件。



MainWindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include "dialog.h"
#include "tictactoe.h"
#include <string.h>
#include <iostream>
#include <QMainWindow>
#include <QPushButton>
#include <QDebug>
#include <QThread>
#include <QtConcurrent>
#include <QFuture>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    int player = 1; //Keeps track of current


    explicit MainWindow(QWidget *parent = 0);
    void setUpGrid();
    void setChar(char);
    void Play();
    void CheckWinner(int currentGrid);

    void colorBoard(int nextGrid, int move);
    void colorBoardWin(int nextGrid,int player);
    void colorBoardUltimateWin(int player);

    void computer(int grid, int player);
    ~MainWindow();

signals:
    void turnComplete(int);
    void computer_(int,int player);

public slots:
    int itemClicked();
    void humanMoves();

    //void computer(int grid,int player);
    void prediction(QString);


private slots:

    void begin(int strength);

    void invalidMove();
    void computerMove(int,int);


    void on_playAgain_clicked();

private:
    Ui::MainWindow *ui;
    Dialog *options = new Dialog;

    QPushButton *itemButtons[9][5];
    QGridLayout *layouts[9];
    QFrame *frames[9];



    QPushButton *createButton(QString&, const QString/*const char**/);

    TicTacToe *game = new TicTacToe();

    int strength;
    bool humanTurn;

    int currentGrid = -1;
    int nextGrid = -1;


    int wonGrids[9] = {};
    int previousMove[2] = {-1,-1};  //Stores currentGrid, move


    int test = -1;


    QThread *pthread = new QThread();

};

#endif // MAINWINDOW_H


MainWindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    humanTurn = false;

    ui->playAgain->setVisible(false);

    options->setWindowFlags(Qt::WindowStaysOnTopHint);
    options->setModal(true);
    options->show();

    setUpGrid();

    game->moveToThread(pthread);


    connect(options,SIGNAL(choosen(int)),this,SLOT(begin(int)));
    connect(game,SIGNAL(humanMoves()),this,SLOT(humanMoves()));
    connect(game,SIGNAL(computerMove(int,int)),this,SLOT(computerMove(int,int)));
    connect(game,SIGNAL(prediction(QString)),this,SLOT(prediction(QString)));

    //connect(this,SIGNAL(computer_(int,int)),this,SLOT(computer(int,int)));

    pthread->start();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::setUpGrid(){




    frames[0] = ui->gridFrame;
    frames[1] = ui->gridFrame_2;
    frames[2] = ui->gridFrame_3;
    frames[3] = ui->gridFrame_4;
    frames[4] = ui->gridFrame_5;
    frames[5] = ui->gridFrame_6;
    frames[6] = ui->gridFrame_7;
    frames[7] = ui->gridFrame_8;
    frames[8] = ui->gridFrame_9;


    layouts[0] = ui->gridLayout;
    layouts[0]->parent()->setObjectName(QString::number(0));
    layouts[1] = ui->gridLayout_2;
    layouts[1]->parent()->setObjectName(QString::number(1));
    layouts[2] = ui->gridLayout_3;
    layouts[2]->parent()->setObjectName(QString::number(2));
    layouts[3] = ui->gridLayout_4;
    layouts[3]->parent()->setObjectName(QString::number(3));
    layouts[4] = ui->gridLayout_5;
    layouts[4]->parent()->setObjectName(QString::number(4));
    layouts[5] = ui->gridLayout_6;
    layouts[5]->parent()->setObjectName(QString::number(5));
    layouts[6] = ui->gridLayout_7;
    layouts[6]->parent()->setObjectName(QString::number(6));
    layouts[7] = ui->gridLayout_8;
    layouts[7]->parent()->setObjectName(QString::number(7));
    layouts[8] = ui->gridLayout_9;
    layouts[8]->parent()->setObjectName(QString::number(8));



    for(int i=0; i<9; i++){
        for(int j=0; j<9; j++){
            QString text = "";
            //        itemButtons[i] = new QPushButton();
            //        connect(itemButtons[i],SIGNAL(clicked()),this,SLOT(itemClicked()));
            itemButtons[i][j] = createButton(text,SLOT(itemClicked()));
            itemButtons[i][j]->setObjectName(QString::number(j));
        }
    }



    for(int j=0; j<9; j++)
        for(int i=0; i<9; i++){
            int row = i/3;
            int column = i%3;
            if(i / 9 == 0)
                layouts[0]->addWidget(itemButtons[0][i],row,column);
            if(i / (9*2) == 0)
                layouts[1]->addWidget(itemButtons[1][i],row,column);
            if(i / (9*3) == 0)
                layouts[2]->addWidget(itemButtons[2][i],row,column);
            if(i / (9*4) == 0)
                layouts[3]->addWidget(itemButtons[3][i],row,column);
            if(i / (9*5) == 0)
                layouts[4]->addWidget(itemButtons[4][i],row,column);
            if(i / (9*6) == 0)
                layouts[5]->addWidget(itemButtons[5][i],row,column);
            if(i / (9*7) == 0)
                layouts[6]->addWidget(itemButtons[6][i],row,column);
            if(i / (9*8) == 0)
                layouts[7]->addWidget(itemButtons[7][i],row,column);
            if(i / (9*9) == 0)
                layouts[8]->addWidget(itemButtons[8][i],row,column);
        }





}


QPushButton *MainWindow::createButton(QString &text, const QString member/*const char *member*/){
    //Creates button and sets size policy. Connects button's signal to slot

    QPushButton *button = new QPushButton;
    button->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
    button->setText(text);
    button->setCheckable(true);
    button->setAutoExclusive(true);

    connect(button, SIGNAL(clicked()),this,member.toStdString().c_str()); //connect button signal to SLOT(itemClicked)
    return button;
}

int MainWindow::itemClicked(){
    //Slot for when a tile has been clicked.

    QPushButton *clickedItem = qobject_cast<QPushButton*>(sender());

    clickedItem->setAutoExclusive(false);
    clickedItem->setChecked(false);
    clickedItem->setAutoExclusive(true);

    currentGrid = clickedItem->parent()->objectName().toInt();

    if(currentGrid != nextGrid && nextGrid != -1 && !wonGrids[nextGrid]){
        qDebug() << "NOPE";
        invalidMove();
        return -1;
    }

    //Read user symbol, and set button to that symbol
    if(humanTurn && game->isLegal(clickedItem->objectName().toInt(),currentGrid) && !wonGrids[currentGrid]){

        clickedItem->setText(QString(QChar(game->gridChar(game->human))));        //Sets pushbutton text to player's char.

        game->humanMove(clickedItem->objectName().toInt(),currentGrid);           //Sets subBoard with player's char


        CheckWinner(currentGrid);
        player = 1;

        nextGrid = clickedItem->objectName().toInt();                             //next move for computer will need to be where player sent it to.


       // emit computer_(nextGrid,1);
        QFuture<void> future = QtConcurrent::run(this,&MainWindow::computer,nextGrid,1);
        //game->CalculateGrid(nextGrid,1);
        qDebug() << "RETURN: ";

    }
    //else if(!game->isLegal(clickedItem->objectName().toInt(),currentGrid))
        //invalidMove();
}

void MainWindow::begin(int strength){
    //Sets player character. Calls TicTacToe::Play()
    //The Game begins.

    QString text = "You are playing as " + QString(QChar(options->getChar()));
    this->strength = strength;
    game->setDepth(strength);

    if(options->getChar() == 'O'){
        text.append(". Computer moves first.");
        player = 1;
        int r = std::rand() % 9;
        game->CalculateGrid(r,1); //Computer moves.
    }
    else{
        text.append(". Select a square.");
        humanTurn = true;
        player = -1;
    }

    ui->announce->setText(text);

}

void MainWindow::humanMoves(){

    humanTurn = true;
    ui->announce->setText("Make a move.");

}


void MainWindow::computerMove(int move,int grid){


    //When the computer goes first.
    if(grid != -1)
        nextGrid = grid;



    qDebug() << "PLAYER: " << player;
    humanTurn = false;
    itemButtons[nextGrid][move]->setText(QString(QChar(game->gridChar(player))));

    //Change player to opponent
    if(player == 1)
        player = -1;
    else
        player = 1;

    colorBoard(nextGrid,move);

    //Check if computer has won
    CheckWinner(nextGrid);

    //If not, then player's next move will be
    nextGrid = move;

    qDebug() << "Player must move here: " << nextGrid;

    humanMoves();


    //emit computer(nextGrid);
}

void MainWindow::CheckWinner(int grid){

    QString announce;
    if(game->winner(grid) == -1){
        game->setGridState(grid,-1);

        qDebug() << "PLAYER WON AT " << grid;

        humanTurn = false; //Disable clicking

        wonGrids[grid] = -1;
        colorBoardWin(grid,-1);

        ui->playAgain->setVisible(true);
    }
    else if(game->winner(grid) == 1){
        game->setGridState(grid,1);

        qDebug() << "COMPUTER WON AT " << grid;

        wonGrids[grid] = 1;
        colorBoardWin(grid,1);

        ui->playAgain->setVisible(true);
    }
    else if(game->winner(grid) == -5){

        announce = "TIE! on board" + QString::number(grid);

        ui->announce->setText(announce);

        ui->playAgain->setVisible(true);
        return;
    }

    //Now check ultimate win
    if(game->ultWin() == -1)
        qDebug() << "HUMAN WIN";
    else if(game->ultWin() == 1){

        qDebug() << "COMPUTER WIN";

        frames[game->ultimateWinGrids[0]]->setStyleSheet("background-color: red");
        frames[game->ultimateWinGrids[1]]->setStyleSheet("background-color: red");
        frames[game->ultimateWinGrids[2]]->setStyleSheet("background-color: red");

    }

}

void MainWindow::invalidMove(){
    ui->announce->setText("Invalid move! Try again.");
    qDebug() << "currentGrid: " << currentGrid;
    qDebug() << "nextGrid: " << nextGrid;
}

void MainWindow::on_playAgain_clicked()
{

    //Clear all background colors,

    for(int i=0; i<9; i++){
        for(int j=0;j<9;j++){
            itemButtons[i][j]->setText("");
        }
    }

    for(int i=0; i<9; i++){
        frames[i]->setStyleSheet("background-color: none");
        wonGrids[i] = 0;
        for(int j=0; j<9; j++){
            itemButtons[i][j]->setStyleSheet("background-color: none");
        }
    }

    currentGrid = -1;
    nextGrid = -1;
    game->reset();
    begin(strength);

    ui->playAgain->setVisible(false);

}

void MainWindow::colorBoard(int nextGrid, int move){

    //itemButtons[nextGrid][move]->setStyleSheet("background-color: red");

    for(int i=0; i<9; i++){
        frames[i]->setStyleSheet("background-color: none");
    }

    for(int i=0; i<9; i++){
        for(int j=0; j<9; j++){

            if(wonGrids[i] == EMPTY){
                itemButtons[i][j]->setStyleSheet("background-color: none");
            }
        }
    }


    //Sets computer move's background color
    QPushButton* button = itemButtons[nextGrid][move];
    QPalette pal = button->palette();
    pal.setColor(QPalette::Button, QColor(Qt::blue));
    button->setAutoFillBackground(true);
    button->setPalette(pal);
    button->update();

    itemButtons[nextGrid][move]->setStyleSheet("background-color: yellow");

    if(wonGrids[move] == EMPTY){
        frames[move]->setStyleSheet("background-color: lightgreen");
    }
    else{
        for(int i=0; i<9; i++){
            if(i != move)
                frames[i]->setStyleSheet("background-color: lightblue");
        }
    }



}

void MainWindow::colorBoardWin(int nextGrid,int player){



    if(player == -1){
        itemButtons[nextGrid][game->winningRows[0]]->setStyleSheet("background-color: lightblue");
        itemButtons[nextGrid][game->winningRows[1]]->setStyleSheet("background-color: lightblue");
        itemButtons[nextGrid][game->winningRows[2]]->setStyleSheet("background-color: lightblue");
    }
    else{
        itemButtons[nextGrid][game->winningRows[0]]->setStyleSheet("background-color: pink");
        itemButtons[nextGrid][game->winningRows[1]]->setStyleSheet("background-color: pink");
        itemButtons[nextGrid][game->winningRows[2]]->setStyleSheet("background-color: pink");
    }



}

void MainWindow::colorBoardUltimateWin(int player){

    //for(int i=0; i<)
}

void MainWindow::computer(int grid,int player){

    double time;
    humanTurn = false; //Prevent random clicking
    QTime myTimer;
    myTimer.start();
    //Qtconcurrent::run();
    ui->announce->setText("Thinking...");
    game->CalculateGrid(nextGrid,player);

    time = myTimer.elapsed();

    ui->timer->setText("Move took: " + QString::number(time/1000) + " seconds.");

    humanTurn = true;

    qDebug() << "Returned!!!";

}


void MainWindow::prediction(QString prediction){

    ui->predictor->setText(prediction);

}


tictactoe.cpp

#include "tictactoe.h"

#include <QTextStream>
#include <QProcess>
#include <stdio.h>
#include <QDebug>
#include <ctime>

using std::cout;
using std::endl;


TicTacToe::TicTacToe(QObject *parent) : QObject(parent)
{
    std::srand(std::time(0));
    std::fill(boards.begin(),boards.end(),std::vector<int>(NUM_SQUARES,EMPTY));
}

void TicTacToe::setDepth(int strength){
    DEPTH_LIMIT = strength;
    qDebug() << "DepthLimit: " << DEPTH_LIMIT;
}

void TicTacToe::humanMove(int move,int currentGrid){

    boards[currentGrid][move] = human;

}

bool TicTacToe::isLegal(int move,int currentGrid) const{

    qDebug() << "is Legal?: " << currentGrid;
    qDebug() << "isLegal move?: " << move;
    qDebug() << "boards[currentGrid][move]: " << (boards[currentGrid][move] == EMPTY);

    return (boards[currentGrid][move] == EMPTY);
}

int TicTacToe::winner(const std::vector<int> &board){

    const int WINNING_ROWS[8][3] = {
        {0,1,2},
        {3,4,5},
        {6,7,8},
        {0,3,6},
        {1,4,7},
        {2,5,8},
        {0,4,8},
        {2,4,6} };
    const int TOTAL_ROWS = 8;

    for(int row = 0; row < TOTAL_ROWS; ++row){

        if( (board[WINNING_ROWS[row][0]] != EMPTY) &&                              //Go through the rows of WINNING_ROWS and determine if board[x][y] is winner
                (board[WINNING_ROWS[row][0]] == (board[WINNING_ROWS[row][1]])) &&
                (board[WINNING_ROWS[row][1]] == board[WINNING_ROWS[row][2]]) )
        {

            qDebug() << "Ultimate win rows: " << WINNING_ROWS[row][0];
            qDebug() << "Ultimate win rows: " << WINNING_ROWS[row][1];
            qDebug() << "Ultimate win rows: " << WINNING_ROWS[row][2];
            ultimateWinGrids[0] = WINNING_ROWS[row][0];
            ultimateWinGrids[1] = WINNING_ROWS[row][1];
            ultimateWinGrids[2] = WINNING_ROWS[row][2];

            return board[WINNING_ROWS[row][0]]; //Return the character that has won
        }
    }

    //No one has won yet
    return 0;
}


int TicTacToe::winner(int currentGrid){

    qDebug() << "Checking winner at grid: " << currentGrid;


    const int WINNING_ROWS[8][3] = {
        {0,1,2},
        {3,4,5},
        {6,7,8},
        {0,3,6},
        {1,4,7},
        {2,5,8},
        {0,4,8},
        {2,4,6} };
    const int TOTAL_ROWS = 8;

    for(int row = 0; row < TOTAL_ROWS; ++row){

        if( (boards[currentGrid][WINNING_ROWS[row][0]] != EMPTY) &&                              //Go through the rows of WINNING_ROWS and determine if board[x][y] is winner
                (boards[currentGrid][WINNING_ROWS[row][0]] == boards[currentGrid][WINNING_ROWS[row][1]]) &&
                (boards[currentGrid][WINNING_ROWS[row][1]] == boards[currentGrid][WINNING_ROWS[row][2]]) )
        {
            qDebug() << "Regular win: " <<  WINNING_ROWS[row][0];
            qDebug() << "Regular win: " <<  WINNING_ROWS[row][1];
            qDebug() << "Regular win: " <<  WINNING_ROWS[row][2];

            winningRows[0] = WINNING_ROWS[row][0];
            winningRows[1] = WINNING_ROWS[row][1];
            winningRows[2] = WINNING_ROWS[row][2];
            return boards[currentGrid][WINNING_ROWS[row][0]]; //Return the character that has won
        }
    }

    //Check for tie. If no more empty spots, no more moves
    if(count(boards[currentGrid].begin(), boards[currentGrid].end(), EMPTY) == 0)
        return TIE;
}


void TicTacToe::reset(){
    for(int i=0; i<9; i++)
        gridStates[i] = 0;
    board = std::vector<int>(NUM_SQUARES,EMPTY);
    std::fill(boards.begin(),boards.end(),std::vector<int>(NUM_SQUARES,EMPTY));

}

char TicTacToe::gridChar(int i) {
    switch(i) {
    case -1:
        return 'X';
    case 0:
        return ' ';
    case 1:
        return 'O';
    }

    return 0;
}

//Ultimate Tic-Tac-Toe Functionality
//Calculates which tile to play

int TicTacToe::CalculateGrid(int currentGrid,int player){

    // If a player forces the computer to a score that has already been won...welp.
    // Computer gets to pick whichever grid he wants. 2 guud 4 uuu
    int test;
    if(gridStates[currentGrid] != EMPTY){
        qDebug() << "NOT EMPTY" << endl << endl;
        int move,best,bestscore = -20000;
        for(int i=0; i<9; i++){
            qDebug() << "looping";
            if((i != currentGrid)){
                move = pickMove(i,player,best);
                qDebug() << "best: " << best;
                //Check if move place is empty, and that the move grid has not been won.
                if((best > bestscore) && (boards[i][move] == EMPTY) && (gridStates[i] == EMPTY)){
                    qDebug() << "move: " << move << " i: " << i;
                    boards[i][move] = player;
                    emit computerMove(move,i);
                    return 20;
                }
            }
        }
    }



    int movetomake = pickMove(currentGrid,player,test);

    boards[currentGrid][movetomake] = player;

    emit computerMove(movetomake,currentGrid);
    return 20;
}


void TicTacToe::setGridState(int grid, int winner){

    gridStates[grid] = winner;
}

int TicTacToe::ultWin(){

    int lol = winner(gridStates);
    qDebug() << "ULIMATE WIN: " << lol;
    //return winner(gridStates);
                return lol;
}

void TicTacToe::utility(int currentGrid,int move,int depth){


    bool win = false;

    int triad_sum = 0;
    int score = 0;


    int numElements = BY_SLOT[move][0];

    for(int i=1; i<=numElements; i++){
        triad_sum = 0;
        for(int j=0; j<3; j++){
            triad_sum += boards[currentGrid][WINNING_TRIADS[BY_SLOT[move][i]][j]];
        }



        switch(triad_sum){

        case 3:
        case -3:
        {
            win = 1;
            score = boards[currentGrid][WINNING_TRIADS[BY_SLOT[move][i]][0]] * VERY_LARGE - depth;
            break;
        }
        case 2:{
            score += 3000;
            break;
        }
        case -2:
            score -=3000;
            break;
        case 1:
        case -1:{
            if((boards[currentGrid][WINNING_TRIADS[BY_SLOT[move][i]][0]] & boards[currentGrid][WINNING_TRIADS[BY_SLOT[move][i]][1]] & boards[currentGrid][WINNING_TRIADS[BY_SLOT[move][i]][2]]) != 0){
                score -= triad_sum * 1000;
            }
            break;
        }
        case 0:{
            score += boards[currentGrid][move];
            break;
        }
        default:
            break;
        }

        if(win){
            break;
        }


    }


    if(!win){

        //qDebug() << "BScore: " << score;
        int bonus = 0;
        if(move == 0 || move == 2 || move == 6 || move == 8){
            bonus += 2;//*boards[currentGrid][move];
        }

//        if(move == 4){
//            bonus += 7;//*boards[currentGrid][move];
//        }

        //Strange behaviour documented here.
        if(currentGrid == 0){
            bonus +=7;
        }

        score += boards[currentGrid][move]*bonus;


    }


    rets[0] = score;
    rets[1] = win;

}

int TicTacToe::pickMove(int currentGrid,int player, int& best){

    qDebug() << "Picking move for grid: " << currentGrid;

    int score = 0;
    int bestScore = -VERY_LARGE - DEPTH_LIMIT;
    std::vector<int> my_moves;

    int opponent;
    if(player == 1)
        opponent = -1;
    else
        opponent = 1;


    for(int slot=0; slot<9; slot++){

        if(boards[currentGrid][slot] == EMPTY){
            //boards[currentGrid][slot] = 1;
            boards[currentGrid][slot] = player;


            utility(currentGrid,slot,0);
            score = alphaBeta(boards[currentGrid],slot,opponent,player,(-(VERY_LARGE+DEPTH_LIMIT)-1),(VERY_LARGE+DEPTH_LIMIT+1),1,rets[0],rets[1]);

            boards[currentGrid][slot] = 0;

            if((score > bestScore) && (gridStates[currentGrid] == EMPTY) && (boards[currentGrid][slot] == EMPTY)){
                bestScore = score;
                my_moves.clear();
                my_moves.push_back(slot);

            }
            else if((score == bestScore) && (gridStates[currentGrid] == EMPTY) && (boards[currentGrid][slot] == EMPTY)){
                my_moves.push_back(slot);
            }


        }

        qDebug() << "Move: " << slot << " Score: " << score;    
    }

    int rv = 0;
    if(my_moves.size() < 1){

    }
    else{
        //rv = my_moves.back();
        rv = my_moves[0];

    }

    if(bestScore > THRESHOLD)
        emit prediction(QString("Predict Computer Wins."));
    else if(bestScore < -THRESHOLD)
        emit prediction(QString("Predict Human Wins."));
    else
        emit prediction(QString("Score: " + QString::number(score)));


    qDebug() << "Ultimate move: " << rv << endl;
    qDebug() << "score: " << score;
    best = score;
    return rv;

}

int TicTacToe::alphaBeta(std::vector<int>& board,int last_slot,int player, int next_player,int alpha, int beta, int depth, int score_so_far, int last_move_won){

    if(last_move_won || depth >= DEPTH_LIMIT){
        return score_so_far;
    }



    int score = score_so_far;
    int value;

    for(int i=0; i<9; i++){
        if(boards[last_slot][i] == EMPTY){
            boards[last_slot][i] = player;

            utility(last_slot,i,depth);
            value = alphaBeta(board,i,next_player,player,alpha,beta,depth+1,score_so_far + rets[0],rets[1]);

            boards[last_slot][i] = 0;
            switch(player){
            case 1:
                if(value > alpha)
                    alpha = value;
                break;
            case -1:
                if(value < beta)
                    beta = value;
                break;
            }

                if(beta <= alpha)
                break;
        }

    }

    score = beta;
    if(player == 1)
        score = alpha;   
    return score;   
}


评论

完美的游戏,对吧?我们让我的一个机器人与您的一个机器人战斗,看看谁玩得最完美呢? :)

@SimonAndréForsbergHa:P。

@SimonAndréForsberg这实际上是一个非常有趣的主意...有很多可能性。程序大战。 *开始构建应用程序*

更新了代码。现在支持玩游戏,直到连续赢得三张牌为止。当前上传的二进制文件无法反映这些更改,因此,如果要进行测试,则必须从源代码进行编译/构建。

只是好奇,您尝试制作多少“干净的代码”?我不是C ++专家,但是我看到一大堆“容易犯规的东西”,可以轻松地改进。

#1 楼

因为我没有真正审查过代码的工作原理,所以这根本不是完整的代码审查,但是无论如何,这里有一些小事情可能会引起人们的兴趣:)

Qt5新的连接语法

Qt5引入了信号和插槽的新语法,该语法使您可以直接传递函数指针,而不必依赖Qt预处理器来完成这项工作。您的连接集可以重写为:

connect(options, &Dialog::choosen,
        this, MainWindow::begin);
connect(game, &TicTacToe::humanMoves,
        this, &MainWindow::humanMoves);
connect(game, &TicTacToe::computerMove,
        this, &MainWindow::computerMove);
connect(game, &TicTacToe::prediction,
        this, &MainWindow::prediction);


有很多优点和缺点。您可以查看我上面链接的页面以获取详细信息。从根本上讲,该语法被认为更易于编译,但由于它确实依赖于C ++类型系统,而不再依赖于字符串处理,因此它可以正确地使用typedef和名称空间。此外,作为插槽传递的功能甚至不必再成为插槽。您甚至可以将lambda作为插槽传递。

使用nullptr


由于您使用的是C ++ 11,因此应使用nullptr代替0NULL来表示空指针。它具有易于搜索的优点,并且当函数为整数和指针重载时,可以选择指针重载:

explicit MainWindow(QWidget *parent = nullptr);


不使用std::rand std::rand并不是生成随机数的最佳工具。对于像这样的简单游戏,可能没什么大不了的,但是C ++ 11标头<random>提供了更好的替代方法来生成伪随机数。这对您的应用程序不是很关键,但是您应该看一下。

使用免费功能std::beginstd::end


再一次,它不会为您带来任何改变,但是自C ++ 11起,优良作法是使用自由函数std::beginstd::end代替容器的方法。原因是它们也可以与C样式数组和std::valarray一起使用。这是一个好习惯,因为它可以确保即使您更改容器,代码仍然可以正常工作。当然,这些功能的真正优势在于它们使模板代码更通用。

std::fill(std::begin(boards),std::end(boards),std::vector<int>(NUM_SQUARES,EMPTY));
是半保留的方法名称

虽然可以命名方法begin,但是普通的C ++用户会希望该方法返回一个迭代器,并且还希望存在另一个名为begin的方法(也返回一个迭代器)。没有任何规则说该方法名称是保留的,但是它在迭代中非常常用,实际上它完全感觉像是保留的名称。为避免潜在的歧义,我将名称end更改为begin或您班上的同等名称。这可能会帮助您或其他人避免将来遇到某些问题。

重新组织您的包含文件

只要有可能,请在实现文件中而不是标头中包含所需的标题。 。另外,尝试删除不使用的标题:


start移至tictactoe.cpp。
<iostream>移至MainWIndow.cpp。
<QFuture>移至不需要它。
我可能忘记了一些可以移动/删除的标头。
请尝试看看是否可以使用前向声明来减少.h文件中包含的标头的数量。 br /> C ++ 11类内初始化程序很棒,但是在.cpp中的构造函数中初始化变量可能反而允许您只需要在.h中进行正向声明,然后将includes移至.cpp文件。 。