欢迎大家来到IT世界,在知识的湖畔探索吧!
1,简介
Qt开发的AI人机对战五子棋游戏。
2,效果
欢迎大家来到IT世界,在知识的湖畔探索吧!
3,思路
棋盘为15*15矩阵
棋子Item 存1个坐标点、一个颜色类型(黑棋还是白棋)
绘制顺序依次为 棋盘、棋子、鼠标(也是一个棋子)
核心算法(判断五子连):
对所下的棋子,向 8个方向分别统计相邻的同色棋子个数
8个方向为:左、左上、上、右上、右、右下、下、左下
然后在一条直线的2个方向的棋子个数加起来,即得到该直线上与所下棋子相邻的同色棋子个数
棋子类Item.h:
包含一个QPoint圆心坐标,和一个bool变量,代表是黑方还是白方
#pragma once #include <QPoint> class Item { public: Item(void); Item(QPoint pt,bool bBlack); ~Item(void); //重载"=="操作符,判等需要颜色和位置都相同 bool operator==(const Item &t1)const { return ((mPt == t1.mPt) && (mBlack == t1.mBlack)); } QPoint mPt; bool mBlack; private: };
欢迎大家来到IT世界,在知识的湖畔探索吧!
MainWindow.h:
QVector<Item> mItems 保存所有棋子。
欢迎大家来到IT世界,在知识的湖畔探索吧!#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include "Item.h" #include "qmap.h" namespace Ui { class MainWindow; } #define CHESS_ROWS 15 #define CHESS_COLUMES 15 #define RECT_WIDTH 50 #define RECT_HEIGHT 50 class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); protected: void paintEvent(QPaintEvent *); void mousePressEvent(QMouseEvent *); private: void DrawChessboard(); void DrawItems(); void DrawItemWithMouse(); void DrawChessAtPoint(QPainter& painter,QPoint& pt); //统计某个方向(共8个方向)上的相连个数,用QPoint表示统计方向,如(1,1)表示右下方,(-1,0)表示向左 int CountNearItem(Item item,QPoint ptDirection); private: Ui::MainWindow *ui; QVector<Item> mItems; bool mIsBlackTurn; //当前该黑棋下 }; #endif // MAINWINDOW_H
MainWindow.cpp:
#include "mainwindow.h" #include "ui_mainwindow.h" #include "qpainter.h" #include "qevent.h" #include "qpoint.h" #include "qmessagebox.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); ui->mainToolBar->hide(); ui->menuBar->hide(); resize((CHESS_COLUMES + 1)*RECT_WIDTH ,(CHESS_ROWS + 1)*RECT_HEIGHT); mIsBlackTurn = true; } MainWindow::~MainWindow() { delete ui; } void MainWindow::paintEvent(QPaintEvent *e) { DrawChessboard(); //画棋盘 DrawItems(); //画棋子 DrawItemWithMouse(); //画鼠标(当前方的棋子形状) update(); } void MainWindow::DrawChessboard() { QPainter painter(this); painter.setRenderHint(QPainter::HighQualityAntialiasing, true); painter.setBrush(Qt::darkYellow); painter.setPen(QPen(QColor(Qt::black),2)); for(int i = 0;i<CHESS_COLUMES; i++) { for (int j = 0; j<CHESS_ROWS; j++) { painter.drawRect( (i+0.5)*RECT_WIDTH,(j+0.5)*RECT_HEIGHT,RECT_WIDTH,RECT_HEIGHT); } } } void MainWindow::DrawItems() { QPainter painter(this); painter.setPen(QPen(QColor(Qt::transparent))); for (int i = 0; i<mItems.size(); i++) { Item item = mItems[i]; if (item.mBlack) { painter.setBrush(Qt::black); } else { painter.setBrush(Qt::white); } DrawChessAtPoint(painter,item.mPt); } } void MainWindow::DrawChessAtPoint(QPainter& painter,QPoint& pt) { //painter.drawRect( (pt.x()+0.5)*RECT_WIDTH,(pt.y()+0.5)*RECT_HEIGHT,RECT_WIDTH,RECT_HEIGHT); QPoint ptCenter((pt.x()+0.5)*RECT_WIDTH,(pt.y()+0.5)*RECT_HEIGHT); painter.drawEllipse(ptCenter,RECT_WIDTH / 2,RECT_HEIGHT / 2); } void MainWindow::DrawItemWithMouse() { QPainter painter(this); painter.setPen(QPen(QColor(Qt::transparent))); if (mIsBlackTurn) { painter.setBrush(Qt::black); } else { painter.setBrush(Qt::white); } //QPoint pt; //pt.setX( (QCursor::pos().x() ) / RECT_WIDTH); //pt.setY( (QCursor::pos().y() ) / RECT_HEIGHT); //DrawChessAtPoint(painter,pt); painter.drawEllipse(mapFromGlobal(QCursor::pos()),RECT_WIDTH / 2,RECT_HEIGHT / 2); } void MainWindow::mousePressEvent(QMouseEvent * e) { //求鼠标点击处的棋子点pt QPoint pt; pt.setX( (e->pos().x() ) / RECT_WIDTH); pt.setY( (e->pos().y() ) / RECT_HEIGHT); //如果已存在棋子,就什么也不做 for (int i = 0; i<mItems.size(); i++) { Item item = mItems[i]; if (item.mPt == pt) { //已有棋子 return; } } //不存在棋子,就下一个 Item item(pt,mIsBlackTurn); mItems.append(item); //统计4个方向是否五子连 int nLeft = CountNearItem(item,QPoint(-1,0)); int nLeftUp = CountNearItem(item,QPoint(-1,-1)); int nUp = CountNearItem(item,QPoint(0,-1)); int nRightUp = CountNearItem(item,QPoint(1,-1)); int nRight = CountNearItem(item,QPoint(1,0)); int nRightDown = CountNearItem(item,QPoint(1,1)); int nDown = CountNearItem(item,QPoint(0,1)); int nLeftDown = CountNearItem(item,QPoint(-1,1)); if ( (nLeft + nRight) >= 4 || (nLeftUp + nRightDown) >= 4 || (nUp + nDown) >= 4 || (nRightUp + nLeftDown) >= 4 ) { QString str = mIsBlackTurn?"Black":"White"; QMessageBox::information(NULL, "GAME OVER",str, QMessageBox::Yes , QMessageBox::Yes); mItems.clear(); //NewGame(); return; } //该另一方下棋了 mIsBlackTurn = !mIsBlackTurn; } int MainWindow::CountNearItem(Item item,QPoint ptDirection) { int nCount = 0; item.mPt += ptDirection; while (mItems.contains(item)) { nCount++; item.mPt += ptDirection; } return nCount; } 判断五子连的算法:
(统计某个棋子item在某个方向ptDirection上,相邻的同色棋子数目)
方向用QPoint来表示,是取8个方向上1个单位坐标的点,例如:向上(0,1)、向右上(1,1)、向右(1,0)等
欢迎大家来到IT世界,在知识的湖畔探索吧!int MainWindow::CountNearItem(Item item,QPoint ptDirection) { int nCount = 0; item.mPt += ptDirection; while (mItems.contains(item)) { nCount++; item.mPt += ptDirection; } return nCount; }
这样在每次下棋后,判断所下棋子横、竖、正斜、反斜4大方向上,每个方向相邻同色棋子数目,达到5个即胜利。
这里的4个方向,每个方向需要调用CountNearItem函数两次,比如横向,需要分别以向右(1,0)和向左(-1,0)来调
CountNearItem函数。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/104920.html