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

您所在的位置:网站首页 五子棋怎么样 C++实现五子棋(含步骤 结尾附完整代码)

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

2024-07-12 18:45| 来源: 网络整理| 查看: 265

使用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 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 #include #include 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(); // 清空棋盘场景,重新绘制棋盘和棋子 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")); } }



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3