//-----------------詹纪超-------------------------
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<string>
/*游戏参与者Player类*/
class Player{
protected:
int color;
std::string id; //id为参与者名称
public:
/*注:此处涉及C++虚函数机制*/
virtual Chess playChess(const int boardState[15][15]) = 0;
//获取玩家ID
std::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;//活4
int die4;//冲4
int lowdie4;//冲4低级版本
int alive3;//活3
int tiao3;//跳3
int die3;//眠3
int alive2;//活2
int lowalive2;//低级活2
int die2;//眠2
int 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活3
static const int levelC = 5000;//双活3
static const int levelD = 1000;//眠3高级活3
static const int levelE = 500;//冲四
static const int levelF = 400;//低级冲四
static const int levelG = 100;//单活3
static const int levelH = 90;//跳活3
static const int levelI = 50;//双活2
static const int levelJ = 10;//活2
static const int levelK = 9;//低级活2
static const int levelL = 5;//眠3
static const int levelM = 2;//眠2
static 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);
//@override
Chess 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;
else
current_player = 1;
return current_player;
}
};
8. Show.h
#pragma once
#include <string>
#include <iostream>
#include <cstdlib>
/*绘制棋盘状态及输出交互信息的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);//绘制函数
//@overload
void 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<string>
/*游戏引擎类*/
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<vector>
#include<iostream>
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}; //棋盘状态标志=棋子标志+1
int 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;
else
temp[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;
else
pe_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活3
if (alive3 >= 2)
return levelC;//双活3
if (situ.die3 >= 1 && situ.alive3 >= 1)
return levelD;//眠3,高级活3(即一定形成活4的活3)
if (situ.die4 >= 1)
return levelE;//高级冲4
if (situ.lowdie4 >= 1)
return levelF;//低级冲4
if (situ.alive3 >= 1)
return levelG;//单活3
if (situ.tiao3 >= 1)
return levelH;//跳活3
if (alive2 >= 2)
return levelI;//双活2
if (situ.alive2 >= 1)
return levelJ;//活2
if (situ.lowalive2 >= 1)
return levelK;//低级活2
if (situ.die3 >= 1)
return levelL;//眠3
if (situ.die2 >= 1)
return levelM;//眠2
return 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;
else
return 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 <iostream>
#include<windows.h>
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;
}
else
break;
}
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;
}
else
count = 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;
}
else
count = 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;
}
else
count = 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<iostream>
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<bits/stdc++.h>
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; //玩家2
while (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玩家2
else 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;
else
cout << "非法输入,请重新输入!" << 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; //合法
}
}
else
return 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;
else
end = 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;
}
颜亦心Qt版本程序下载](/codes/yanyexin.zip)
您的打赏是对我最大的鼓励!