Qt、C++实现五子棋人机对战与本地双人对战(高难度AI,极少代码)

#include "mainwindow.h" #include "ui_mainwindow.h" #include <QMessageBox> #include <cstdlib> // 用于随机数生成(AI 落子) MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow), board(boardSize, QVector<int>(boardSize, 0)) { ui->setupUi(this); // 设置窗口大小 setFixedSize(gridSize * boardSize, gridSize * boardSize + 80); // 初始化按钮 newGameButton = new QPushButton("新游戏", this); switchModeButton = new QPushButton("切换模式", this); // 初始化标签 statusLabel = new QLabel("当前轮到黑棋", this); modeLabel = new QLabel("当前模式:人人对战", this); // 初始化难度选择下拉框 difficultyComboBox = new QComboBox(this); difficultyComboBox->addItem("简单"); difficultyComboBox->addItem("中等"); difficultyComboBox->addItem("困难"); difficultyComboBox->setCurrentIndex(difficultyLevel - 1); // 默认选中“简单” // 设置控件位置 newGameButton->setGeometry(10, gridSize * boardSize + 10, 100, 30); switchModeButton->setGeometry(120, gridSize * boardSize + 10, 100, 30); difficultyComboBox->setGeometry(240, gridSize * boardSize + 10, 80, 30); statusLabel->setGeometry(330, gridSize * boardSize + 10, 120, 30); modeLabel->setGeometry(10, gridSize * boardSize + 50, 200, 30); // 设置按钮样式 QString buttonStyle = "QPushButton {" " background-color: #87CEFA;" // 浅蓝色背景 " color: white;" // 白色文字 " border-radius: 10px;" // 圆角 " font-size: 14px;" // 字体大小 " padding: 5px 10px;" "}" "QPushButton:hover {" " background-color: #4682B4;" // Hover时深蓝色 "}"; newGameButton->setStyleSheet(buttonStyle); switchModeButton->setStyleSheet(buttonStyle); // 设置下拉框样式 difficultyComboBox->setStyleSheet( "QComboBox {" " border: 2px solid #4682B4;" // 深蓝色边框 " border-radius: 5px;" " padding: 3px 8px;" " font-size: 14px;" "}" "QComboBox::drop-down {" " border: none;" "}" "QComboBox:hover {" " border-color: #87CEFA;" // Hover时浅蓝边框 "}" ); // 设置标签样式 QString labelStyle = "QLabel {" " font-size: 16px;" " color: #2F4F4F;" // 深灰色文字 " font-weight: bold;" "}"; statusLabel->setStyleSheet(labelStyle); modeLabel->setStyleSheet(labelStyle); // 绑定信号与槽 connect(newGameButton, &QPushButton::clicked, this, &MainWindow::onNewGameClicked); connect(switchModeButton, &QPushButton::clicked, this, &MainWindow::onSwitchModeClicked); connect(difficultyComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &MainWindow::onDifficultyChanged); } MainWindow::~MainWindow() { delete ui; } void MainWindow::paintEvent(QPaintEvent *) { QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); // 绘制棋盘背景 painter.setBrush(QColor(245, 222, 179)); // 棋盘为浅棕色 painter.drawRect(0, 0, gridSize * boardSize, gridSize * boardSize); // 绘制棋盘线条 painter.setPen(QPen(Qt::black, 2)); // 黑色线条,宽度2px for (int i = 0; i < boardSize; ++i) { painter.drawLine(gridSize / 2, gridSize / 2 + i * gridSize, gridSize / 2 + (boardSize - 1) * gridSize, gridSize / 2 + i * gridSize); painter.drawLine(gridSize / 2 + i * gridSize, gridSize / 2, gridSize / 2 + i * gridSize, gridSize / 2 + (boardSize - 1) * gridSize); } // 绘制棋子 for (int i = 0; i < boardSize; ++i) { for (int j = 0; j < boardSize; ++j) { if (board[i][j] == 1) { painter.setBrush(Qt::black); painter.drawEllipse(gridSize / 2 + i * gridSize - 15, gridSize / 2 + j * gridSize - 15, 30, 30); } else if (board[i][j] == 2) { painter.setBrush(Qt::white); painter.drawEllipse(gridSize / 2 + i * gridSize - 15, gridSize / 2 + j * gridSize - 15, 30, 30); } } } } void MainWindow::mousePressEvent(QMouseEvent *event) { if (!isBlackTurn && isPlayerVsAI) return; // 人机对战时禁止白棋玩家操作 // 计算点击的位置对应的棋盘格子 int x = (event->x() - gridSize / 2 + gridSize / 2) / gridSize; int y = (event->y() - gridSize / 2 + gridSize / 2) / gridSize; // 检查点击是否在有效范围内,且是否未落子 if (x < 0 || x >= boardSize || y < 0 || y >= boardSize || board[x][y] != 0) return; // 记录当前落子 board[x][y] = isBlackTurn ? 1 : 2; isBlackTurn = !isBlackTurn; // 更新提示信息 statusLabel->setText(isBlackTurn ? "当前轮到黑棋" : "当前轮到白棋"); update(); // 更新界面 checkWin(x, y); // 如果是人机对战模式,AI 落子 if (!isBlackTurn && isPlayerVsAI) { aiMove(); } } void MainWindow::checkWin(int x, int y) { int directions[4][2] = {{1, 0}, {0, 1}, {1, 1}, {1, -1}}; int currentPlayer = board[x][y]; for (auto &dir : directions) { int count = 1; for (int i = 1; i < 5; ++i) { int nx = x + i * dir[0], ny = y + i * dir[1]; if (nx >= 0 && nx < boardSize && ny >= 0 && ny < boardSize && board[nx][ny] == currentPlayer) ++count; else break; } for (int i = 1; i < 5; ++i) { int nx = x - i * dir[0], ny = y - i * dir[1]; if (nx >= 0 && nx < boardSize && ny >= 0 && ny < boardSize && board[nx][ny] == currentPlayer) ++count; else break; } if (count >= 5) { QString winner = (currentPlayer == 1) ? "黑棋" : "白棋"; QMessageBox::information(this, "游戏结束", winner + " 胜利!"); resetGame(); return; } } } void MainWindow::resetGame() { for (auto &row : board) row.fill(0); isBlackTurn = true; statusLabel->setText("当前轮到黑棋"); update(); } void MainWindow::onNewGameClicked() { resetGame(); } void MainWindow::onSwitchModeClicked() { isPlayerVsAI = !isPlayerVsAI; // 切换模式 QString modeText = isPlayerVsAI ? "人机对战模式" : "人人对战模式"; modeLabel->setText("当前模式:" + modeText); // 更新模式显示 QMessageBox::information(this, "模式切换", modeText); resetGame(); // 切换模式后重置棋盘 } void MainWindow::onDifficultyChanged(int index) { difficultyLevel = index + 1; // 更新难度等级 QString difficultyText = difficultyComboBox->currentText(); QMessageBox::information(this, "难度选择", "当前难度:" + difficultyText); } void MainWindow::aiMove() { int bestX = -1, bestY = -1; if (difficultyLevel == 1) { // 简单模式:随机选择空位 while (true) { int x = rand() % boardSize; int y = rand() % boardSize; if (board[x][y] == 0) { bestX = x; bestY = y; break; } } } else { // 中等/困难模式:计算最佳位置 int maxScore = -1; QVector<QVector<int>> score(boardSize, QVector<int>(boardSize, 0)); for (int x = 0; x < boardSize; ++x) { for (int y = 0; y < boardSize; ++y) { if (board[x][y] != 0) continue; int baseScore = calculateScore(x, y, 2) + calculateScore(x, y, 1); if (difficultyLevel == 3) { // 困难模式:增加中心权重 int distanceToCenter = abs(x - boardSize / 2) + abs(y - boardSize / 2); baseScore += (boardSize - distanceToCenter) * 5; } score[x][y] = baseScore; if (baseScore > maxScore) { maxScore = baseScore; bestX = x; bestY = y; } } } } // 在最佳位置落子 if (bestX != -1 && bestY != -1) { board[bestX][bestY] = 2; isBlackTurn = true; statusLabel->setText("当前轮到黑棋"); update(); checkWin(bestX, bestY); } } int MainWindow::calculateScore(int x, int y, int player) { int directions[4][2] = {{1, 0}, {0, 1}, {1, 1}, {1, -1}}; int score = 0; for (auto &dir : directions) { int count = 1; // 当前玩家的连子数 int block = 0; // 是否被堵住:0为两端均开,1为一端堵,2为两端堵 int empty = 0; // 连子中的空位数 // 正向检查 for (int i = 1; i < 5; ++i) { int nx = x + i * dir[0]; int ny = y + i * dir[1]; if (nx < 0 || nx >= boardSize || ny < 0 || ny >= boardSize) { block++; // 超出棋盘视为堵住 break; } if (board[nx][ny] == player) { count++; } else if (board[nx][ny] == 0) { empty++; break; // 停止正向检查 } else { block++; break; // 对方棋子,视为堵住 } } // 反向检查 for (int i = 1; i < 5; ++i) { int nx = x - i * dir[0]; int ny = y - i * dir[1]; if (nx < 0 || nx >= boardSize || ny < 0 || ny >= boardSize) { block++; break; } if (board[nx][ny] == player) { count++; } else if (board[nx][ny] == 0) { empty++; break; } else { block++; break; } } // 根据连子数、空位数和堵塞情况评估分值 if (count >= 5) { score += 10000
上一篇:HTML 元素详解


下一篇:Java RPC框架的接口预热原理及无损实现