C++实现五子棋(含步骤 结尾附完整代码)

使用C++实现五子棋大概分为以下四个步骤:

1.创建棋盘和游戏界面

2.实现棋子的绘制和落子

3.实现胜负判断和游戏结束

4.实现悔棋和重新开始功能

1.创建棋盘和游戏界面

首先,我们需要创建一个棋盘和游戏界面,可以使用Qt框架来实现。具体步骤如下:

1.1 创建Qt项目,并在主窗口中添加一个QGraphicsView控件,用于显示游戏界面。

1.2 在QGraphicsView中添加一个QGraphicsScene,用于绘制棋盘和棋子。

1.3 在QGraphicsScene中添加一个QPixmapItem,用于显示棋盘的背景图片。

1.4 将棋盘分成15行15列,使用QGraphicsRectItem绘制棋盘的格子。

示例代码如下:

// 创建一个棋盘场景
QGraphicsScene* scene = new QGraphicsScene(this);

// 添加背景图片
QPixmap pixmap(":/images/board.png");
QGraphicsPixmapItem* pixmapItem = new QGraphicsPixmapItem(pixmap);
scene->addItem(pixmapItem);

// 绘制棋盘的格子
const int kBoardSize = 15;
const int kCellSize = 40;
const int kMargin = 20;
for (int i = 0; i < kBoardSize; i++) {
    for (int j = 0; j < kBoardSize; j++) {
        QGraphicsRectItem* rectItem = new QGraphicsRectItem(
            kMargin + i * kCellSize, kMargin + j * kCellSize,
            kCellSize, kCellSize);
        rectItem->setPen(QPen(Qt::black, 1));
        rectItem->setBrush(QBrush(Qt::white));
        scene->addItem(rectItem);
    }
}

// 将场景添加到视图中
ui->graphicsView->setScene(scene);

2.实现棋子的绘制和落子

在游戏中,玩家需要能够通过鼠标点击来落子,并且需要在棋盘上显示出来。具体步骤如下:

2.1 创建一个QGraphicsEllipseItem,用于绘制棋子。

2.2 响应鼠标点击事件,获取鼠标点击的位置。

2.3 将鼠标点击的位置转换为棋盘上的坐标。

2.4 判断该位置是否已经有棋子,如果没有则在该位置落子。

2.5 落子后,判断游戏是否结束。

示例代码如下:

// 定义棋子的半径和颜色
const int kPieceRadius = 18;
const QColor kBlackPieceColor(Qt::black);
const QColor kWhitePieceColor(Qt::white);

// 创建一个棋子场景
QGraphicsScene* scene = new QGraphicsScene(this);

// 添加背景图片
...

// 绘制棋盘的格子
...

// 响应鼠标点击事件
void GameWidget::mousePressEvent(QMouseEvent *event) {
    // 获取鼠标点击的位置
    QPointF pos = ui->graphicsView->mapToScene(event->pos());

    // 将鼠标点击的位置转换为棋盘上的坐标
    int x = (pos.x() - kMargin + kCellSize / 2) / kCellSize;
    int y = (pos.y() - kMargin + kCellSize / 2) / kCellSize;

    // 判断该位置是否已经有棋子
    if (board_[x][y] != kEmpty) {
        return;
    }

    // 在该位置落子
    board_[x][y] = currentPlayer_;
    QGraphicsEllipseItem* pieceItem = new QGraphicsEllipseItem(
        kMargin + x * kCellSize - kPieceRadius,
        kMargin + y * kCellSize - kPieceRadius,
        kPieceRadius * 2, kPieceRadius * 2);
    pieceItem->setPen(QPen(Qt::black, 1));
    pieceItem->setBrush续上:

    (currentPlayer_ == kBlack ? kBlackPieceColor : kWhitePieceColor));
    scene->addItem(pieceItem);

    // 判断游戏是否结束
    if (checkWin(x, y)) {
        QMessageBox::information(this, tr("Game Over"),
            QString("%1 Win!").arg(currentPlayer_ == kBlack ? tr("Black") : tr("White")));
        resetGame();
        return;
    }
    if (checkTie()) {
        QMessageBox::information(this, tr("Game Over"), tr("Tie!"));
        resetGame();
        return;
    }

    // 切换玩家
    currentPlayer_ = (currentPlayer_ == kBlack ? kWhite : kBlack);
}

// 判断是否五子连珠
bool GameWidget::checkWin(int x, int y) {
    int count = 1;
    int i, j;

    // 判断横向是否五子连珠
    for (i = x - 1; i >= 0 && board_[i][y] == currentPlayer_; i--) {
        count++;
    }
    for (i = x + 1; i < kBoardSize && board_[i][y] == currentPlayer_; i++) {
        count++;
    }
    if (count >= 5) {
        return true;
    }

    // 判断纵向是否五子连珠
    count = 1;
    for (j = y - 1; j >= 0 && board_[x][j] == currentPlayer_; j--) {
        count++;
    }
    for (j = y + 1; j < kBoardSize && board_[x][j] == currentPlayer_; j++) {
        count++;
    }
    if (count >= 5) {
        return true;
    }

    // 判断左上到右下是否五子连珠
    count = 1;
    for (i = x - 1, j = y - 1; i >= 0 && j >= 0 && board_[i][j] == currentPlayer_; i--, j--) {
        count++;
    }
    for (i = x + 1, j = y + 1; i < kBoardSize && j < kBoardSize && board_[i][j] == currentPlayer_; i++, j++) {
        count++;
    }
    if (count >= 5) {
        return true;
    }

    // 判断左下到右上是否五子连珠
    count = 1;
    for (i = x - 1, j = y + 1; i >= 0 && j < kBoardSize && board_[i][j] == currentPlayer_; i--, j++) {
        count++;
    }
    for (i = x + 1, j = y - 1; i < kBoardSize && j >= 0 && board_[i][j] == currentPlayer_; i++, j--) {
        count++;
    }
    if (count >= 5) {
        return true;
    }

    return false;
}

// 判断是否平局
bool GameWidget::checkTie() {
    for (int i = 0; i < kBoardSize; i++) {
        for (int j = 0; j < kBoardSize; j++) {
            if (board_[i][j] == kEmpty) {
                return false;
            }
        }
    }
    return true;
}

3.实现胜负判断和游戏结束

在落子后,需要判断游戏是否结束。如果有一方获得了五子连珠,则该方获胜;如果棋盘已经填满,但仍然没有五子连珠,则游戏结束,双方平局。具体步骤如下:

3.1 编写checkWin函数,用于判断是否存在五子连珠。

3.2 编写checkTie函数,用于判断是否平局。

3.3 在落子后,判断游戏是否结束。如果游戏结束,则弹出游戏结束信息,并重置游戏。

示例代码如下:

// 在GameWidget类中添加以下成员变量
private:
    QGraphicsScene* scene;              // 棋盘场景
    QGraphicsEllipseItem* lastItem_;    // 上一个落子的棋子
    PieceType board_[kBoardSize][kBoardSize]; // 棋盘数组
    PieceType currentPlayer_;           // 当前玩家

// 在GameWidget类的构造函数中添加以下代码,用于初始化棋盘
GameWidget::GameWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::GameWidget)
{
    ui->setupUi(this);

    // 创建棋盘场景
    scene = new QGraphicsScene(this);
    ui->boardView->setScene(scene);
    ui->boardView->setRenderHint(QPainter::Antialiasing);

    // 绘制棋盘
    for (int i = 0; i < kBoardSize; i++) {
        for (int j = 0; j < kBoardSize; j++) {
            QGraphicsRectItem* rect = new QGraphicsRectItem(i * kCellSize, j * kCellSize, kCellSize, kCellSize);
            rect->setPen(Qt::NoPen);
            rect->setBrush(QBrush(QColor("#D18B47"), Qt::SolidPattern));
            scene->addItem(rect);
        }
    }

    // 初始化棋盘数组
    for (int i = 0; i < kBoardSize; i++) {
        for (int j = 0; j < kBoardSize; j++) {
            board_[i][j] = kEmpty;
        }
    }

    // 初始化当前玩家为黑色
    currentPlayer_ = kBlack;
    ui->statusLabel->setText(tr("Black's turn"));
}

// 响应落子事件
void GameWidget::mousePressEvent(QMouseEvent* event) {
    if (event->button() != Qt::LeftButton) {
        return;
    }

    QPointF pos = ui->boardView->mapToScene(event->pos());

    // 将落点转换为棋盘坐标
    int x = qRound(pos.x() / kCellSize);
    int y = qRound(pos.y() / kCellSize);

    // 判断落点是否有效,如果无效则返回
    if (x < 0 || x >= kBoardSize || y < 0 || y >= kBoardSize || board_[x][y] != kEmpty) {
        return;
    }

    // 在落点绘制棋子
    QGraphicsEllipseItem* item = new QGraphicsEllipseItem(x * kCellSize + kMargin, y * kCellSize + kMargin,
                                                           kPieceSize, kPieceSize);
    item->setBrush(QBrush((currentPlayer_ == kBlack) ? Qt::black : Qt::white, Qt::SolidPattern));
    scene->addItem(item);

    // 记录落子位置和棋子对象
    QPoint point(x, y);
    history_.push(point);
    lastItem_ = item;

    // 更新棋盘数组
    board_[x][y] = currentPlayer_;

    // 判断游戏是否结束
    if (checkWin(x, y)) {
        QString message = (currentPlayer_ == kBlack) ? tr("Black wins!") : tr("White wins!");
        QMessageBox::StandardButton button = QMessageBox::information(this, tr("Game Over"), message);
        if (button == QMessageBox::Ok) {
            resetGame();
        }
        return;
    } else if (checkTie()) {
        QMessageBox::StandardButton button = QMessageBox::information(this, tr("Game Over"), tr("Tie!"));
        if (button == QMessageBox::Ok) {
            resetGame();
        }
        return;
    }

    // 切换玩家
    currentPlayer_ = (currentPlayer_ == kBlack) ? kWhite : kBlack;
    ui->statusLabel->setText((currentPlayer_ == kBlack) ? tr("Black's turn") : tr("White's turn"));
}

// 判断是否五子连珠
bool GameWidget::checkWin(int x, int y) {
    int i, j, count;

    // 判断横向是否五子连珠
    count = 1;
    for (i = x - 1; i >= 0 && board_[i][y] == currentPlayer_; i--) {
        count++;
    }
    for (i = x + 1; i < kBoardSize && board_[i][y] == currentPlayer_; i++) {
        count++;
    }
    if (count >= 5)请注意,在这段代码中,有一些变量和常量没有定义。其中,kBoardSize、kCellSize、kMargin、kPieceSize、kEmpty、kBlack、kWhite都是需要定义的。如果您已经在之前的代码中定义了这些变量和常量,可以直接使用以下代码片段。如果没有,请先定义这些变量和常量,再使用以下代码片段。

```cpp
const int kBoardSize = 15;             // 棋盘大小
const int kCellSize = 40;              // 格子大小
const int kMargin = 20;                // 棋盘边距
const int kPieceSize = 30;             // 棋子大小

enum PieceType {
    kEmpty,
    kBlack,
    kWhite
};

4.实现悔棋和重新开始

在游戏中,玩家需要能够进行悔棋和重新开始游戏。具体步骤如下:

4.1 在界面上添加两个按钮,分别用于悔棋和重新开始游戏。

4.2 响应按钮点击事件,实现悔棋和重新开始游戏的功能。

4.3 在实现悔棋功能时,需要将棋盘上最后一个落子的位置清空。

示例代码如下:

// 在界面上添加两个按钮
ui->undoButton->setText(tr("悔棋"));
connect(ui->undoButton, &QPushButton::clicked, this, &GameWidget::undo);

ui->restartButton->setText(tr("重新开始"));
connect(ui->restartButton, &QPushButton::clicked, this, &GameWidget::restart);

// 实现悔棋功能
void GameWidget::undo() {
    // 获取棋盘上最后一个落子的位置
    int x = history_.back().x;
    int y = history_.back().y;

    // 清空该位置的棋子
    board_[x][y] = kEmpty;
    QGraphicsItem* item = scene_->itemAt(
        kMargin + x * kCellSize, kMargin + y * kCellSize,
        QTransform());
    if (item != nullptr) {
        scene_->removeItem(item);
        delete item;
    }

    // 移除落子历史记录中的最后一个位置
    history_.pop_back();

    // 切换当前玩家
    currentPlayer_ = (currentPlayer_ == kBlack) ? kWhite : kBlack;
}

// 实现重新开始游戏的功能
void GameWidget::restart() {
    // 清空棋盘
    memset(board_, kEmpty, sizeof(board_));

    // 清空场景中的棋子
    QList<QGraphicsItem*> items = scene_->items();
    for (auto item : items) {
        scene_->removeItem(item);
        delete item;
    }

    // 清空落子历史记录
    history_.clear();

    // 切换当前玩家
    currentPlayer_ = kBlack;
}

以上就是使用C++实现五子棋游戏的详细代码教程,包括棋盘和游戏界面的创建、棋子的绘制和落子、胜负判断和游戏结束、悔棋和重新开始功能。由于篇幅限制,代码中可能存在一些细节问题,需要根据具体情况进行调整。

以下是完整代码:

#include "gamewidget.h"
#include "ui_gamewidget.h"
#include <QGraphicsRectItem>
#include <QGraphicsEllipseItem>
#include <QMessageBox>

const int kBoardSize = 15;             // 棋盘大小
const int kCellSize = 40;              // 格子大小
const int kMargin = 20;                // 棋盘边距
const int kPieceSize = 30;             // 棋子大小

enum PieceType {
    kEmpty,
    kBlack,
    kWhite
};

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

    // 创建棋盘场景
    scene = new QGraphicsScene(this);
    ui->boardView->setScene(scene);
    ui->boardView->setRenderHint(QPainter::Antialiasing);

    // 绘制棋盘
    for (int i = 0; i < kBoardSize; i++) {
        for (int j = 0; j < kBoardSize; j++) {
            QGraphicsRectItem* rect = new QGraphicsRectItem(i * kCellSize, j * kCellSize, kCellSize, kCellSize);
            rect->setPen(Qt::NoPen);
            rect->setBrush(QBrush(QColor("#D18B47"), Qt::SolidPattern));
            scene->addItem(rect);
        }
    }

    // 初始化棋盘数组
    for (int i = 0; i < kBoardSize; i++) {
        for (int j = 0; j < kBoardSize; j++) {
            board_[i][j] = kEmpty;
        }
    }

    // 初始化当前玩家为黑色
    currentPlayer_ = kBlack;
    ui->statusLabel->setText(tr("Black's turn"));
}

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

void GameWidget::mousePressEvent(QMouseEvent* event) {
    if (event->button() != Qt::LeftButton) {
        return;
    }

    QPointF pos = ui->boardView->mapToScene(event->pos());

    // 将落点转换为棋盘坐标
    int x = qRound(pos.x() / kCellSize);
    int y = qRound(pos.y() / kCellSize);

    // 判断落点是否有效,如果无效则返回
    if (x < 0 || x >= kBoardSize || y < 0 || y >= kBoardSize || board_[x][y] != kEmpty) {
        return;
    }

    // 在落点绘制棋子
    QGraphicsEllipseItem* item = new QGraphicsEllipseItem(x * kCellSize + kMargin, y * kCellSize + kMargin,
                                                           kPieceSize, kPieceSize);
    item->setBrush(QBrush((currentPlayer_ == kBlack) ? Qt::black : Qt::white, Qt::SolidPattern));
    scene->addItem(item);

    // 记录落子位置和棋子对象
    QPoint point(x, y);
    history_.push(point);
    lastItem_ = item;

    // 更新棋盘数组
    board_[x][y] = currentPlayer_;

    // 判断游戏是否结束
    if (checkWin(x, y)) {
        QString message = (currentPlayer_ == kBlack) ? tr("Black wins!") : tr("White wins!");
        QMessageBox::StandardButton button = QMessageBox::information(this, tr("Game Over"), message);
        if (button == QMessageBox::Ok) {
            resetGame();
        }
        return;
    } else if (checkTie()) {
        QMessageBox::StandardButton button = QMessageBox::information(this, tr("Game Over"), tr("Tie!"));
        if (button == QMessageBox::Ok) {
            resetGame();
        }
        return;
    }

    // 切换玩家
    currentPlayer_ = (currentPlayer_ == kBlack) ? kWhite : kBlack;
    ui->statusLabel->setText((currentPlayer_ == kBlack) ? tr("Black's turn") : tr("White's turn"));
}

bool GameWidget::checkWin(int x, int y) {
    int i, j, count;

    // 判断横向是否五子连珠
    count = 1;
    for (i = x - 1; i >= 0 && board_[i][y] == currentPlayer_; i--) {
        count++;
    }
    for (i = x + 1; i < kBoardSize && board_[i][y] == currentPlayer_; i++) {
        count++;
    }
    if (count >= 5) {
        return true;
    }

    // 判断纵向是否五子连珠
    count = 1;
    for (j = y - 1; j >= 0 && board_[x][j] == currentPlayer_; j--) {
        count++;
    }
    for (j = y + 1; j < kBoardSize && board_[x][j] == currentPlayer_; j++) {
        count++;
    }
    if (count >= 5) {
        return true;
    }

    // 判断左上到右下是否五子连珠
    count = 1;
    for (i = x - 1, j = y - 1; i >= 0 && j >= 0 && board_[i][j] == currentPlayer_; i--, j--) {
        count++;
    }
    for (i = x + 1, j = y + 1; i < kBoardSize && j < kBoardSize && board_[i][j] == currentPlayer_; i++, j++) {
        count++;
    }
    if (count >= 5) {
        return true;
    }

    // 判断左下到右上是否五子连珠
    count = 1;
    for (i = x - 1, j = y + 1; i >= 0 && j < kBoardSize && board_[i][j] == currentPlayer_; i--, j++) {
        count++;
    }
    for (i = x + 1, j = y - 1; i < kBoardSize && j >= 0 && board_[i][j] == currentPlayer_; i++, j--) {
        count++;
    }
    if (count >= 5) {
        return true;
    }

    return false;
}

bool GameWidget::checkTie() {
    for (int i = 0; i < kBoardSize; i++) {
        for (int j = 0; j < kBoardSize; j++) {
            if (board_[i][j] == kEmpty) {
                return false;
            }
        }
    }
    return true;
}

void GameWidget::resetGame() {
    // 清空棋盘场景和棋盘数组
    scene->clear();
    for (int i = 0; i < kBoardSize; i++) {
        for (int j = 0; j < kBoardSize; j++) {
            board_[i][j] = kEmpty;
        }
    }

    // 重置历史记录和当前玩家
    while (!history_.empty()) {
        history_.pop();
    }
    currentPlayer_ = kBlack;

    // 更新状态栏
    ui->statusLabel->setText(tr("Black's turn"));
}

void GameWidget::undo() {
    // 如果历史记录为空,则返回
    if (history_.empty()) {
        return;
    }

    // 恢复上一个落子点的状态,并从历史记录中删除该点
    QPoint point = history_.top();
    history_.pop();
    board_[point.x()][point.y()] = kEmpty;
    scene->removeItem(lastItem_);
    delete lastItem_;
    lastItem_ = nullptr;

    // 切换当前玩家
    currentPlayer_ = (currentPlayer_ == kBlack) ? kWhite : kBlack;
    ui->statusLabel->setText((currentPlayer_ == kBlack) ? tr("Black's turn") : tr("White's turn"));
}

void GameWidget::newGame() {
    // 弹出确认对话框
    QMessageBox::StandardButton button = QMessageBox::question(this, tr("New Game"),
                                                               tr("Are you sure you want to start a new game?"),
                                                               QMessageBox::Yes | QMessageBox::No);
    if (button == QMessageBox::Yes) {
        resetGame();
    }
}

void GameWidget::saveGame() {
    // 弹出保存对话框,获取保存文件路径
    QString fileName = QFileDialog::getSaveFileName(this, tr("Save Game"), ".", tr("Game files (*.game)"));
    if (fileName.isEmpty()) {
        return;
    }

    // 打开保存文件,保存棋盘数组和当前玩家
    QFile file(fileName);
    if (file.open(QIODevice::WriteOnly)) {
        QDataStream stream(&file);
        stream.writeRawData((const char*)board_, sizeof(board_));
        stream << currentPlayer_;
        file.close();
    }
}

void GameWidget::loadGame() {
    // 弹出打开对话框,获取打开文件路径
    QString fileName = QFileDialog::getOpenFileName(this, tr("Load Game"), ".", tr("Game files (*.game)"));
if (fileName.isEmpty()) {
return;
}
// 打开保存文件,读取棋盘数组和当前玩家
QFile file(fileName);
if (file.open(QIODevice::ReadOnly)) {
    QDataStream stream(&file);
    stream.readRawData((char*)board_, sizeof(board_));
    stream >> currentPlayer_;
    file.close();

    // 清空棋盘场景,重新绘制棋盘和棋子
    scene->clear();
    for (int i = 0; i < kBoardSize; i++) {
        for (int j = 0; j < kBoardSize; j++) {
            QGraphicsRectItem* rect = new QGraphicsRectItem(i * kCellSize, j * kCellSize, kCellSize, kCellSize);
            rect->setPen(Qt::NoPen);
            rect->setBrush(QBrush(QColor("#D18B47"), Qt::SolidPattern));
            scene->addItem(rect);

            if (board_[i][j] != kEmpty) {
                QGraphicsEllipseItem* item = new QGraphicsEllipseItem(i * kCellSize + kMargin, j * kCellSize + kMargin,
                                                                       kPieceSize, kPieceSize);
                item->setBrush(QBrush((board_[i][j] == kBlack) ? Qt::black : Qt::white, Qt::SolidPattern));
                scene->addItem(item);
            }
        }
    }

    // 更新状态栏
    ui->statusLabel->setText((currentPlayer_ == kBlack) ? tr("Black's turn") : tr("White's turn"));
}
}

  • 10
    点赞
  • 80
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值