C语言实现AI五子棋算法


前言

该文章用于记录在人工智能算法学习中的学习经历,同时也将所遇到的问题与经验分享给大家以作参考。

具体思路与分析有 时间会一一分享。

详细介绍

棋盘、棋子、主菜单绘制

通过一些特殊的符号对于棋盘进行绘制:

//绘制棋盘
void draw_chessboardn(int row, int col, int chessboard[][MAX_COL]) {
	for (int i = 0; i < row; i++) {
		if (i == 0) {
			for (int j = 0; j < col; j++) {
				if (j == 0)
					draw_chessman(chessboard[i][j], "┌ ");
				else if (j == 14)
					draw_chessman(chessboard[i][j], "┐");
				else
					draw_chessman(chessboard[i][j], "┬ ");
			}
			printf("\n");
		}
		else if (i == 14) {
			for (int j = 0; j < col; j++) {
				if (j == 0)
					draw_chessman(chessboard[i][j], "└ ");
				else if (j == 14)
					draw_chessman(chessboard[i][j], "┘ ");
				else
					draw_chessman(chessboard[i][j], "┴ ");
			}
			printf("\n");
		}
		else {
			for (int j = 0; j < col; j++) {
				if (j == 0)
					draw_chessman(chessboard[i][j], "├ ");
				else if (j == 14)
					draw_chessman(chessboard[i][j], "┤");
				else
					draw_chessman(chessboard[i][j], "┼ ");
			}
			printf("\n");
		}
	}
}
//绘制棋子
void draw_chessman(int type, const char* tableline) {
	if (type == WHITE)
		printf("●");
	if (type == BLACK)
		printf("○");
	if (type == BLANK)
		printf("%s", tableline);
}
//绘制主菜单
void draw_menu(void) {
	printf("******************************\n");
	printf("******* 欢迎使用五子棋 *******\n");
	printf("***     研发者:666        ***\n");
	printf("***     请选择对战方式     ***\n");
	printf("*      1.人-人对战           *\n");
	printf("*      2.人-机对战           *\n");
	printf("*      3.退出                *\n");
	printf("******************************\n");
	printf("请选择:");
}

胜负判断

五子棋正常来说是不会将棋盘所占满的,但是不排除这种极端情况,故小写了一个判断棋盘是否满的函数:

//判断棋盘是否已满
int is_full(int chessboard[][MAX_COL], int row, int col) {
	int ret = 1;
	for (int i = 0; i < row; i++) {
		for (int j = 0; j < col; j++) {
			if (chessboard[i][j] == BLANK) {        //遍历数组,当有一个位置为空,则棋盘不满
				ret = 0;
				break;
			}
		}
	}
	return ret;
}

之后是通过遍历棋盘来判断是否有五子连珠的情况,此处的返回值是棋子的颜色,也就是1,-1或者0。

//判断胜负
int is_win(int chessboard[][MAX_COL], int row, int col) {
	int i, j;
	for (i = 0; i < row; i++) {
		for (j = 0; j < col; j++) {
			if (chessboard[i][j] == BLANK)
				continue;
			if (j < col - 4)
				if (chessboard[i][j] == chessboard[i][j + 1] && chessboard[i][j] == chessboard[i][j + 2]
					&& chessboard[i][j] == chessboard[i][j + 3] && chessboard[i][j] == chessboard[i][j + 4])
					return chessboard[i][j];
			if (i < row - 4)
				if (chessboard[i][j] == chessboard[i + 1][j] && chessboard[i][j] == chessboard[i + 2][j]
					&& chessboard[i][j] == chessboard[i + 3][j] && chessboard[i][j] == chessboard[i + 4][j])
					return chessboard[i][j];
			if (i < row - 4 && j < col - 4)
				if (chessboard[i][j] == chessboard[i + 1][j + 1] && chessboard[i][j] == chessboard[i + 2][j + 2]
					&& chessboard[i][j] == chessboard[i + 3][j + 3] && chessboard[i][j] == chessboard[i + 4][j + 4])
					return chessboard[i][j];
			if (i < row - 4 && j > 4)
				if (chessboard[i][j] == chessboard[i + 1][j - 1] && chessboard[i][j] == chessboard[i + 2][j - 2]
					&& chessboard[i][j] == chessboard[i + 3][j - 3] && chessboard[i][j] == chessboard[i + 4][j - 4])
					return chessboard[i][j];
		}
	}
	return BLANK;
}

人人对战

void person_person(void) {
	int chessboard[MAX_ROW][MAX_COL] = { BLANK };
	int chessboard_c[MAX_ROW][MAX_COL] = { BLANK };
	int i, j;
	int ij[10][4] = { 0 };
	char key;
	draw_chessboardn(MAX_ROW, MAX_COL, chessboard);
	for (int step = 1; step <= MAX_ROW * MAX_COL; step++) {    //黑子先行,然后双方轮流下棋
		if (step % 2 == 1) {                                   //当前步数为单数,黑棋落子。
			printf("请黑棋落子:");
			while (1) {
				scanf("%d %d", &i, &j);
				if (chessboard[i][j] != BLANK) {
					printf("该位置已有棋子,请重新输入\n");        //棋子只能落在空白处
					continue;
				}
				if (i >= MAX_ROW || j >= MAX_COL || i < 0 || j < 0) {
					printf("输入超出棋盘范围,请重新输入\n");      //棋子坐标不可超出棋盘
					continue;
				}
				break;
			}
			chessboard[i][j] = BLACK;
			printf("%d %d\n", ij[0][0], ij[0][1]);
			draw_chessboardn(MAX_ROW, MAX_COL, chessboard);
			if (is_win(chessboard, MAX_ROW, MAX_COL) == BLACK) {
				printf("黑棋胜");
				exit(0);
			}
			//save_chess(chessboard, MAX_ROW, MAX_COL);
		}
		else if (step % 2 == 0) {                            //当前步数为双数,则白棋落子
			printf("请白棋落子:");
			while (1) {
				scanf("%d %d", &i, &j);
				if (chessboard[i][j] != BLANK) {
					printf("该位置已有棋子,请重新输入\n");        //棋子只能落在空白处
					continue;
				}
				if (i >= MAX_ROW || j >= MAX_COL || i < 0 || j < 0) {
					printf("输入超出棋盘范围,请重新输入\n");     //棋子坐标不可超出棋盘
					continue;
				}
				break;
			}
			chessboard[i][j] = WHITE;
			printf("%d %d\n", ij[0][0], ij[0][1]);
			draw_chessboardn(MAX_ROW, MAX_COL, chessboard);
			if (is_win(chessboard, MAX_ROW, MAX_COL) == WHITE) {
				printf("白棋胜");
				exit(0);
			}
		}
	}
	if (is_full(chessboard, MAX_ROW, MAX_COL) == 1)
		printf("棋盘已满");
}

人机对战

在人机对战模块,这里设置的紧紧是人为先手后,机器后手计算最优解,再进行对弈。在函数传参的过程中,利用两个数组,通过复制函数chessboard_copy()来进行后续多层深度的计算,从而不影响原本棋盘状态:

//棋盘复制
void chessboard_copy(int chessboard_c[][MAX_COL],int chessboard[][MAX_COL])
{	
	//复制棋盘,用于试下,不破坏原有棋盘
	for (int i = 0; i < MAX_ROW; i++) {
		for (int j = 0; j < MAX_COL; j++) {
			chessboard_c[i][j] = chessboard[i][j];
		}
	}
}

在传递坐标过程中,用一个数组ij[]来存储当前最优坐标进行传递参数。具体的函数操作如下:

void person_computer_random(void) {
	int chessboard[MAX_ROW][MAX_COL] = { BLANK };
	int chessboard_c[MAX_ROW][MAX_COL] = { BLANK };
	int i, j;
	int ij[4] = { 0 }; //用于传递生成的坐标值
	draw_chessboardn(MAX_ROW, MAX_COL, chessboard);
	for (int step = 1; step <= MAX_ROW * MAX_COL; step++) {
		if (step % 2 == 1) {
			printf("请黑棋落子:");
			while (1) {
				scanf("%d %d", &i, &j);
				if (chessboard[i][j] != BLANK) {
					printf("该位置已有棋子,请重新输入\n");
					continue;
				}
				if (i >= MAX_ROW || j >= MAX_COL || i < 0 || j < 0) {
					printf("输入超出棋盘范围,请重新输入\n");
					continue;
				}
				break;
			}
			chessboard[i][j] = BLACK;
			draw_chessboardn(MAX_ROW, MAX_COL, chessboard);
			if (is_win(chessboard, MAX_ROW, MAX_COL) == BLACK) {
				printf("黑棋胜");
				exit(0);
			}
		}
		else if (step % 2 == 0) {
			deep_search(ij, chessboard,WHITE, 0, i, j);
			printf(" 白棋落子(%d %d)\n", ij[0], ij[1]);
			chessboard[ij[0]][ij[1]] = WHITE;
			draw_chessboardn(MAX_ROW, MAX_COL, chessboard);
			if (is_win(chessboard, MAX_ROW, MAX_COL) == WHITE) {
				printf("白棋胜");
				exit(0);
			}
		}
	}
	if (is_full(chessboard, MAX_ROW, MAX_COL) == 1)
		printf("棋盘已满");
}

评分判断

我们在编写AI对弈相关程序的同时,我们要清楚如何告诉机器,每个点的价值,此处我们通过五子棋的特点,通过活二、活三等棋型,通过棋盘上每个空点位能够实现几种棋型,以及每种棋型相应的得分相加,得到每个点位的评分机制。这段代码是编写AI的基础,具体代码如下:

//评分计算各个点的价值
void calculateScore(int chessboard[][MAX_COL])
{
	int personNum = 0; //玩家方(黑棋)多少个连续的棋子
	int aiNum = 0; //系统方(白棋)连续有多少个连续的棋子
	int emptyNum = 0; // 该方向上空白位的个数

	// 评分数组清零
	pfclear();

	for (int row = 0; row < 15; row++) {
		for (int col = 0; col < 15; col++) {
			//对每个点进行计算
			if (chessboard[row][col]) { continue; } //避开已经下过的点 -1、1都是true

			//控制方向 一共4个正方向:y不变 x+、y- x-、y- x不变、y- x+
			for (int y = -1; y <= 0; y++) {        //Y的范围是-1,0
				for (int x = -1; x <= 1; x++) {    //X的范围是 -1,0,1
					if (y == 0 && x == 0) { continue; }
					if (y == 0 && x != 1) { continue; } //当y=0时,仅允许x=1

					personNum = 0;
					aiNum = 0;
					emptyNum = 0;

					// 假设黑棋在该位置落子,会构成什么棋型
					for (int i = 1; i <= 4; i++) {
						int curRow = row + i * y;
						int curCol = col + i * x;

						if (curRow >= 0 && curRow < 15 &&
							curCol >= 0 && curCol < 15 &&
							chessboard[curRow][curCol] == 1) {
							personNum++;
						}
						else if (curRow >= 0 && curRow < 15 &&
							curCol >= 0 && curCol < 15 &&
							chessboard[curRow][curCol] == 0) {
							emptyNum++;
							break;
						}
						else {
							break;
						}
					}

					// 反向继续计算
					for (int i = 1; i <= 4; i++) {
						int curRow = row - i * y;
						int curCol = col - i * x;

						if (curRow >= 0 && curRow < 15 &&
							curCol >= 0 && curCol < 15 &&
							chessboard[curRow][curCol] == 1) {
							personNum++;
						}
						else if (curRow >= 0 && curRow < 15 &&
							curCol >= 0 && curCol < 15 &&
							chessboard[curRow][curCol] == 0) {
							emptyNum++;
							break;
						}
						else {
							break;
						}
					}

					if (personNum == 1) { //连2
						pf[row][col] += 10;
					}
					else if (personNum == 2) {
						if (emptyNum == 1) { //死3
							pf[row][col] += 30;
						}
						else if (emptyNum == 2) { //活3
							pf[row][col] += 40;
						}
					}
					else if (personNum == 3) {
						if (emptyNum == 1) { //死4
							pf[row][col] = 60;
						}
						else if (emptyNum == 2) { //活4
							pf[row][col] = 5000;
						}
					}
					else if (personNum == 4) { //连5
						pf[row][col] = 20000;
					}

					// 假设白棋在该位置落子,会构成什么棋型
					emptyNum = 0;

					for (int i = 1; i <= 4; i++) {
						int curRow = row + i * y;
						int curCol = col + i * x;

						if (curRow >= 0 && curRow < 15 &&
							curCol >= 0 && curCol < 15 &&
							chessboard[curRow][curCol] == -1) {
							aiNum++;
						}
						else if (curRow >= 0 && curRow < 15 &&
							curCol >= 0 && curCol < 15 &&
							chessboard[curRow][curCol] == 0) {
							emptyNum++;
							break;
						}
						else {
							break;
						}
					}

					for (int i = 1; i <= 4; i++) {
						int curRow = row - i * y;
						int curCol = col - i * x;

						if (curRow >= 0 && curRow < 15 &&
							curCol >= 0 && curCol < 15 &&
							chessboard[curRow][curCol] == -1) {
							aiNum++;
						}
						else if (curRow >= 0 && curRow < 15 &&
							curCol >= 0 && curCol < 15 &&
							chessboard[curRow][curCol] == 0) {
							emptyNum++;
							break;
						}
						else {
							break;
						}
					}

					if (aiNum == 0) {
						pf[row][col] += 5;
					}
					else if (aiNum == 1) { //连2
						pf[row][col] += 10;
					}
					else if (aiNum == 2) {
						if (emptyNum == 1) { //死3
							pf[row][col] += 25;
						}
						else if (emptyNum == 2) { //活3
							pf[row][col] += 50;
						}
					}
					else if (aiNum == 3) {
						if (emptyNum == 1) { //死4
							pf[row][col] += 55;
						}
						else if (emptyNum == 2) { //活4
							pf[row][col] += 10000;
						}
					}
					else if (aiNum >= 4) { //连5
						pf[row][col] += 30000;
					}
				}
			}
		}
	}
}


总体代码

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAX_ROW 15  //行
#define MAX_COL 15  //列
#define WHITE -1
#define BLACK 1
#define BLANK 0
 
struct Chess_b_score
{
	int  score;//当前位置的得分
	int	 i, j;//上一级棋子位置
	int  best[32][3];//用于存放同一状态下评分相同且最优的各个点
	int	 s_list[MAX_ROW][MAX_COL];//当前棋盘下各个点得分值
	struct Chess_b_score* c[MAX_ROW][MAX_COL];//下一等级搜索的指针 
};
 
 
void draw_chessboardn(int row, int col, int chessboard[][MAX_COL]);
void draw_chessman(int type, const char* tableline);
int random_create_point(void);
void draw_menu(void);
void person_person(void);
void person_computer_random(void);
int is_full(int chessboard[][MAX_COL], int row, int col);
int is_win(int chessboard[][MAX_COL], int row, int col);
void chessboard_copy(int chessboard_c[][MAX_COL], int chessboard[][MAX_COL]);
void pfclear();
void deep_search(int ij[4], int chessboard[][MAX_COL],int BOW, int n, int row, int col);
int deep666(Chess_b_score* chess,int chessboard[][MAX_COL],int row,int col,int BOW);
void calculateScore(int chessboard[][MAX_COL]);
 
int pf[MAX_ROW][MAX_COL] = {};//全局变量的二维数组,用于存储各点位价值
 
 
int main() {
	int choice;
	draw_menu();
	while (1) {
		scanf("%d", &choice);
		switch (choice) {
		case 1:
			person_person();
			break;
		case 2:
			person_computer_random();
			break;
		case 3:
			exit(0);
			break;
		default:
			printf("输入错误,请重新选择\n");
		}
	}
	return 0;
}
//绘制棋盘
void draw_chessboardn(int row, int col, int chessboard[][MAX_COL]) {
	for (int i = 0; i < row; i++) {
		if (i == 0) {
			for (int j = 0; j < col; j++) {
				if (j == 0)
					draw_chessman(chessboard[i][j], "┌ ");
				else if (j == 14)
					draw_chessman(chessboard[i][j], "┐");
				else
					draw_chessman(chessboard[i][j], "┬ ");
			}
			printf("\n");
		}
		else if (i == 14) {
			for (int j = 0; j < col; j++) {
				if (j == 0)
					draw_chessman(chessboard[i][j], "└ ");
				else if (j == 14)
					draw_chessman(chessboard[i][j], "┘ ");
				else
					draw_chessman(chessboard[i][j], "┴ ");
			}
			printf("\n");
		}
		else {
			for (int j = 0; j < col; j++) {
				if (j == 0)
					draw_chessman(chessboard[i][j], "├ ");
				else if (j == 14)
					draw_chessman(chessboard[i][j], "┤");
				else
					draw_chessman(chessboard[i][j], "┼ ");
			}
			printf("\n");
		}
	}
}
//绘制棋子
void draw_chessman(int type, const char* tableline) {
	if (type == WHITE)
		printf("●");
	if (type == BLACK)
		printf("○");
	if (type == BLANK)
		printf("%s", tableline);
}
//随机算法获取棋子的坐标
int random_create_point(void) {
	int point; 
	srand((unsigned)time(NULL));
	//point = rand() % MAX_ROW;
	point = rand() % 15;
	if (point <4)return -1;
	if (point >= 5 && point <= 9)return 0;
	if (point >= 10 && point <= 15)return 1;
	//printf("%d", point);
}
//绘制主菜单
void draw_menu(void) {
	printf("******************************\n");
	printf("******* 欢迎使用五子棋 *******\n");
	printf("***     研发者:666        ***\n");
	printf("***     请选择对战方式     ***\n");
	printf("*      1.人-人对战           *\n");
	printf("*      2.人-机对战           *\n");
	printf("*      3.退出                *\n");
	printf("******************************\n");
	printf("请选择:");
}
//人人对战
void person_person(void) {
	int chessboard[MAX_ROW][MAX_COL] = { BLANK };
	int chessboard_c[MAX_ROW][MAX_COL] = { BLANK };
	int i, j;
	int ij[10][4] = { 0 };
	char key;
	draw_chessboardn(MAX_ROW, MAX_COL, chessboard);
	for (int step = 1; step <= MAX_ROW * MAX_COL; step++) {    //黑子先行,然后双方轮流下棋
		if (step % 2 == 1) {                                   //当前步数为单数,黑棋落子。
			printf("请黑棋落子:");
			while (1) {
				scanf("%d %d", &i, &j);
				if (chessboard[i][j] != BLANK) {
					printf("该位置已有棋子,请重新输入\n");        //棋子只能落在空白处
					continue;
				}
				if (i >= MAX_ROW || j >= MAX_COL || i < 0 || j < 0) {
					printf("输入超出棋盘范围,请重新输入\n");      //棋子坐标不可超出棋盘
					continue;
				}
				break;
			}
			chessboard[i][j] = BLACK;
			printf("%d %d\n", ij[0][0], ij[0][1]);
			draw_chessboardn(MAX_ROW, MAX_COL, chessboard);
			if (is_win(chessboard, MAX_ROW, MAX_COL) == BLACK) {
				printf("黑棋胜");
				exit(0);
			}
			//save_chess(chessboard, MAX_ROW, MAX_COL);
		}
		else if (step % 2 == 0) {                            //当前步数为双数,则白棋落子
			printf("请白棋落子:");
			while (1) {
				scanf("%d %d", &i, &j);
				if (chessboard[i][j] != BLANK) {
					printf("该位置已有棋子,请重新输入\n");        //棋子只能落在空白处
					continue;
				}
				if (i >= MAX_ROW || j >= MAX_COL || i < 0 || j < 0) {
					printf("输入超出棋盘范围,请重新输入\n");     //棋子坐标不可超出棋盘
					continue;
				}
				break;
			}
			chessboard[i][j] = WHITE;
			printf("%d %d\n", ij[0][0], ij[0][1]);
			draw_chessboardn(MAX_ROW, MAX_COL, chessboard);
			if (is_win(chessboard, MAX_ROW, MAX_COL) == WHITE) {
				printf("白棋胜");
				exit(0);
			}
			//save_chess(chessboard, MAX_ROW, MAX_COL);
		}
	}
	if (is_full(chessboard, MAX_ROW, MAX_COL) == 1)
		printf("棋盘已满");
}
//判断棋盘是否已满
int is_full(int chessboard[][MAX_COL], int row, int col) {
	int ret = 1;
	for (int i = 0; i < row; i++) {
		for (int j = 0; j < col; j++) {
			if (chessboard[i][j] == BLANK) {        //遍历数组,当有一个位置为空,则棋盘不满
				ret = 0;
				break;
			}
		}
	}
	return ret;
}
//判断胜负
int is_win(int chessboard[][MAX_COL], int row, int col) {
	int i, j;
	for (i = 0; i < row; i++) {
		for (j = 0; j < col; j++) {
			if (chessboard[i][j] == BLANK)
				continue;
			if (j < col - 4)
				if (chessboard[i][j] == chessboard[i][j + 1] && chessboard[i][j] == chessboard[i][j + 2]
					&& chessboard[i][j] == chessboard[i][j + 3] && chessboard[i][j] == chessboard[i][j + 4])
					return chessboard[i][j];
			if (i < row - 4)
				if (chessboard[i][j] == chessboard[i + 1][j] && chessboard[i][j] == chessboard[i + 2][j]
					&& chessboard[i][j] == chessboard[i + 3][j] && chessboard[i][j] == chessboard[i + 4][j])
					return chessboard[i][j];
			if (i < row - 4 && j < col - 4)
				if (chessboard[i][j] == chessboard[i + 1][j + 1] && chessboard[i][j] == chessboard[i + 2][j + 2]
					&& chessboard[i][j] == chessboard[i + 3][j + 3] && chessboard[i][j] == chessboard[i + 4][j + 4])
					return chessboard[i][j];
			if (i < row - 4 && j > 4)
				if (chessboard[i][j] == chessboard[i + 1][j - 1] && chessboard[i][j] == chessboard[i + 2][j - 2]
					&& chessboard[i][j] == chessboard[i + 3][j - 3] && chessboard[i][j] == chessboard[i + 4][j - 4])
					return chessboard[i][j];
		}
	}
	return BLANK;
}
//人机对战
void person_computer_random(void) {
	int chessboard[MAX_ROW][MAX_COL] = { BLANK };
	int chessboard_c[MAX_ROW][MAX_COL] = { BLANK };
	int i, j;
	int ij[4] = { 0 }; //用于传递生成的坐标值
	draw_chessboardn(MAX_ROW, MAX_COL, chessboard);
	for (int step = 1; step <= MAX_ROW * MAX_COL; step++) {
		if (step % 2 == 1) {
			printf("请黑棋落子:");
			while (1) {
				scanf("%d %d", &i, &j);
				if (chessboard[i][j] != BLANK) {
					printf("该位置已有棋子,请重新输入\n");
					continue;
				}
				if (i >= MAX_ROW || j >= MAX_COL || i < 0 || j < 0) {
					printf("输入超出棋盘范围,请重新输入\n");
					continue;
				}
				break;
			}
			chessboard[i][j] = BLACK;
			draw_chessboardn(MAX_ROW, MAX_COL, chessboard);
			if (is_win(chessboard, MAX_ROW, MAX_COL) == BLACK) {
				printf("黑棋胜");
				exit(0);
			}
		}
		else if (step % 2 == 0) {
			deep_search(ij, chessboard,WHITE, 0, i, j);
			printf(" 白棋落子(%d %d)\n", ij[0], ij[1]);
			chessboard[ij[0]][ij[1]] = WHITE;
			draw_chessboardn(MAX_ROW, MAX_COL, chessboard);
			if (is_win(chessboard, MAX_ROW, MAX_COL) == WHITE) {
				printf("白棋胜");
				exit(0);
			}
		}
	}
	if (is_full(chessboard, MAX_ROW, MAX_COL) == 1)
		printf("棋盘已满");
}
//棋盘复制
void chessboard_copy(int chessboard_c[][MAX_COL],int chessboard[][MAX_COL])
{	
	//复制棋盘,用于试下,不破坏原有棋盘
	for (int i = 0; i < MAX_ROW; i++) {
		for (int j = 0; j < MAX_COL; j++) {
			chessboard_c[i][j] = chessboard[i][j];
		}
	}
}
//全局变量价值表初始化
void pfclear()
{
	for (int i = 0; i < MAX_ROW; i++) {
		for (int j = 0; j < MAX_COL; j++) {
			pf[i][j] = 0;
		}
	}
}
//全局搜索
void deep_search(int ij[4],int chessboard[][MAX_COL],int BOW,int n,int row,int col)
{
	Chess_b_score *chess0;
	int score_max=0, score=0,score_min=10000000,score_2=0;
	int m=0;
	int chessboard_c[MAX_ROW][MAX_COL] = { BLANK };
	chess0 = (struct Chess_b_score*)malloc(sizeof(struct Chess_b_score));
	chessboard_copy(chessboard_c, chessboard);
	calculateScore(chessboard_c);
	//由上一步为中心向四周发散搜素
	for (int i = row; i < MAX_ROW; i++) {
		for (int j = col; j < MAX_COL; j++) {
			if (chessboard_c[i][j] == BLANK)
			{
				score = pf[i][j];
				chess0->s_list[i][j] = score;
				if (score > score_max) {
					score_max = score;
				}
			}
			else {
				chess0->s_list[i][j] =chessboard_c[i][j];
			}
		}
	}  //右上
	for (int i = row; i < MAX_ROW; i++) {
		for (int j = col; j >= 0; j--) {
			if (chessboard_c[i][j] == BLANK)
			{
				score = pf[i][j];
				chess0->s_list[i][j] = score;
				if (score > score_max) {
					score_max = score;
				}
			}
			else {
				chess0->s_list[i][j] = chessboard_c[i][j];;
			}
		}
	}
	for (int i = row; i >= 0; i--) {
		for (int j = col; j >= 0; j--) {
			if (chessboard_c[i][j] == BLANK)
			{
				score = pf[i][j];
				chess0->s_list[i][j] = score;
				if (score > score_max) {
					score_max = score;
				}
			}
			else {
				chess0->s_list[i][j] = chessboard_c[i][j];;
			}
		}
	}
	for (int i = row; i >= 0; i--) {
		for (int j = col; j < MAX_COL; j++) {
			if (chessboard_c[i][j] == BLANK)
			{
				score = pf[i][j];
				chess0->s_list[i][j] = score;
				if (score > score_max) {
					score_max = score;
				}
			}
			else {
				chess0->s_list[i][j] = chessboard_c[i][j];
			}
		}
	}
	printf("\n");
	//将搜索评价表的最大值放入到该棋盘结构体中的best数组中,用于后面的深层搜索
	for (int i = 0; i < MAX_ROW; i++) {
		for (int j = 0; j < MAX_COL; j++) {
			if (pf[i][j] == score_max) {
				chess0->best[m][0] = i;
				chess0->best[m][1] = j;
				chess0->best[m][2] = score_max;
				m++;
			}
		}
	}
	m--;
	//判断二层搜索结果,将第一层相等的点位对第二层进行搜索,然后取第二层的min值。
	while (m!=-1) {
		score_2=deep666(chess0,chessboard_c,chess0->best[m][0], chess0->best[m][1],WHITE);
		if (score_2 < score_min) {
			score_min = score_2;
			chess0->i = chess0->best[m][0];
			chess0->j = chess0->best[m][1];
		}
		m--;
	}
	ij[0] = chess0->i;
	ij[1] = chess0->j;
}
//二层搜索
int deep666(Chess_b_score* chess,int chessboard[][MAX_COL],int row,int col,int BOW)
{
	int m = 0;
	Chess_b_score* p;
	int chessboard_c[MAX_ROW][MAX_COL] = { BLANK };
	p= (struct Chess_b_score*)malloc(sizeof(struct Chess_b_score));
	chess->c[row][col]= (struct Chess_b_score*)malloc(sizeof(struct Chess_b_score));
	chessboard_copy(chessboard_c, chessboard);
	chessboard_c[row][col] = BOW;
	calculateScore(chessboard_c);
	p = chess->c[row][col];
	chess->c[row][col]->score = 0;
	for (int i = 0; i < MAX_ROW; i++) {
		for (int j = 0; j < MAX_COL; j++) {
			p->s_list[i][j] = pf[i][j];
			if (pf[i][j] > p->score) {
				p->score = pf[i][j];
			}
		}
	}
	for (int i = 0; i < MAX_ROW; i++) {
		for (int j = 0; j < MAX_COL; j++) {
			if (pf[i][j] == p->score) {
				p->best[m][0] = i;
				p->best[m][1] = j;
				p->best[m][2] = p->score;
				m++;
			}
		}
	}
	return p->score;
}
//评分计算各个点的价值
void calculateScore(int chessboard[][MAX_COL])
{
	int personNum = 0; //玩家方(黑棋)多少个连续的棋子
	int aiNum = 0; //系统方(白棋)连续有多少个连续的棋子
	int emptyNum = 0; // 该方向上空白位的个数
 
	// 评分数组清零
	pfclear();
 
	for (int row = 0; row < 15; row++) {
		for (int col = 0; col < 15; col++) {
			//对每个点进行计算
			if (chessboard[row][col]) { continue; } //避开已经下过的点 -1、1都是true
 
			//控制方向 一共4个正方向:y不变 x+、y- x-、y- x不变、y- x+
			for (int y = -1; y <= 0; y++) {        //Y的范围是-1,0
				for (int x = -1; x <= 1; x++) {    //X的范围是 -1,0,1
					if (y == 0 && x == 0) { continue; }
					if (y == 0 && x != 1) { continue; } //当y=0时,仅允许x=1
 
					personNum = 0;
					aiNum = 0;
					emptyNum = 0;
 
					// 假设黑棋在该位置落子,会构成什么棋型
					for (int i = 1; i <= 4; i++) {
						int curRow = row + i * y;
						int curCol = col + i * x;
 
						if (curRow >= 0 && curRow < 15 &&
							curCol >= 0 && curCol < 15 &&
							chessboard[curRow][curCol] == 1) {
							personNum++;
						}
						else if (curRow >= 0 && curRow < 15 &&
							curCol >= 0 && curCol < 15 &&
							chessboard[curRow][curCol] == 0) {
							emptyNum++;
							break;
						}
						else {
							break;
						}
					}
 
					// 反向继续计算
					for (int i = 1; i <= 4; i++) {
						int curRow = row - i * y;
						int curCol = col - i * x;
 
						if (curRow >= 0 && curRow < 15 &&
							curCol >= 0 && curCol < 15 &&
							chessboard[curRow][curCol] == 1) {
							personNum++;
						}
						else if (curRow >= 0 && curRow < 15 &&
							curCol >= 0 && curCol < 15 &&
							chessboard[curRow][curCol] == 0) {
							emptyNum++;
							break;
						}
						else {
							break;
						}
					}
 
					if (personNum == 1) { //连2
						pf[row][col] += 10;
					}
					else if (personNum == 2) {
						if (emptyNum == 1) { //死3
							pf[row][col] += 30;
						}
						else if (emptyNum == 2) { //活3
							pf[row][col] += 40;
						}
					}
					else if (personNum == 3) {
						if (emptyNum == 1) { //死4
							pf[row][col] = 60;
						}
						else if (emptyNum == 2) { //活4
							pf[row][col] = 5000;
						}
					}
					else if (personNum == 4) { //连5
						pf[row][col] = 20000;
					}
 
					// 假设白棋在该位置落子,会构成什么棋型
					emptyNum = 0;
 
					for (int i = 1; i <= 4; i++) {
						int curRow = row + i * y;
						int curCol = col + i * x;
 
						if (curRow >= 0 && curRow < 15 &&
							curCol >= 0 && curCol < 15 &&
							chessboard[curRow][curCol] == -1) {
							aiNum++;
						}
						else if (curRow >= 0 && curRow < 15 &&
							curCol >= 0 && curCol < 15 &&
							chessboard[curRow][curCol] == 0) {
							emptyNum++;
							break;
						}
						else {
							break;
						}
					}
 
					for (int i = 1; i <= 4; i++) {
						int curRow = row - i * y;
						int curCol = col - i * x;
 
						if (curRow >= 0 && curRow < 15 &&
							curCol >= 0 && curCol < 15 &&
							chessboard[curRow][curCol] == -1) {
							aiNum++;
						}
						else if (curRow >= 0 && curRow < 15 &&
							curCol >= 0 && curCol < 15 &&
							chessboard[curRow][curCol] == 0) {
							emptyNum++;
							break;
						}
						else {
							break;
						}
					}
 
					if (aiNum == 0) {
						pf[row][col] += 5;
					}
					else if (aiNum == 1) { //连2
						pf[row][col] += 10;
					}
					else if (aiNum == 2) {
						if (emptyNum == 1) { //死3
							pf[row][col] += 25;
						}
						else if (emptyNum == 2) { //活3
							pf[row][col] += 50;
						}
					}
					else if (aiNum == 3) {
						if (emptyNum == 1) { //死4
							pf[row][col] += 55;
						}
						else if (emptyNum == 2) { //活4
							pf[row][col] += 10000;
						}
					}
					else if (aiNum >= 4) { //连5
						pf[row][col] += 30000;
					}
				}
			}
		}
	}
}

总结

  • 10
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值