用QT和C++程序实现五子棋游戏
五子棋游戏教程
五子棋游戏一
1. Chess.h
#pragma once //注:该行语句保证头文件只被编译一次 /*棋子类*/
class Chess{int color;int row;int column;public://初始化成员列表Chess(int color, int row, int col):color(color), row(row), column(col){}//获取棋子颜色int getColor(){return color;}//获取棋子位置void getPosition(int &row, int &col){row = this->row;col = this->column;}//设置棋子颜色void setColor(int color){this->color = color;}//设置棋子位置void setPosition(int row, int col){this->row = row;this->column = col;}
};2. Player.h
#pragma once #include"Chess.h" #include /*游戏参与者Player类*/
class Player{protected:int color;std::string id; //id为参与者名称public:/*注:此处涉及C++虚函数机制*/virtual Chess playChess(const int boardState[15][15]) = 0;//获取玩家IDstd::string getId(){return id;}
};3. PersonPlayer.h
#pragma once #include"Player.h" /*玩家类PersonPlayer,继承Player*/
class PersonPlayer :public Player{public:PersonPlayer(const int color, const std::string id);//给出下一步棋的位置Chess playChess(const int boardState[15][15]);
};4. Board.h
#pragma once #include "Chess.h" /*棋盘类*/
class Board{static const int ROW = 15; //行数,固定static const int COLUMN = 15;//列数,固定int boardState[ROW][COLUMN]; //棋盘状态矩阵int lastrow;//上一步位置的行int lastcol;//上一步位置的列public:Board(){lastcol = lastrow = 0;for (int i = 0;i < 15;i++)for (int j = 0;j < 15;j++)boardState[i][j] = 0;}//向棋盘添加棋子void addChess(Chess chess);//获取棋盘状态矩阵void getBoardState(int boardState[15][15]);
};5. AI.h
#pragma once /*五子棋AI的相关结构及类的头文件*/
//坐标
struct Position
{int x;int y;
};//棋局形势
struct Situation
{int win5;//5连,必胜int alive4;//活4int die4;//冲4int lowdie4;//冲4低级版本int alive3;//活3int tiao3;//跳3int die3;//眠3int alive2;//活2int lowalive2;//低级活2int die2;//眠2int safe;//对手安全位置,无法产生威胁,不需考虑
};/*注:以下各函数的依赖关系为: *getPosition()<-maxScore()<-getScore()<-judgeChessSituation()<-getType()<-judgeType()<-getChess() */
//AI类,核心功能类
class AI{private://棋盘位置的标志(黑子,白子或无子)static const int WHITE = 2;static const int BLACK = 1;static const int EMPTY = 0;//各棋局形势对应编号static const int WIN5 = 0;static const int ALIVE4 = 1;static const int DIE4 = 2;static const int LOWDIE4 = 3;static const int ALIVE3 = 4;static const int TIAO3 = 5;static const int DIE3 = 6;static const int ALIVE2 = 7;static const int LOWALIVE2 = 8;static const int DIE2 = 9;static const int SAFE = 10;//估值函数的分数评判标准static const int levelA = 999999;//成五static const int levelB = 10000;//成活4 或 双冲4 或 冲4活3static const int levelC = 5000;//双活3static const int levelD = 1000;//眠3高级活3static const int levelE = 500;//冲四static const int levelF = 400;//低级冲四static const int levelG = 100;//单活3static const int levelH = 90;//跳活3static const int levelI = 50;//双活2static const int levelJ = 10;//活2static const int levelK = 9;//低级活2static const int levelL = 5;//眠3static const int levelM = 2;//眠2static const int levelN = 1;//没有威胁static const int levelO = 0;//有子,不能下//获得当前方向的棋局数组chess,line表示方向线,包括横向,纵向,左上到右下,右上到左下等四个方向线void getChess(int chess[9], const int state[15][15], Position position, int color, int line);//判断当前方向的棋局形势,关键函数int judgeType(const int chess[9]);//综合四个方向判断棋局形势int judgeChessSituation(const int state[15][15], Position position, int color);//综合5个方向评判当前位置的棋局形势,根据形势,评判分值int getScore(Situation situation);//获得judgeSituation返回当前方向的棋局类型int getType(const int state[15][15], Position position, int color, int line);//依据分数判断最佳落子的位置Position maxScore(const int myscore[15][15], const int hisscore[15][15]);public://开放接口,获取最优落子位置Position getPosition(const int boardState[15][15], int color);
};6. AIplayer.h
#pragma once #include "Player.h" #include "AI.h" /*AI方,继承Player*/
class AIplayer :public Player{AI ai; //生成AI系统public:AIplayer(const int color, const std::string id);//@overrideChess playChess(const int boardState[15][15]);
};
7. Judge.h
#pragma once /*裁判类*/
class Judge{int current_player; //当前执棋者,0黑方,1白方public:Judge(){current_player = 1;}// 判断当前比赛结果,0还将继续,1黑胜,2白胜,3和棋(棋盘满了)int judgeResult(const int boardState[15][15]);//下一个执棋手int nextPlayer(){if(current_player)current_player = 0;elsecurrent_player = 1;return current_player;}
};8. Show.h
#pragma once #include #include #include /*绘制棋盘状态及输出交互信息的Show类*/
class Show{std::string COORDS; //标记棋盘位置的字母坐标std::string BOARD; //DOS字符绘制的棋盘public:Show(){COORDS = " A B C D E F G H I J K L M N O";BOARD = "┌┬┬┬┬┬┬┬┬┬┬┬┬┬┐""├┼┼┼┼┼┼┼┼┼┼┼┼┼┤""├┼┼┼┼┼┼┼┼┼┼┼┼┼┤""├┼┼┼┼┼┼┼┼┼┼┼┼┼┤""├┼┼┼┼┼┼┼┼┼┼┼┼┼┤""├┼┼┼┼┼┼┼┼┼┼┼┼┼┤""├┼┼┼┼┼┼┼┼┼┼┼┼┼┤""├┼┼┼┼┼┼┼┼┼┼┼┼┼┤""├┼┼┼┼┼┼┼┼┼┼┼┼┼┤""├┼┼┼┼┼┼┼┼┼┼┼┼┼┤""├┼┼┼┼┼┼┼┼┼┼┼┼┼┤""├┼┼┼┼┼┼┼┼┼┼┼┼┼┤""├┼┼┼┼┼┼┼┼┼┼┼┼┼┤""├┼┼┼┼┼┼┼┼┼┼┼┼┼┤""└┴┴┴┴┴┴┴┴┴┴┴┴┴┘";}void setVisualble(const int chesspadstate[15][15], const std::string msg);//绘制函数//@overloadvoid setVisualble(const std::string msg);//输出交互信息
};9. Game.h
#pragma once #include"Chess.h" #include"Board.h" #include"AIplayer.h" #include"PersonPlayer.h" #include"Judge.h" #include"Show.h" #include /*游戏引擎类*/
class Game{int pattern; //游戏模式,人人或人机int first_player; //先手std::string black_id, white_id; //玩家名称//生成棋盘,裁判,及展示类Show show;Board board;Judge judge;void getPattern(); //获取模式void getOrder(); //获取先手void getPlayerID(); //获取玩家名称public:Game(){pattern = -1;}void initGame(); //初始化游戏相关信息void startGame(); //启动游戏引擎void playGame(Player &black, Player &white, Judge &judge, Board &board, Show &show);
};(二) CPP文件
1. AI.cpp
#include"AI.h" #include #include
Position AI::getPosition(const int boardState[15][15], int color){int aiscore[15][15]{0}; //AI的分数int pescore[15][15]{0}; //玩家的分数int temp[15][15]{0}; //临时状态矩阵int ai_chess_color{color+1}; //棋盘状态标志=棋子标志+1int pe_chess_color;int flag{0};//判断是否刚开始下棋for(int i=0;i<15;i++){for(int j=0;j<15;j++){if(boardState[i][j]>0){flag = 1;break;}}if(flag)break;}if(!flag){Position pos = {7, 7}; //第一个棋默认置于中间return pos;}//还原最后一步的棋盘标志for (int i = 0;i < 15;i++) {for (int j = 0;j < 15;j++) {if (boardState[i][j]>2)temp[i][j] = boardState[i][j] - 2;elsetemp[i][j] = boardState[i][j];}}//估价for (int i = 0;i < 15;i++)for (int j = 0;j < 15;j++) {Position pos;int score;pos.x = i;pos.y = j;//我的分数score = judgeChessSituation(temp, pos, ai_chess_color);//返回当前形势分数aiscore[i][j] = score;if (ai_chess_color == BLACK)pe_chess_color = WHITE;elsepe_chess_color = BLACK;score = judgeChessSituation(temp, pos, pe_chess_color);//返回当前形势分数pescore[i][j] = score;}//根据分数,给出落子位置return maxScore(aiscore, pescore);
}int AI::judgeChessSituation(const int state[15][15], Position pos, int color){Situation situ{0};//记录当前位置形势的变量//非空位if(state[pos.x][pos.y])return levelO;for(int line = 0;line<4;line++){int type{getType(state, pos, color, line)};switch (type){case WIN5:situ.win5++;break;case ALIVE4:situ.alive4++;break;case DIE4:situ.die4++;break;case LOWDIE4:situ.lowdie4++;break;case ALIVE3:situ.alive3++;break;case TIAO3:situ.tiao3++;break;case DIE3:situ.die3++;break;case ALIVE2:situ.alive2++;break;case LOWALIVE2:situ.lowalive2++;break;case DIE2:situ.die2++;break;case SAFE:situ.safe++;break;default:std::cout<<"错误";break;}}return getScore(situ);
}int AI::getScore(Situation situ){int die4{situ.die4 + situ.lowdie4};int alive3{situ.alive3 + situ.tiao3};int alive2{situ.alive2 + situ.lowalive2};if (situ.win5 >= 1)return levelA;//五子成一线,必胜if (situ.alive4 >= 1 || die4 >= 2 || (die4 >= 1 && alive3 >= 1))return levelB;//活4,双冲4,冲4活3if (alive3 >= 2)return levelC;//双活3if (situ.die3 >= 1 && situ.alive3 >= 1)return levelD;//眠3,高级活3(即一定形成活4的活3)if (situ.die4 >= 1)return levelE;//高级冲4if (situ.lowdie4 >= 1)return levelF;//低级冲4if (situ.alive3 >= 1)return levelG;//单活3if (situ.tiao3 >= 1)return levelH;//跳活3if (alive2 >= 2)return levelI;//双活2if (situ.alive2 >= 1)return levelJ;//活2if (situ.lowalive2 >= 1)return levelK;//低级活2if (situ.die3 >= 1)return levelL;//眠3if (situ.die2 >= 1)return levelM;//眠2return levelN;//无威胁
}int AI::getType(const int state[15][15], Position pos, int color, int line){int type;int chess[9]{0};getChess(chess, state, pos, color, line);type = judgeType(chess);return type;
}void AI::getChess(int chess[9], const int state[15][15], Position pos, int color, int line){int pecolor;if(color == BLACK)pecolor = WHITE;else{pecolor = BLACK;}chess[4] = color;switch (line){case 0://横向for(int j=1;j<=4;j++){//往左探索四个位置的状态int col = pos.y-j;if(col<0){for(;j<=4;j++)chess[4-j] = pecolor;//出界的位置填充玩家的颜色break;}chess[4-j] = state[pos.x][col];}for(int j=1;j<=4;j++){//往右探索四个位置的状态int col = pos.y+j;if(col>14){for(;j<=4;j++)chess[4+j] = pecolor;break;}chess[4+j] = state[pos.x][col];}break;case 1: //纵向for(int j=1;j<=4;j++){//往上探索四个位置的状态int row = pos.x-j;if(row<0){for(;j<=4;j++)chess[4-j] = pecolor;break;}chess[4-j] = state[row][pos.y];}for(int j=1;j<=4;j++){//往下探索四个位置的状态int row = pos.x+j;if(row>14){for(;j<=4;j++)chess[4+j] = pecolor;break;}chess[4+j] = state[row][pos.y];}break;case 2://左上for (int i = 1, j = 1;i <= 4;i++,j++) {//往左上探索四个位置int row = pos.x - i;int column = pos.y - j;if (row < 0 || column <0) {//其中一个出边界for (;i <= 4;i++)chess[4 - i] = pecolor;//出界设置对手颜色break;}chess[4 - i] = state[row][column];//没出界,复制state数组}for (int i = 1, j = 1;i <= 4;i++, j++) {//往右下探索四个位置int row = pos.x + i;int column = pos.y + j;if (row > 14 || column > 14) {//其中一个出边界for (;i <= 4;i++)chess[4 + i] = pecolor;//出界设置对手颜色break;}chess[4 + i] = state[row][column];//没出界,复制state数组}break;case 3://右上for (int i = 1, j = 1;i <= 4;i++,j++) {//往左下探索四个位置int row = pos.x + i;int column = pos.y - j;if (row > 14 || column < 0) {//其中一个出边界for (;i <= 4;i++)chess[4 - i] = pecolor;//出界设置对手颜色break;}chess[4 - i] = state[row][column];//没出界,复制state数组}for (int i = 1, j = 1;i <= 4;i++, j++) {//往右上探索四个位置int row = pos.x - i;int column = pos.y + j;if (row < 0 || column > 14) {//其中一个出边界for (;i <= 4;i++)chess[4 + i] = pecolor;//出界设置对手颜色break;}chess[4 + i] = state[row][column];//没出界,复制state数组}break;default:break;}
}//AI核心算法,判断当前方向的棋局形势,作为打分依据
int AI::judgeType(const int chess[9]){int aicolor = chess[4];int pecolor{3-aicolor};int left_pos, right_pos;int left_color, right_color;int count{1};for(int i=1;i<=4;i++){if(chess[4-i] == aicolor)count++;else{left_pos = 4-i;left_color = chess[4-i];break;}}for (int i = 1;i <= 4;i++) {if (chess[4 + i] == aicolor)count++;//同色else {right_pos = 4 + i;//存储断开位置right_color = chess[4 + i];//存储断开颜色break;}}if(count == 5)//5连,必胜return WIN5;if(count == 4){//中心线4连if(left_color == EMPTY && right_color == EMPTY)return ALIVE4;else if(left_color == pecolor && right_color == pecolor)return SAFE;elsereturn DIE4;}if(count == 3){//中心线3连int left_color1 = chess[left_pos-1];int right_color1 = chess[right_pos+1];if(left_color == EMPTY && right_color == EMPTY){//两边断开位置均空if(left_color1 == pecolor && right_color1 == pecolor)return DIE3;else if(left_color1 == aicolor || right_color1 == aicolor)//均为AI方棋子return LOWDIE4;else if(left_color1 == EMPTY || right_color1 == EMPTY)//两边断开位置只有一个空return ALIVE3;}else if(left_color == pecolor && right_color == pecolor){//均为对手棋子return SAFE;}else{if(left_color == pecolor){//左边被对方堵住if(right_color1 == pecolor)//右边也被对方堵住return SAFE;if(right_color1 == EMPTY)//右边均空return DIE3;if(right_color1 == aicolor)return LOWDIE4;}if(right_color == pecolor){if(left_color1 == pecolor)return SAFE;if(left_color1 == EMPTY)return DIE3;if(left_color1 == aicolor)//左边还有AI的棋子return LOWDIE4;}}}if(count==2){//中心线2连int left_color1 = chess[left_pos - 1];int right_color1 = chess[right_pos + 1];int left_color2 = chess[left_pos - 2];int right_color2 = chess[right_pos + 2];if(left_color == EMPTY && right_color == EMPTY){if((right_color1 == EMPTY && right_color2 == aicolor)||(left_color1 == EMPTY && left_color2 == aicolor))return DIE3;else if(left_color1 == EMPTY && right_color1 == EMPTY)return ALIVE2;if((right_color1 == aicolor && right_color2 == pecolor)||(left_color1 == aicolor && left_color2 == pecolor))return DIE3;if((right_color1 == aicolor && right_color2 == aicolor)||(left_color1 == aicolor && left_color2 == aicolor))return LOWDIE4;if((right_color1 == aicolor && right_color2 == EMPTY)||(left_color1 == aicolor && left_color2 == EMPTY))return TIAO3;}else if(left_color == pecolor && right_color == pecolor)return SAFE;else{//两边断开位置只有一个空if(left_color == pecolor){//左边被对方堵住if(right_color1 == pecolor || right_color2 == pecolor)//只要有对方的一个棋子return SAFE;else if(right_color1 == EMPTY && right_color2 == EMPTY)//均空return DIE2;else if(right_color1 == aicolor && right_color2 == aicolor)return LOWDIE4;else if(right_color1 == aicolor || right_color2 == aicolor)//只有一个AI的棋子return DIE3;}if(right_color == pecolor){if(left_color1 == pecolor || left_color2 == pecolor)return SAFE;else if(left_color1 == EMPTY && left_color2 == EMPTY)return DIE2;else if(left_color1 == aicolor && left_color2 == aicolor)return LOWDIE4;else if(left_color1 == aicolor || left_color2 == aicolor)return DIE3;}}}if(count == 1){//孤子int left_color1 = chess[left_pos - 1];int right_color1 = chess[right_pos + 1];int left_color2 = chess[left_pos - 2];int right_color2 = chess[right_pos + 2];int left_color3 = chess[left_pos - 3];int right_color3 = chess[right_pos + 3];if(left_color == EMPTY && left_color1 == aicolor &&left_color2 == aicolor && left_color3 == aicolor)return LOWDIE4;if(right_color == EMPTY && right_color1 == aicolor &&right_color2 == aicolor && right_color3 == aicolor)return LOWDIE4;if (left_color == EMPTY && left_color1 == aicolor &&left_color2 == aicolor && left_color3 == EMPTY && right_color == EMPTY)return TIAO3;if (right_color == EMPTY && right_color1 == aicolor &&right_color2 == aicolor && right_color3 == EMPTY && left_color == EMPTY)return TIAO3;if (left_color == EMPTY && left_color1 == aicolor &&left_color2 == aicolor && left_color3 == pecolor && right_color == EMPTY)return DIE3;if (right_color == EMPTY && right_color1 == aicolor &&right_color2 == aicolor && right_color3 == pecolor && left_color == EMPTY)return DIE3;if (left_color == EMPTY && left_color1 == EMPTY &&left_color2 == aicolor && left_color3 == aicolor)return DIE3;if (right_color == EMPTY && right_color1 == EMPTY &&right_color2 == aicolor && right_color3 == aicolor)return DIE3;if (left_color == EMPTY && left_color1 == aicolor &&left_color2 == EMPTY && left_color3 == aicolor)return DIE3;if (right_color == EMPTY && right_color1 == aicolor &&right_color2 == EMPTY && right_color3 == aicolor)return DIE3;if (left_color == EMPTY && left_color1 == aicolor &&left_color2 == EMPTY && left_color3 == EMPTY && right_color == EMPTY)return LOWALIVE2;if (right_color == EMPTY && right_color1 == aicolor &&right_color2 == EMPTY && right_color3 == EMPTY && left_color == EMPTY)return LOWALIVE2;if (left_color == EMPTY && left_color1 == EMPTY &&left_color2 == aicolor && left_color3 == EMPTY && right_color == EMPTY)return LOWALIVE2;if (right_color == EMPTY && right_color1 == EMPTY &&right_color2 == aicolor && right_color3 == EMPTY && left_color == EMPTY)return LOWALIVE2;}return SAFE; //其他的情况意义不大,均返回无威胁形势
}Position AI::maxScore(const int aiscore[15][15], const int pescore[15][15]){Position pos{0, 0};int max_ai_score{0};int max_pe_score{0};std::vector<Position> ai_pos;//vector容器存储最大分数对应的位置std::vector<Position> pe_pos;//求出AI的最大值向量for(int i=0;i<15;i++)for(int j=0;j<15;j++){if(aiscore[i][j] == max_ai_score){pos.x = i;pos.y = j;ai_pos.push_back(pos);}if(aiscore[i][j]>max_ai_score){max_ai_score = aiscore[i][j];ai_pos.clear();pos.x = i;pos.y = j;ai_pos.push_back(pos);}}//求出玩家的最大值向量for(int i=0;i<15;i++)for(int j=0;j<15;j++){if(pescore[i][j] == max_pe_score){pos.x = i;pos.y = j;pe_pos.push_back(pos);}if(pescore[i][j]>max_pe_score){max_pe_score = pescore[i][j];pe_pos.clear();pos.x = i;pos.y = j;pe_pos.push_back(pos);}}//选择攻if(max_ai_score >= max_pe_score){int temp{0};//存储对手的最有利位置的分数std::vector<Position>::iterator iter;for(iter=ai_pos.begin();iter!=ai_pos.end();iter++){Position temp_pos = *iter;/*生成迭代器*/if(pescore[temp_pos.x][temp_pos.y] >= temp){temp = pescore[temp_pos.x][temp_pos.y];pos = temp_pos;}}return pos;//返回最终选择的落子位置}//选择守else{int temp{0};//存储AI的最有利位置的分数std::vector<Position>::iterator iter;for(iter=pe_pos.begin();iter!=pe_pos.end();iter++){Position temp_pos = *iter;if(aiscore[temp_pos.x][temp_pos.y] >= temp){temp = aiscore[temp_pos.x][temp_pos.y];pos = temp_pos;}}return pos;}
}2. AIplayer.cpp
#include"AIplayer.h" AIplayer::AIplayer(const int color, const std::string id){this->color = color;this->id = id;
}Chess AIplayer::playChess(const int boardState[15][15]){Position pos;pos = ai.getPosition(boardState, color);return Chess(color, pos.x, pos.y);
}3. PersonPlayer.cpp
#include "PersonPlayer.h" #include #include
PersonPlayer::PersonPlayer(const int color, const std::string id){this->color = color;this->id = id;
}Chess PersonPlayer::playChess(const int boardState[15][15]){int i, j;char a, b;while(true){std::cout << "请输入下步棋,如H行A列,则输入HA即可(大写):";std::cin.clear();/*注:该操作清空输入流*/std::cin.sync();std::cin >> a;std::cin >> b;if('A' > a || a > 'O' || 'A' > b || b > 'O'){std::cout<<"字符非法,请重新输入!\n";Sleep(1);continue;}i = a-'A';j = b-'A';if(boardState[i][j]){std::cout<<"该位置已经有棋子,请下别的位置\n";continue;}elsebreak;}return Chess(color, i, j);
}4. Judge.cpp
#include"Judge.h" int Judge::judgeResult(const int boardState[15][15]){int flag{0};int lastrow,lastcol;int result;for(int i=0;i<15;i++){for(int j=0;j<15;j++){if(!boardState[i][j]){flag = 1;break;}}if(flag)break;}if(!flag)return 3;//棋盘满,和局flag = 0;for (int i = 0;i < 15;i++) {//最后一步的坐标for (int j = 0;j < 15;j++)if (boardState[i][j]>2) {lastrow = i;lastcol = j;result = boardState[i][j] - 2;//返回当前旗手赢的标志flag = 1;break;}if (flag)break;}if (!flag)//还没开始下棋return 0;//横向int count{0};int mincol{lastcol-4 < 0 ? 0:lastcol - 4};int maxcol{lastcol + 4 > 14 ? 14 : lastcol + 4};for (int i = lastrow, j = mincol;j <= maxcol;j++) {if (boardState[i][j] == result || boardState[i][j] == result + 2) {//返回结果标志和棋标志相同count++;if (count == 5)//赢了return result;}else count = 0;//重头数起}//纵向count = 0;int minrow{lastrow - 4 < 0 ? 0 : lastrow - 4};int maxrow{lastrow + 4 > 14 ? 14 : lastrow + 4};for (int i = minrow, j = lastcol;i <= maxrow;i++) {if (boardState[i][j] == result || boardState[i][j] == result + 2) {//返回结果标志和棋标志相同count++;if (count == 5)//赢了return result;}elsecount = 0;//重头数起}//左上count = 0;minrow = lastrow - 4;mincol = lastcol - 4;if (minrow < 0 || mincol < 0) {//出界if (lastrow > lastcol) {//出界步数小先出界mincol = 0;//先出界的为边界值minrow = lastrow - lastcol;//后出界的根据斜率1}else {minrow = 0;mincol = lastcol - lastrow;}}maxrow = lastrow + 4;maxcol = lastcol + 4;if (maxrow > 14 || maxcol > 14) {//出界if (14 - lastrow < 14 - lastcol) {//出界步数小先出界maxrow = 14;//先出界的为边界值maxcol = lastcol + 14 - lastrow;}else {maxcol = 14;maxrow = lastrow + 14 - lastcol;}}for (int i = minrow, j = mincol;i <= maxrow;i++, j++) {if (boardState[i][j] == result || boardState[i][j] == result + 2) {//返回结果标志和棋标志相同count++;if (count == 5)//赢了return result;}elsecount = 0;//重头数起}//右上count = 0;minrow = lastrow - 4;maxcol = lastcol + 4;if (minrow < 0 || maxcol>14) {//出界if (lastrow - 0 < 14 - lastcol) {//出界步数小先出界minrow = 0;//先出界为边界值maxcol = lastcol + lastrow;}else {maxcol = 14;minrow = lastrow - (14 - lastcol);}}maxrow = lastrow + 4;mincol = lastcol - 4;if (maxrow > 14 || mincol < 0) {//出界if (14 - lastrow < lastcol - 0) {//出界步数小先出界maxrow = 14;mincol = lastcol - (14 - lastrow);}else {mincol = 0;maxrow = lastrow + lastcol - 0;}} for (int i = minrow, j = maxcol;i <= maxrow;i++, j--) {if (boardState[i][j] == result || boardState[i][j] == result + 2) {//返回结果标志和棋标志相同count++;if (count == 5)//赢了return result;}elsecount = 0;//重头数起}return 0;//还将继续
}5. Board.cpp
#include"Board.h" void Board::addChess(Chess chess){if (boardState[lastrow][lastcol])//有棋子boardState[lastrow][lastcol] -= 2;//不是最后一步了chess.getPosition(lastrow, lastcol);//重新设置最后一步记录if (chess.getColor())//白棋boardState[lastrow][lastcol] = 4;else//黑棋boardState[lastrow][lastcol] = 3;
}void Board::getBoardState(int boardState[15][15]){for(int i=0;i<15;i++)for(int j=0;j<15;j++)boardState[i][j] = this->boardState[i][j];
}6. Show.cpp
#include "Show.h" using namespace std;void Show::setVisualble(string msg){int initState[15][15]{0};setVisualble(initState, msg);
}void Show::setVisualble(const int boardState[15][15], const string msg){system("cls");//先清屏cout << COORDS << endl;//列号for (int row = 0;row < 15;row++) {//第row行cout << COORDS.at((row + 1) * 2 + 1) << " ";//行号for (int col = 0;col < 15;col++) {//第col列switch (boardState[row][col]) {case 0://空白cout << BOARD.at((row * 15 + col) * 2)<< BOARD.at((row * 15 + col) * 2 + 1);break;case 1://黑棋cout << "○";break;case 2://白旗cout << "●";break;case 3://黑棋(最后一步)cout << "▽";break;case 4://白棋(最后一步)cout << "▼";break;default:cout<<"错误";break;}}cout << endl;}cout << msg;
}7. Game.cpp
#include"Game.h" #include using namespace std;void Game::getPattern(){do {show.setVisualble("选择游戏模式0为人机对弈,1为人人对弈:");cin.clear();cin.sync();cin >> pattern;} while (2 <= pattern || pattern < 0);
}void Game::getOrder(){do {//选择顺序show.setVisualble("电脑先下请输入0,你先下请输入1:");cin.clear();cin.sync();cin >> first_player;} while (2 <= first_player || first_player < 0);
}void Game::getPlayerID(){if(pattern){show.setVisualble("请输入黑方棋手的名称(默认黑方先下):");cin.clear();cin.sync();getline(cin, black_id);show.setVisualble("请输入白方棋手的名称(默认黑方先下):");cin.clear();cin.sync();getline(cin, white_id);}else{getOrder();if(first_player){black_id = "你";white_id = "AI";}else{black_id = "AI";white_id = "你";}}
}void Game::initGame(){getPattern();getPlayerID();
}void Game::startGame(){if (pattern) {//人人模式//初始化选手PersonPlayer black(0, black_id);PersonPlayer white(1, white_id);//下棋playGame(black, white, judge, board, show);}else {//人机if (first_player) {//AI后下//初始化选手AIplayer white(1, "AI");PersonPlayer black(0, "你");//下棋playGame(black, white, judge, board, show);}else {//AI先下//初始化选手AIplayer black(0, "AI");PersonPlayer white(1, "你");//下棋playGame(black, white, judge, board, show);}}
}void Game::playGame(Player &black, Player &white, Judge &judge, Board &board, Show &show){int result;int state[15][15]{0};//下棋阶段while (!(result = judge.judgeResult(state))) {if (judge.nextPlayer()) {show.setVisualble(state, "白方:" + white.getId() + "\n");board.addChess(white.playChess(state));}else {show.setVisualble(state, "黑方:" + black.getId() + "\n");board.addChess(black.playChess(state));}board.getBoardState(state);}//显示结果switch (result) {case 1:show.setVisualble(state, "黑方:" + black.getId() + "胜\n请按e键退出");break;case 2:show.setVisualble(state, "白方:" + white.getId() + "胜\n请按e键退出");break;case 3:show.setVisualble(state, "本局结束,你们打平\n请按e键退出");break;default:cout<<"错误";break;}//退出char exit;do {cin.clear();cin.sync();cin >> exit;} while (exit != 'e' && exit != 'E');
}8. main.cpp
#include "Game.h" /*五子棋项目主函数*/
int main() {Game game;game.initGame();game.startGame();
}
五子棋游戏二
#include using namespace std;
vector<vector<int> > scoreMapVec; // 存储各个点位的评分情况,作为AI下棋依据
const int N = 15; //说明棋盘是15*15的
char ChessFlag = ' '; //棋盘上空位置的标志
char flag1 = 'O'; //玩家1或电脑的标志
char flag2 = 'X'; //玩家2的标志
struct point //下棋的坐标
{ int x; //行int y; //列
};class wuziqi //五子棋类
{
private:char ChessBoard[N + 2][N + 2]; //棋盘
public://初始化棋盘,即将所有位置都设置为ChessFlag wuziqi(){InitChessBoard(); }void run() //运行 { point Play1; //玩家1或电脑point Play2; //玩家2while (true){int mode = choise_mode();PrintChessBoard(); //打印棋盘while (true){ //0代表电脑,1代表玩家1,2代表玩家2 //玩家vs电脑 if (mode == 1){ Player_Play_Chess(Play2, 2, flag2); //轮到玩家2下棋 if (get_victory(Play2, 2, flag2)) //为真表示玩家2获胜 { break;}Computer_Play_Chess(Play1, flag1); //轮到电脑下棋 if (get_victory(Play1, 0, flag1)) //为真则表示电脑获胜{ break;}}//玩家1VS玩家2else if(mode == 2){ Player_Play_Chess(Play1, 1, flag1); //轮到玩家1下棋 if (get_victory(Play1, 1, flag1)) //为真表示玩家1赢{ break;}Player_Play_Chess(Play2, 2, flag2); //轮到玩家2下棋 if (get_victory(Play2, 2, flag2)) //为真表示玩家2赢{ break;}}}cout << "再来一局?" << endl;cout << "YES or NO :"; string s;cin >> s;if (s=="NO"){break;}}}void InitChessBoard() //初始化棋盘函数{ for (int i = 0; i < N + 1; ++i)for (int j = 0; j < N + 1; ++j)ChessBoard[i][j] = ChessFlag;}//选择游戏模式int choise_mode(){ InitChessBoard(); //初始化棋盘,即将所有位置均设为空位置 cout << "======================================================" << endl;cout << "** 0:退出 **" << endl;cout << "** 1:电脑 vs 玩家 **" << endl;cout << "** 2:玩家 vs 玩家 **" << endl;cout << "======================================================" << endl;while (1) //循环直到输入合法 { int i = 0;cout << "请选择游戏模式:";cin >> i;if (i == 0) //退出exit(1);if (i == 1 || i == 2) return i;elsecout << "非法输入,请重新输入!" << endl;}}void PrintChessBoard() //打印棋盘函数 { cout<<" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15"<<endl;cout<<" |---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|"<<endl;for(int i=0;i<=N+1;i++){ChessBoard[0][i] == ChessFlag;ChessBoard[N+1][i] == ChessFlag;ChessBoard[i][0] == ChessFlag;ChessBoard[i][N+1] == ChessFlag;}for (int i = 1; i < N + 1; ++i) //1~N才是真正的棋盘 {printf("%2d ", i);printf("| %c | %c | %c | %c | %c | %c | %c | %c | %c | %c | %c | %c | %c | %c | %c |\n", ChessBoard[i][1], ChessBoard[i][2], ChessBoard[i][3], ChessBoard[i][4], ChessBoard[i][5], ChessBoard[i][6], ChessBoard[i][7], ChessBoard[i][8], ChessBoard[i][9], ChessBoard[i][10], ChessBoard[i][11], ChessBoard[i][12], ChessBoard[i][13], ChessBoard[i][14], ChessBoard[i][15]);cout<<" |---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|"<<endl;}cout << endl;}void Computer_Play_Chess(point& pos, char flag) //电脑下棋
{ // 计算评分calculateScore();// 从评分中找出最大分数的位置int maxScore = 0;vector< pair<int, int> > maxPoints;for (int row = 1; row < N; row++)for (int col = 1; col < N; col++){// 前提是这个坐标是空的if (ChessBoard[row][col] == ' '){if (scoreMapVec[row][col] > maxScore) // 找最大的数和坐标{maxPoints.clear();maxScore = scoreMapVec[row][col];maxPoints.push_back(make_pair(row, col));}else if (scoreMapVec[row][col] == maxScore) // 如果有多个最大的数,都存起来maxPoints.push_back(make_pair(row, col));}}// 随机落子,如果有多个点的话srand((unsigned)time(0));int index = rand() % maxPoints.size();pair<int, int> pointPair = maxPoints.at(index);pos.x = pointPair.first; // 记录落子点pos.y = pointPair.second;ChessBoard[pos.x][pos.y] = flag;PrintChessBoard();printf("电脑下棋坐标为:%d,%d\n",pos.x,pos.y);
}void calculateScore()
{// 统计玩家或者电脑连成的子int personNum = 0; // 玩家连成子的个数int AINum = 0; // AI连成子的个数int emptyNum = 0; // 各方向空白位的个数// 清空评分数组scoreMapVec.clear();for (int i = 0; i < N; i++){vector<int> lineScores;for (int j = 0; j < N; j++)lineScores.push_back(0);scoreMapVec.push_back(lineScores);}// 计分(可以调整AI智能程度以及攻守风格)for (int row = 0; row < N; row++)for (int col = 0; col < N; col++){// 空白点才算if (row > 0 && col > 0 && ChessBoard[row][col] == ' '){// 遍历周围八个方向for (int y = -1; y <= 1; y++)for (int x = -1; x <= 1; x++){// 重置personNum = 0;AINum = 0;emptyNum = 0;// 原坐标不算if (!(y == 0 && x == 0)){// 每个方向延伸4个子// 对玩家'X'评分(正反两个方向)for (int i = 1; i <= 4; i++){if (row + i * y > 0 && row + i * y < N &&col + i * x > 0 && col + i * x < N &&ChessBoard[row + i * y][col + i * x] == 'X') // 玩家的子{personNum++;}else if (row + i * y > 0 && row + i * y < N &&col + i * x > 0 && col + i * x < N &&ChessBoard[row + i * y][col + i * x] == ' ') // 空白位{emptyNum++;break;}else // 出边界break;}for (int i = 1; i <= 4; i++){if (row - i * y > 0 && row - i * y < N &&col - i * x > 0 && col - i * x < N &&ChessBoard[row - i * y][col - i * x] == 'X') // 玩家的子{personNum++;}else if (row - i * y > 0 && row - i * y < N &&col - i * x > 0 && col - i * x < N &&ChessBoard[row - i * y][col - i * x] == ' ') // 空白位{emptyNum++;break;}else // 出边界break;}if (personNum == 1) scoreMapVec[row][col] += 10; //权重 else if (personNum == 2) {if (emptyNum == 1)scoreMapVec[row][col] += 30;else if (emptyNum == 2)scoreMapVec[row][col] += 50;}else if (personNum == 3) {// 量变空位不一样,优先级不一样if (emptyNum == 1)scoreMapVec[row][col] += 60;else if (emptyNum == 2)scoreMapVec[row][col] += 100;}else if (personNum == 4) scoreMapVec[row][col] += 10000;// 进行一次清空emptyNum = 0;// 对AI评分for (int i = 1; i <= 4; i++){if (row + i * y > 0 && row + i * y < N &&col + i * x > 0 && col + i * x < N &&ChessBoard[row + i * y][col + i * x] == 'O') // 玩家的子{AINum++;}else if (row + i * y > 0 && row + i * y < N &&col + i * x > 0 && col + i * x < N &&ChessBoard[row +i * y][col + i * x] == ' ') // 空白位{emptyNum++;break;}else // 出边界break;}for (int i = 1; i <= 4; i++){if (row - i * y > 0 && row - i * y < N &&col - i * x > 0 && col - i * x < N &&ChessBoard[row - i * y][col - i * x] == 'O') // AI的子{AINum++;}else if (row - i * y > 0 && row - i * y < N &&col - i * x > 0 && col - i * x < N &&ChessBoard[row - i * y][col - i * x] == ' ') // 空白位{emptyNum++;break;}else // 出边界break;}if (AINum == 0) scoreMapVec[row][col] += 5+5;else if (AINum == 1) scoreMapVec[row][col] += 10+5;else if (AINum == 2){if (emptyNum == 1) scoreMapVec[row][col] += 30+5;else if (emptyNum == 2)scoreMapVec[row][col] += 50+5; }else if (AINum == 3){if (emptyNum == 1) scoreMapVec[row][col] += 60+5;else if (emptyNum == 2)scoreMapVec[row][col] += 100+5; }else if (AINum >= 4)scoreMapVec[row][col] += 100000+5; }}}}
}void Player_Play_Chess(point& pos, int player, char flag){while (true){printf("请玩家%d输入坐标:", player);scanf("%d%d",&pos.x,&pos.y);if (judge_value(pos) == 1){ //判断坐标是否合法break;}cout << "坐标不合法,请重新输入:" << endl;}ChessBoard[pos.x][pos.y] = flag;PrintChessBoard(); //打印棋盘}int judge_value(const point pos){ //判断坐标的合法性//1.在棋盘上if (pos.x >= 1 && pos.x <= N && pos.y >= 1 && pos.y <= N){//2.所在位置为空(没有棋子)if (ChessBoard[pos.x][pos.y] == ChessFlag){return 1; //合法}}elsereturn 0; //非法}int judge_victory(point pos, char flag){ //判断是否有玩家获胜(底层判断)int len = 0; //相对长度int begin = 0; //横坐标起始位置 int end = 0; //纵坐标起始位置 int start = 0; //纵坐标起始位置 int finish = 0; //纵坐标结束位置 //1.判断行是否满足条件if(pos.y-4 >= 1) //后四个位置 begin = pos.y - 4;else begin = 1;if(pos.y + 4 > N) //前四个位置 end = N;elseend = pos.y + 4;for (int i = pos.x, j = begin; j + 4 <= end; ++j){if (ChessBoard[i][j] == flag && ChessBoard[i][j + 1] == flag &&ChessBoard[i][j + 2] == flag && ChessBoard[i][j + 3] == flag &&ChessBoard[i][j + 4] == flag)return 1;}//2.判断列是否满足条件(pos.x - 4) > 0 ? begin = (pos.x - 4) : begin = 1;(pos.x + 4) > N ? end = N : end = (pos.x + 4);for (int j = pos.y, i = begin ; i + 4 <= end; ++i){if (ChessBoard[i][j] == flag && ChessBoard[i + 1][j] == flag &&ChessBoard[i + 2][j] == flag && ChessBoard[i + 3][j] == flag &&ChessBoard[i + 4][j] == flag)return 1;}//3.判断主对角线是否满足条件pos.x > pos.y ? len = pos.y - 1 : len = pos.x - 1;if (len > 4){len = 4;}begin = pos.x - len; start = pos.y - len; pos.x > pos.y ? len = N - pos.x : len = N - pos.y;if (len > 4){len = 4;}end = pos.x + len; finish = pos.y + len; for (int i = begin, j = start; (i + 4 <= end) && (j + 4 <= finish); ++i, ++j){if (ChessBoard[i][j] == flag && ChessBoard[i + 1][j + 1] == flag &&ChessBoard[i + 2][j + 2] == flag && ChessBoard[i + 3][j + 3] == flag &&ChessBoard[i + 4][j + 4] == flag)return 1;}//4.判断副对角线是否满足条件(pos.x - 1) > (N - pos.y) ? len = N - pos.y : len = pos.x - 1;if (len > 4){len = 4;}begin = pos.x - len; start = pos.y + len; (N - pos.x) > (pos.y - 1) ? len = pos.y - 1 : len = N - pos.x;if (len > 4){len = 4;}end = pos.x + len; finish = pos.y - len; for (int i = begin, j = start; (i + 4 <= end) && (j - 4 >= finish); ++i, --j){if (ChessBoard[i][j] == flag && ChessBoard[i + 1][j - 1] == flag &&ChessBoard[i + 2][j - 2] == flag && ChessBoard[i + 3][j - 3] == flag &&ChessBoard[i + 4][j - 4] == flag)return 1;}//仍有位置还未下棋,说明游戏继续,还不能和局 for (int x = 1; x < N + 1; ++x){for (int y = 1; y < N + 1; ++y){if (ChessBoard[x][y] == ChessFlag){return 0; //未下棋}}}return -1; //所有位置均已下棋且仍未分出胜负,则和局}bool get_victory(point& pos, int player, char flag){ //判断具体哪位玩家赢if (judge_victory(pos, flag) != 0){ //判断有无人获胜if (judge_victory(pos, flag) == 1){ //判断是否有人获胜,1表示获胜PrintChessBoard(); //打印棋盘if (player == 0){cout << "电脑获胜!" << endl;}else{printf("恭喜玩家%d获胜!\n", player);}}else{printf("和局!\n");}return true; //有人获胜} return false; //没人获胜}
};int main(){wuziqi wzq;wzq.run();return 0;
}
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
