前言
该文章用于记录在人工智能算法学习中的学习经历,同时也将所遇到的问题与经验分享给大家以作参考。
具体思路与分析有 时间会一一分享。
详细介绍
棋盘、棋子、主菜单绘制
通过一些特殊的符号对于棋盘进行绘制:
//绘制棋盘
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;
}
}
}
}
}
}