五子棋大战

编程入门 行业动态 更新时间:2024-10-27 20:30:41

<a href=https://www.elefans.com/category/jswz/34/1769950.html style=五子棋大战"/>

五子棋大战

QQ录屏20220807164624

1.数据模型

构思好代码的数据,并实现相应的算法

#ifndef GAMEMODLE_H
#define GAMEMODLE_H
//五指棋模型
#include<vector>//游戏类型
enum GameType{MAN,//人人对战AI,//人机对战};
enum GameStatus{PLAYING,//正在执行WIN, //胜利DEAD //
};
//棋盘尺寸
const int BOARD_GRAD_SZIE =15;//15 x 15;const int MARGIN =30; //棋盘边缘空白
const int CHESS_RADIUS= 15;//棋子半径
const int MARK_SIZE =6; //落子标记边长
const int BLOCK_SIZE =40;//格子大小const int POS_OFFSET =BLOCK_SIZE *0.4;//鼠标点击模糊距离上限const int AI_THINK_TIME =100; //AI延迟的速度class GameModel
{
public:GameModel();public://存储当前游戏棋盘和棋子的情况,空白为0,黑子为1,白子为-1std::vector<std::vector<int>> gameMapVec;//存储各个点的评分情况,作为AI下棋依据std::vector<std::vector<int>> scoreMapVec;//标识下下棋放,true:黑棋,false//AI白棋bool playerFlag;GameType gameType;//游戏模式GameStatus gameStatus;//游戏状态void startGame(GameType type);//开始游戏void calculateScore();//计算评分void actionByPerson(int row,int col);//人执行下棋void actionByAI(int &clickRow, int &clickcol);//机器执行下棋void  updateGameMap(int row,int col);//每次落子更行游戏棋盘bool isWin(int row,int col);//判断游戏是否胜利bool isDeadGame();//判断是否和棋};#endif // GAMEMODLE_H

绘制棋盘

 QPainter p1(this);p1.setRenderHint(QPainter::Antialiasing);//设置抗锯齿//画棋盘for(int i=0;i<BOARD_GRAD_SZIE+1;i++){//C从左到右画(i+1)第一条竖线p1.drawLine(MARGIN+BLOCK_SIZE*i,MARGIN,MARGIN+BLOCK_SIZE*i,size().height()-MARGIN);//从上到下,第(i+1)条横线p1.drawLine(MARGIN,MARGIN+BLOCK_SIZE*i,width()-MARGIN,MARGIN+BLOCK_SIZE*i);}

//实现模糊标记

void MainWindow::mouseMoveEvent(QMouseEvent *event)
{//通过鼠标的移动确定落子标记int x = event->x();int y =event->y();//棋子边缘不能落子if(x >= MARGIN+BLOCK_SIZE/2&&x<size().width()-MARGIN-BLOCK_SIZE/2&&y>=MARGIN+BLOCK_SIZE/2&&y<this->height()-MARGIN-BLOCK_SIZE/2){//获得最近的左上角的点  坐标减去边界除方格宽度int col =(x-MARGIN)/BLOCK_SIZE;//行int row =(y-MARGIN)/BLOCK_SIZE;//列int leftTopPosX=MARGIN+BLOCK_SIZE*col;int leftTopPosY=MARGIN+BLOCK_SIZE*row;//根据距离算出合适的点击位置,点击位置四周四个点,根据距离最近的clickPosRow=-1;//行初始化clickPosCol=-1;int len=0;//鼠标点击与四个顶点距离selectPos=false;//确定一个误差在范围内的点,有且只有一个可以确定下来//两直角边求斜边len左上角len=sqrt((x-leftTopPosX)*(x-leftTopPosX)+(y-leftTopPosY)*(y-leftTopPosY));if(len<POS_OFFSET){clickPosRow=row;clickPosCol=col;//判断棋盘有没有棋子,没有就下,标志位改变if(game->gameMapVec[clickPosRow][clickPosCol]==0){selectPos=true;}}//len 右上角距离len=sqrt( (x-(leftTopPosX+BLOCK_SIZE)) *(x-(leftTopPosX+BLOCK_SIZE))+(y-leftTopPosY)*(y-leftTopPosY) );if(len<POS_OFFSET){clickPosRow=row;clickPosCol=col+1;//棋盘行加1//判断棋盘有没有棋子,没有就下,标志位改变if(game->gameMapVec[clickPosRow][clickPosCol]==0){selectPos=true;}}//len左下角距离len=sqrt( (x-leftTopPosX) *(x-leftTopPosX)+(y-(leftTopPosY+BLOCK_SIZE))*(y-(leftTopPosY+BLOCK_SIZE)));if(len<POS_OFFSET){clickPosRow=row+1;clickPosCol=col;//判断棋盘有没有棋子,没有就下,标志位改变if(game->gameMapVec[clickPosRow][clickPosCol]==0){selectPos=true;}}//右下角len =sqrt( (x-(leftTopPosX+BLOCK_SIZE)) *(x-(leftTopPosX+BLOCK_SIZE))+ (y-(leftTopPosY+BLOCK_SIZE))*(y-(leftTopPosY+BLOCK_SIZE)));if(len<POS_OFFSET){clickPosRow=row+1;clickPosCol=col+1;//判断棋盘有没有棋子,没有就下,标志位改变if(game->gameMapVec[clickPosRow][clickPosCol]==0){selectPos=true;}}}//重新绘制update();}

//绘制并落下棋子

//绘制选点QPainter p2(this);QBrush brush;brush.setStyle(Qt::SolidPattern);//绘制防止落子标记(鼠标越界)if(clickPosRow>0&&clickPosRow<BOARD_GRAD_SZIE&&clickPosCol>0&&clickPosCol<BOARD_GRAD_SZIE&&game->gameMapVec[clickPosRow][clickPosCol]==0){if(game->playerFlag){brush.setColor(Qt::black);}else{brush.setColor(Qt::white);}p2.setBrush(brush);p2.drawRect(MARGIN+BLOCK_SIZE*clickPosCol-MARK_SIZE/2,MARGIN+BLOCK_SIZE*clickPosRow,MARK_SIZE,MARK_SIZE);}//绘制棋子for(int i=0;i<BOARD_GRAD_SZIE;i++){for(int j=0;j<BOARD_GRAD_SZIE;j++){if(game->gameMapVec[i][j]==1){brush.setColor(Qt::black);p2.setBrush(brush);p2.drawEllipse(MARGIN+BLOCK_SIZE*j-CHESS_RADIUS,MARGIN+BLOCK_SIZE*i-CHESS_RADIUS,CHESS_RADIUS*2,CHESS_RADIUS*2);}else if(game->gameMapVec[i][j]==-1){brush.setColor(Qt::white);p2.setBrush(brush);p2.drawEllipse(MARGIN+BLOCK_SIZE*j-CHESS_RADIUS,MARGIN+BLOCK_SIZE*i-CHESS_RADIUS,CHESS_RADIUS*2,CHESS_RADIUS*2);}}}

//人下棋

void GameModel::actionByPerson(int row, int col)
{//更新数据updateGameMap(row,col);
}
void  GameModel::updateGameMap(int row, int col)
{if(playerFlag)gameMapVec[row][col]=1;elsegameMapVec[row][col]=-1;//重绘playerFlag=!playerFlag;}
//判断是否输赢
bool GameModel::isWin(int row, int col)
{//垂直方向是否有五个子for(int i;i<5;i++){if(row>0&&row<BOARD_GRAD_SZIE&&col-i>0&&col-i+4<BOARD_GRAD_SZIE&&//基准点上下是否有4个相同棋子gameMapVec[row][col-i] == gameMapVec[row][col-i+1]&&gameMapVec[row][col-i] == gameMapVec[row][col-i+2]&&gameMapVec[row][col-i] == gameMapVec[row][col-i+3]&&gameMapVec[row][col-i] == gameMapVec[row][col-i+4])return true;}//水平方向for(int i=0;i<5;i++){if(row-i>0&&row-i+4<BOARD_GRAD_SZIE &&col>0&&col<BOARD_GRAD_SZIE&&gameMapVec[row-i][col] == gameMapVec[row-i+1][col]&&gameMapVec[row-i][col] == gameMapVec[row-i+2][col]&&gameMapVec[row-i][col] == gameMapVec[row-i+3][col]&&gameMapVec[row-i][col] == gameMapVec[row-i+4][col])return true;}// '/'方向判断右下for(int i =0;i<5;i++){if(row-i>0 && row-i+4<BOARD_GRAD_SZIE&&col+i-4>0 && col+i<BOARD_GRAD_SZIE&&gameMapVec[row-i][col+i] ==gameMapVec[row-i+1][col+i-1] &&gameMapVec[row-i][col+i] ==gameMapVec[row-i+2][col+i-2] &&gameMapVec[row-i][col+i] ==gameMapVec[row-i+3][col+i-3]&&gameMapVec[row-i][col+i] ==gameMapVec[row-i+4][col+i-4])return true;}// '\'方向左下for(int i=0;i<5;i++){if(row-i>0 &&row-i+4<BOARD_GRAD_SZIE &&col-i>0 && col-i+4<BOARD_GRAD_SZIE&&gameMapVec[row-i][col-i] ==gameMapVec[row-i+1][col-i+1] &&gameMapVec[row-i][col-i] ==gameMapVec[row-i+2][col-i+2] &&gameMapVec[row-i][col-i] ==gameMapVec[row-i+3][col-i+3] &&gameMapVec[row-i][col-i] ==gameMapVec[row-i+4][col-i+4] )return true;}return false;}

//AI下棋

AI算法根据棋子的八个方向的棋子获得分数,再根据取最佳分数实现人工智能算法

void GameModel::calculateScore()
{//統計玩家或者電腦連成的子int personNum = 0; //玩家連成子的個數int botNum = 0;   //AI連成子的個數int emptyNum = 0;   //各方向空白位的個數//清空評分數組scoreMapVec.clear();for(int i=0;i<BOARD_GRAD_SZIE;i++){std::vector<int> lineScores;for(int j=0;j<BOARD_GRAD_SZIE;j++){lineScores.push_back(0);}scoreMapVec.push_back(lineScores);}//計分/*計分個人理解:* 遍歷每一個格子,判斷哪些是空白的點(即為0的點),以該點為中心,判斷周圍的八個點向外延伸的四格裡,* 有多少個是黑子、白子、空白,以此作為依據來評分。下方算法是以守為主,所以守的分數>攻的分數*/for(int row=0;row<BOARD_GRAD_SZIE;row++){for(int col=0;col<BOARD_GRAD_SZIE;col++){//空白點才算if(row>0 && col>0 && gameMapVec[row][col]==0){//遍歷周圍8個方向for(int y=-1;y<=1;y++){for(int x=-1;x<=1;x++){//重置personNum = 0;botNum = 0;emptyNum = 0;//原坐標不算if(!(y==0 && x==0)){//每個方向延伸4個子//對玩家黑子評分(正反兩個方向)for(int i=1;i<=4;i++){if(row+i*y>0 && row+i*y<BOARD_GRAD_SZIE &&col+i*x>0 && col+i*x<BOARD_GRAD_SZIE &&gameMapVec[row+i*y][col+i*x]==1){ //真人玩家的子personNum++;}else if(row+i*y>0 && row+i*y<BOARD_GRAD_SZIE &&col+i*x>0 && col+i*x<BOARD_GRAD_SZIE &&gameMapVec[row+i*y][col+i*x]==0){ //空白位emptyNum++;break;}else{ //出邊界,或有白子break;}}for(int i=1;i<=4;i++){if(row-i*y>0 && row-i*y<BOARD_GRAD_SZIE &&col-i*x>0 && col-i*x<BOARD_GRAD_SZIE &&gameMapVec[row-i*y][col-i*x]==1){ //真人玩家的子personNum++;}else if(row-i*y>0 && row-i*y<BOARD_GRAD_SZIE &&col-i*x>0 && col-i*x<BOARD_GRAD_SZIE &&gameMapVec[row-i*y][col-i*x]==0){ //空白位emptyNum++;break;}else{ //出邊界,或有白子break;}}if(personNum == 1){                 //殺2scoreMapVec[row][col]+=10;}else if(personNum == 2){           //殺3if(emptyNum == 1)scoreMapVec[row][col]+=30;else if(emptyNum == 2)scoreMapVec[row][col]+=40;}else if(personNum == 3){           //殺4//量變空位不一樣,優先級不一樣if(emptyNum == 1)scoreMapVec[row][col]+=60;else if(emptyNum == 2)scoreMapVec[row][col]+=110;}else if(personNum == 4){           //殺5scoreMapVec[row][col]+=10100;}//進行一次清空emptyNum = 0;//對AI白子評分for(int i=1;i<=4;i++){if(row+i*y>0 && row+i*y<BOARD_GRAD_SZIE &&col+i*x>0 && col+i*x<BOARD_GRAD_SZIE &&gameMapVec[row+i*y][col+i*x]==-1){ //AI的子botNum++;}else if(row+i*y>0 && row+i*y<BOARD_GRAD_SZIE &&col+i*x>0 && col+i*x<BOARD_GRAD_SZIE &&gameMapVec[row+i*y][col+i*x]==0){ //空白位emptyNum++;break;}else{ //出邊界break;}}for(int i=1;i<=4;i++){if(row-i*y>0 && row-i*y<BOARD_GRAD_SZIE &&col-i*x>0 && col-i*x<BOARD_GRAD_SZIE &&gameMapVec[row-i*y][col-i*x]==-1){ //AI的子botNum++;}else if(row-i*y>0 && row-i*y<BOARD_GRAD_SZIE &&col-i*x>0 && col-i*x<BOARD_GRAD_SZIE &&gameMapVec[row-i*y][col-i*x]==0){ //空白位emptyNum++;break;}else{ //出邊界break;}}if(botNum == 0){scoreMapVec[row][col]+=5;  //活1}else if(botNum == 1){scoreMapVec[row][col]+=10; //活2}else if(botNum == 2){         //活3if(emptyNum == 1)scoreMapVec[row][col]+=25;else if(emptyNum == 2)scoreMapVec[row][col]+=50;}else if(botNum == 3){         //活4if(emptyNum == 1)scoreMapVec[row][col]+=55;else if(emptyNum == 2)scoreMapVec[row][col]+=100;}else if(botNum >= 4){         //活5scoreMapVec[row][col]+=20000;}}}}}}}}
void GameModel::actionByAI(int &clickRow, int &clickCol)
{//計算評分calculateScore();//從評分中找出最大分數的位置int maxScore = 0;std::vector<std::pair<int,int>> maxPoints;for(int row = 1;row<BOARD_GRAD_SZIE;row++){for(int col = 1;col<BOARD_GRAD_SZIE;col++){//前提是這個坐標是空的if(gameMapVec[row][col] == 0){if(scoreMapVec[row][col]>maxScore){     //找最大數和坐標maxPoints.clear();maxScore = scoreMapVec[row][col];maxPoints.push_back(std::make_pair(row,col));}else if(scoreMapVec[row][col] == maxScore){   //如果有多個最大值就將他們存儲起來,在後面的代碼隨機抽1個maxPoints.push_back(std::make_pair(row,col));}}}}//隨機落子,如果有多個點的話srand((unsigned)time(0));int index = rand()%maxPoints.size();std::pair<int,int> pointPair = maxPoints.at(index);clickRow = pointPair.first;clickCol = pointPair.second;updateGameMap(clickRow,clickCol);}

更多推荐

五子棋大战

本文发布于:2023-06-28 00:33:51,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/919131.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:五子   大战

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!