parent
50a072618d
commit
207c68e525
@ -1,2 +1,274 @@
|
||||
# WZQ
|
||||
|
||||
#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"));
|
||||
}
|
||||
}
|
Loading…
Reference in new issue