基于min-max搜索和alpha-beta(α-β)剪枝的五子棋的c语言实现(带简单禁手)

这实际上是我学校的C语言程序设计课结课作业。整个作业代码适中,算法难度合适,是对初学者很友好的一件结课作业。
对五子棋而言最重要的还是估值函数的选择,如果一开始就写出了一个全盘估值的算法,那么很快就能改完了。
我的实现是这么考虑的,对于一个棋盘,黑白两色分别考虑,对于一个颜色,选择棋盘上分数最大的一个点作为这个颜色棋盘的分数,而这个分数的选择是基于活二活三等的数量统计出来的。
然后将两个颜色做差得到分数。

int F(int x,int y,int col){//get F
	int ret=0;
	for(int dir=0;dir<4;++dir){
		int dx=DirX[dir];
		int dy=DirY[dir];
		int now=0;
		for(int i=-4;i<=4;++i){
			int nowx=x+i*dx;
			int nowy=y+i*dy;
			now|=Get_Val(nowx,nowy,col);
			now<<=2;
		}
		now>>=2;
		ret+=SCORE_V[now];
	}
	return ret;
}

在这里我对棋盘进行了hash映射,使用0、1、2代表空,己方有子,对方有子。因为一个棋子只需要考虑哈他四个方向计九个棋子的权值即可。
查找棋子分数我选择的是AC自动机实现。
在实现了AC自动机后,我又发现可能我们并不需要对每个局面都调用AC自动机,这个复杂度太高了,相反,我们可以用预处理的办法。
对于一个棋子,我认为在一条线上,其周围至多左四右四,合计9个棋子比较有用,他们只有黑白空三种情况,对一个子用2bit记录,只需要18个比特即可记录所有情况,这个总数是很少的,情况的总数只有区区262143种,可以直接先把这些情况权值全部算完再O(1)查询估值即可,这就是上文我说的hash映射,这使得估值的复杂度为至多16次位运算和四次访存。

#ifndef AC
#define AC
#define MAXLEN 10000 
    const int CHENG_5_SCORE = 5000000;
    const int HUO_4_SCORE = 100000;
    const int CHONG_4_SCORE = 10000;
    const int DAN_HUO_3_SCORE = 8000;
    const int TIAO_HUO_3_SCORE = 7000;
    const int MIAN_3_SCORE = 500;
    const int HUO_2_SCORE = 50;
    const int MIAN_2_SCORE = 10;
    char CHANG_LIAN[]="111111"; 
    char CHENG_5[] = "11111";
    char HUO_4[] = "011110";
    char DAN_HUO_3_1[] = "001110";
    char DAN_HUO_3_2[] = "011100";
    char TIAO_HUO_3_1[] = "010110";
    char TIAO_HUO_3_2[] = "011010";
    char HUO_2_1[] = "001100";
    char HUO_2_2[] = "010100";
    char HUO_2_3[] = "001010";
    char CHONG_4_1[] = "011112";
    char CHONG_4_2[] = "211110";
    char CHONG_4_3[] = "10111";
    char CHONG_4_4[] = "11101";
    char CHONG_4_5[] = "11011";
    char MIAN_3_1[] = "001112";
    char MIAN_3_2[] = "211100";
    char MIAN_3_3[] = "010112";
    char MIAN_3_4[] = "211010";
    char MIAN_3_5[] = "011012";
    char MIAN_3_6[] = "210110";
    char MIAN_3_7[] = "10011";
    char MIAN_3_8[] = "11001";
    char MIAN_3_9[] = "10101";
    char MIAN_3_10[] = "2011102";
    char MIAN_2_1[] = "000112";
    char MIAN_2_2[] = "211000";
    char MIAN_2_3[] = "001012";
    char MIAN_2_4[] = "210100";
    char MIAN_2_5[] = "010012";
    char MIAN_2_6[] = "210010";
    char MIAN_2_7[] = "10001";
    char SHUANGCHONG_4_1[]= "1011101";
    char SHUANGCHONG_4_2[]= "11011011";
    char SHUANGCHONG_4_3[]= "111010111";
//the template of the AC_AUTOMATION
struct AC_AUTO{
	int fail;
	int vis[4];
	int cnt;	
}T1[1001],T2[1001],T3[1001],T4[1001],T5[1001],T6[1001],T7[1001],T8[1001],T9[1001],T10[1001];
int ACcnt=0;
void build_T(char s[],struct AC_AUTO T[]){
	int len=strlen(s);
	int idx=0;
	for(int i=0;i<len;i++){
		if(!T[idx].vis[s[i]-'0']){
			T[idx].vis[s[i]-'0']=++ACcnt;
			idx=ACcnt; 
		}
		else{
			idx=T[idx].vis[s[i]-'0'];
		}
	}
	T[idx].cnt++;
}
void build_fail_Arr(struct AC_AUTO T[]){
	int q[MAXLEN]={};
	int head=0;
	int tail=-1;
	for(int i=0;i<3;i++){
		if(T[0].vis[i]){
			T[0].fail=0;
			q[++tail]=T[0].vis[i];
		}
	}
	while(head<=tail){
		int x=q[head];
		head++;
		for(int i=0;i<3;i++){
			if(T[x].vis[i]){
				T[T[x].vis[i]].fail=T[T[x].fail].vis[i];
				q[++tail]=T[x].vis[i]; 
			}
			else
				T[x].vis[i]=T[T[x].fail].vis[i];
		}
	}
} 
int AC_Quary(char s[],struct AC_AUTO T[]){
	int len=strlen(s);
	int idx=0;
	for(int i=0;i<len;i++){
		idx=T[idx].vis[s[i]-'0'];
		for(int j=idx;j&&T[j].cnt!=-1;j=T[j].fail){
			if(T[j].cnt>0)
				return 1;
		}
	}
	return 0;
}
//T1 MIAN_3 
//T2 HUO_2 
//T3_CHONG_4
//T4 TIAO_HUO_3
//T5 DAN_HUO_3
//T6 HUO_4
//T7 MIAN_2
//T8 CHENG_5 
void AC_Build(){
	build_T(MIAN_3_1,T1);
	build_T(MIAN_3_2,T1);
	build_T(MIAN_3_3,T1);
	build_T(MIAN_3_4,T1);
	build_T(MIAN_3_5,T1);
	build_T(MIAN_3_6,T1);
//	build_T(MIAN_3_7,T1);
//	build_T(MIAN_3_8,T1);
	build_T(MIAN_3_9,T1);
	build_T(MIAN_3_10,T1);
	ACcnt=0;
	build_fail_Arr(T1); 
	
	build_T(HUO_2_1,T2);
	build_T(HUO_2_2,T2);
	build_T(HUO_2_3,T2);
	ACcnt=0;
	build_fail_Arr(T2);
	
	build_T(CHONG_4_1,T3);
	build_T(CHONG_4_2,T3);
	build_T(CHONG_4_3,T3);
	build_T(CHONG_4_4,T3);
	build_T(CHONG_4_5,T3);
	ACcnt=0;
	
	build_fail_Arr(T3);	
	build_T(TIAO_HUO_3_1,T4);
	build_T(TIAO_HUO_3_2,T4);
	ACcnt=0;
	build_fail_Arr(T4);

	build_T(DAN_HUO_3_1,T5);
	build_T(DAN_HUO_3_2,T5);
	ACcnt=0;
	build_fail_Arr(T5); 
	
	build_T(HUO_4,T6);
	ACcnt=0;
	build_fail_Arr(T6);
	
	build_T(MIAN_2_1,T7);
	build_T(MIAN_2_2,T7);
	build_T(MIAN_2_3,T7);
	build_T(MIAN_2_4,T7);
	build_T(MIAN_2_5,T7);
	build_T(MIAN_2_6,T7);
	build_T(MIAN_2_7,T7);
	ACcnt=0;
	build_fail_Arr(T7);
	
	build_T(CHENG_5,T8);
	ACcnt=0;
	build_fail_Arr(T8);
	
	build_T(CHANG_LIAN,T9);
	ACcnt=0;
	build_fail_Arr(T9);

	build_T(SHUANGCHONG_4_1,T10);
	build_T(SHUANGCHONG_4_2,T10);
	build_T(SHUANGCHONG_4_3,T10);
	ACcnt=0;
	build_fail_Arr(T10);
}
#endif 

预处理模块:

int GETSCORE(char s[]){
	int ret=0;
	if(AC_Quary(s,T8))ret+=CHENG_5_SCORE;
	if(AC_Quary(s,T7))ret+=MIAN_2_SCORE;
	if(AC_Quary(s,T6))ret+=HUO_4_SCORE;
	if(AC_Quary(s,T5))ret+=DAN_HUO_3_SCORE;
	if(AC_Quary(s,T4))ret+=TIAO_HUO_3_SCORE;
	if(AC_Quary(s,T3))ret+=CHONG_4_SCORE;
	if(AC_Quary(s,T2))ret+=HUO_2_SCORE;
	if(AC_Quary(s,T1))ret+=MIAN_3_SCORE;		
	return ret;
}
void SCORE_init(){//prepare for the F
	for(int i=0;i<=262143;i++){
		int x=i;
		char s[10];
		int flag=1;
		for(int i=0;i<9;++i){
			int now=x&3;
			if(now==3)flag=0;
			x>>=2;
		}
		if(flag==0)continue;
		x=i;
		for(int i=0;i<9;++i){
			int now=x&3;
			if(now==0)s[i]='0';
			if(now==1)s[i]='1';
			if(now==2)s[i]='2';
			x>>=2;
		}
		s[9]='\0';
		SCORE_V[i]=GETSCORE(s);
		CHANGLIAN[i]=AC_Quary(s,T9);
		CHENG5[i]=AC_Quary(s,T8);
		CHONG4[i]=((AC_Quary(s,T6)+AC_Quary(s,T3))>=1);
		HUO3[i]=((AC_Quary(s,T5)+AC_Quary(s,T4))>=1); 
		SHUANGCHONG4[i]=AC_Quary(s,T10);
	}
}

如是,我们就得到了一个可以搜索一层,估值全盘的五子棋。
随后将其放置在min-max搜索上。
关于min-max搜索无须多叙,参考wiki的伪代码便可以轻松实现(前提是你有一个估值全盘的估值函数)

function  minimax(node, depth, maximizingPlayer) is
    if depth = 0 or node is a terminal node then
        return the heuristic value of node
    if maximizingPlayer then
        value := −∞
        for each child of node do
            value := max(value, minimax(child, depth − 1, FALSE))
        return value
    else (* minimizing player *)
        value := +for each child of node do
            value := min(value, minimax(child, depth − 1, TRUE))
        return value

另外,我发现在很多时候,前一步搜索结果可以被继承(即你下的那一步和对手下的那一步全部被搜索),因此我设计了一个树状链表记录搜索树。
关于禁手:
我的代码并没有设计需要迭代的复杂禁手判断,这主要的原因是为了增加搜索层数,普通禁手可以判断长连,双四,双三等最主要的禁手。依旧使用预处理思想尽快判断禁手,复杂度为稳定的48次运算。

int JudgeBan(int x,int y){//judge a point  
	int ret=0;//0 not ban 1 ban
	int cntCHANGLIAN=0;
	int cntCHENG5=0;
	int cntCHONG4=0;
	int cntSHUANGCHONG4=0;
	int cntHUO3=0; 
	for(int dir=0;dir<4;++dir){
		int dx=DirX[dir];
		int dy=DirY[dir];
		int now=0;
		for(int i=-4;i<=4;++i){
			int nowx=x+i*dx;
			int nowy=y+i*dy;
			now|=Get_Val(nowx,nowy,0);
			now<<=2;
		}
		now>>=2; 
		if(CHANGLIAN[now]){
			cntCHANGLIAN++;
		}
		else{
			if(CHENG5[now]){
				cntCHENG5++;
			}
			else{
				if(CHONG4[now]){
					cntCHONG4++;
				}
				else{
					if(HUO3[now]){
						cntHUO3++;
					}
				}
			}
		}
		if(SHUANGCHONG4[now]){
			cntSHUANGCHONG4++;
		}
	}	
	if(cntCHANGLIAN)return 1;
	if(cntCHENG5)return 0;
	return ((cntHUO3>=2)||(cntCHONG4>=2)||(cntSHUANGCHONG4>=1));
}

一些值得注意的点:

  1. 编译优化很重要,如果使用的VS,released版本就很不错。
  2. 电脑配置也很重要,特别是在一场淘汰赛中取得较好成绩,在使用Core i7 gen 8时单核频率3.0Ghz,这份代码只能跑13层每层9个点,但在使用Core i9 gen 12时单核频率4.5Ghz,这份代码就可以跑13层每层均摊10.5个点了。

最终这份代码得到了最后的冠军(并列第一,因为我和对手都能持黑击败对方,但事实上我的代码持黑可以用更少步数击败对手)
核心代码wzq.c:已附加基本的注释

#include
#include 
#include
#include
#include 
#include "opt.h"
#include "AC.h"
#include "IO.h"
#include "algorithm.h"
#include "opt.h" 
#include "SCORE.h"
#include "tree.h" 
//#include "heap.h"
//#define Debug 0
//#define Debug2 0
#define depth 10
#define SUM 10
int T=0;
int nowrate=0;

int Limit1[13]={9,9,9,9,9,9,9,9,9,9,9,9,9}; 
//int Limit1[13]={10,9,9,9,9,8,8,8,8,8,8,8,8}; 
int Limit2[13]={9,9,9,9,9,8,8,8,8,8,8,8,8};
int Limit3[13]={8,8,8,7,7,7,7,7,6,6,6,6,6};
int (*Limit)[13];
struct Node{
	int x,y;
	int sum;
};
void putchess(int x,int y,int cur);
void UpdateV(int x,int y,int player);//update the value of the chessboard
void GetBan();
//
void player_to_player();
void computer_to_player(); 
void AC_Build();//build AC_AUTOMACHINE
void SCORE_init();
void pvalue();//print value  for debug
int checkwin();
void Tree_DFS(struct Tree_Node * now);//free the unnecessary tree node  
void regret();//regret two steps 
int main(){
	srand(233);
	printf("1:player to player ,2:player to computer \n");
	int x;
	scanf("%d",&x);
	if(x==1){
		player_to_player();
	}
	else{
		computer_to_player();		
	}
	return 0;
}
void player_to_player(){
	InitBoardArray();
	AC_Build();
	SCORE_init();
	DisplayBoard();
	for(int cur=0;;cur^=1){
		char c[40];
		int x,y;
		while(1){
			scanf("%s",c);
			int len=strlen(c);
			if(len==5){
				if(c[0]=='p'&&c[1]=='r'&&c[2]=='i'&&c[3]=='n'&&c[4]=='t'){
					print_step();
				}
				continue;
			}
			if(len==4){
				if(c[0]=='q'&&c[1]=='u'&&c[2]=='i'&&c[3]=='t'){
					return;
				}
			}
			if(len<=3&&len>1){
				int a;
				char b;
				b=(GETY(c));
				a=(GETX(c));
				y=(GETY(c))-'a';
				x=SIZE-(GETX(c));
				if(a==0||b=='z'||B.Array[x][y]!=2){
					printf("error input\n");
				}		
				else{
					break;
				}		
			}
			else{
				printf("error input\n");
			}	
		}
		y=(GETY(c))-'a';
		x=SIZE-(GETX(c));
		putchess(x,y,cur);
		GetBan();
		DisplayBoard();
		int check=checkwin();
		if(check!=2){
			if(check==0)
				puts("Black Win");
			else puts("White Win");
			return ;
		}
	}	
}
//
int F(int x,int y,int player);//judge function
int CheckCHENG_5(int x,int y,int col);
struct Node GetNext(int alpha,int beta,int player,int dep,struct Tree_Node *now);

void computer_to_player(){
	//0 black 1 white
	puts("1 you first,0 computer first");
	InitBoardArray();
	AC_Build();
	SCORE_init();
	int player;
	scanf("%d",&player);
	Limit=Limit3;
	int cur=1;
	if(player==0){//computer first, put the chess at H8
		cur^=1;
		putchess(7,7,cur);
		DisplayBoard();
	}
	if(player==1){
		DisplayBoard();//player first, giving a blank board
	}
	struct Tree_Node *head;
	head=malloc(sizeof(struct Tree_Node));
	memset(head,0,sizeof(struct Tree_Node));
	for(;;){
		if(B.cnt>=4){
			Limit=Limit1;
		}
		char c[40];
		int x,y;
		while(1){
			scanf("%s",c);
			int len=strlen(c);
			if(len==1){
				if(c[0]=='p'){//print the value of the board
					pvalue();
				}
				continue; 
			}
			if(len==6){
				if(c[0]=='r'&&c[1]=='e'&&c[2]=='g'&&c[3]=='r'&&c[4]=='e'&&c[5]=='t');{//regret,and give a new node to the tree.
					regret();
					Tree_DFS(head);
					head=malloc(sizeof(struct Tree_Node));
					memset(head,0,sizeof(struct Tree_Node));					
				} 
			}
			if(len==5){
				if(c[0]=='p'&&c[1]=='r'&&c[2]=='i'&&c[3]=='n'&&c[4]=='t'){
					print_step();
				}
				continue;
			}
			if(len==4){
				if(c[0]=='q'&&c[1]=='u'&&c[2]=='i'&&c[3]=='t'){
					return;
				}
			}
			if(len<=3&&len>1){
				int a;
				char b;
				b=(GETY(c));
				a=(GETX(c));
				y=(GETY(c))-'a';
				x=SIZE-(GETX(c));
				if(a==0||b=='z'||B.Array[x][y]!=2){
					printf("error input\n");
				}		
				else{
					break;
				}		
			}
			else{
				printf("error input\n");
			}	
		}
		y=(GETY(c))-'a';
		x=SIZE-(GETX(c));
		cur^=1;	
		putchess(x,y,cur);
		GetBan();
		DisplayBoard();
		int check=checkwin();
		if(check!=2){
			if(check==0)
				puts("Black Win");
			else puts("White Win");
			return ;
		}
		int findson=0;
		struct Tree_Node * tmpnow=head;
		//if already find some sons, just turn the head to that son.
		if(head->flag)
			for(int i=1;i<=head->cnt;++i){
				if(head->son[i]!=NULL&&head->son[i]->x==x&&head->son[i]->y==y){
					tmpnow=head->son[i];
					findson=1;
				}
				else{
					if(head->son[i]!=NULL){
						Tree_DFS(head->son[i]);
					}
				}
			}
		head=tmpnow;
		//not find the son, just create a new tree
		if(!findson){			
			head=malloc(sizeof(struct Tree_Node));
			memset(head,0,sizeof(struct Tree_Node));
		}
		//print the pos and predicting step
		if(findson){
			printf("%p\n",head);
			for(int i=1;i<=head->cnt;++i){
				printf("%p %d %c\n",head->son[i],15-head->son[i]->x,'A'+head->son[i]->y);
			} 
		}
		struct Node tmp;
		T=clock();
		tmp=GetNext(-1e9,1e9,player,depth,head);	
		cur^=1;
		#ifdef Debug2
			printf("%d %d %d\n",tmp.x,tmp.y,tmp.sum);
		#endif
		nowrate=tmp.sum;
		putchess(tmp.x,tmp.y,cur);
		tmpnow=head;
		for(int i=1;i<=head->cnt;++i){
			if(head->son[i]!=NULL&&head->son[i]->x==tmp.x&&head->son[i]->y==tmp.y){
				tmpnow=head->son[i];
				puts("IN");
			}
			else{
				if(head->son[i]!=NULL){
					Tree_DFS(head->son[i]);
				}
			}
		}		
		head=tmpnow;
		GetBan();
		DisplayBoard();
		printf("%d %c %d ms\n",15-tmp.x,'A'+tmp.y,(clock()-T)/1000);
		check=checkwin();
		if(check!=2){
			if(check==0)
				puts("Black Win");
			else puts("White Win");
			return ;
		}
	}
}
/*
function  minimax(node, depth, maximizingPlayer) is
    if depth = 0 or node is a terminal node then
        return the heuristic value of node
    if maximizingPlayer then
        value := -INF
        for each child of node do
            value := max(value, minimax(child, depth ? 1, FALSE))
        return value
    else (* minimizing player *)
        value := +INF
        for each child of node do
            value := min(value, minimax(child, depth ? 1, TRUE))
        return value
*/
void UpdateV(int x,int y,int col){
	if(B.Array[x][y]!=2)val[x][y]=F(x,y,B.Array[x][y]);
	else{val[x][y]=0;}
	for(int dir=0;dir<4;++dir){
		int dx=DirX[dir];
		int dy=DirY[dir];
		for(int i=-4;i<=4;i++){
			if(i==0)continue;
			int nowx=x+dx*i;
			int nowy=y+dy*i;
			if(inX(nowx)&&inY(nowy)&&B.Array[nowx][nowy]!=2){
				val[nowx][nowy]=F(nowx,nowy,B.Array[nowx][nowy]);
			}
		}
	}
}
struct Node GetNext(int alpha,int beta,int player,int dep,struct Tree_Node* nowNode){
	struct Node ret={-1,-1,-1e9}; 
	// if((T-clock())/1000>5000&&B.cnt>=6)Limit=Limit2;
	int cnt=0;
	if(dep==0){
		int now=-1e9;
		for(int i=0;ison[cnt]=malloc(sizeof(struct Tree_Node));
						memset(nowNode->son[cnt],0,sizeof(struct Tree_Node));
						nowNode->son[cnt]->x=i;
						nowNode->son[cnt]->y=j;
						nowNode->son[cnt]->sum=sum;
						for(int i=cnt-1;i>=1;i--){
							if((nowNode->son[i]->sum)<(nowNode->son[i+1]->sum)){
								struct Tree_Node* tmp=nowNode->son[i+1];
								nowNode->son[i+1]=nowNode->son[i];
								nowNode->son[i]=tmp;
							}
						}
					}
					else{
						if(nowNode->son[cnt]->sumson[cnt],0,sizeof(struct Tree_Node));
							nowNode->son[cnt]->x=i;
							nowNode->son[cnt]->y=j;
							nowNode->son[cnt]->sum=sum;
							for(int i=cnt-1;i>=1;i--){
								if((nowNode->son[i]->sum)<(nowNode->son[i+1]->sum)){
									struct Tree_Node* tmp=nowNode->son[i+1];
									nowNode->son[i+1]=nowNode->son[i];
									nowNode->son[i]=tmp;
								}						
							}
						}
					}
				}		
			}	
		}
		nowNode->cnt=cnt;
		if((player==0&&(dep%2==0))||(player==1&&(dep%2==1))){//get the ban of the black goal
			for(int i=1;i<=cnt;i++){
				nowNode->son[i]->ban=checkBan(nowNode->son[i]->x,nowNode->son[i]->y);
			}	
		}		
		nowNode->flag=1;
		int tot=0; 
		for(int i=1;i<=nowNode->cnt;i++){
			if(nowNode->son[i]==NULL)continue; 
			++tot;
			if(tot>(*Limit)[depth-dep])break;
			if(((player==0&&(dep%2==0))||(player==1&&(dep%2==1)))&&nowNode->son[i]->ban){
					continue;
			}
			int sum=0;
			int x=nowNode->son[i]->x;
			int y=nowNode->son[i]->y;
			int nowcol=(dep%2==1)?(player^1):player;
			int Mx=-1e9;
			int Mn=-1e9;
			if(CheckCHENG_5(x,y,nowcol)){
				sum=5000000;
			}
			else{
				B.Array[x][y]=nowcol;
				UpdateV(x,y,nowcol);
				for(int u=0;unow){
				now=sum;
				ret.x=x;
				ret.y=y;
				ret.sum=sum;
			}			
		} 
		return ret;
	}
	if(B.cnt==1&&dep==depth){
		for(int dir=0;dir<8;++dir){
			int x=B.curx+DirX[dir];
			int y=B.cury+DirY[dir];
			if(inX(x)&&inY(y)&&B.Array[x][y]==2){
				cnt++;
				nowNode->son[cnt]=malloc(sizeof(struct Tree_Node));
				memset(nowNode->son[cnt],0,sizeof(struct Tree_Node));
				nowNode->son[cnt]->x=x;
				nowNode->son[cnt]->y=y;
			}
		}
		nowNode->cnt=cnt;
		nowNode->flag=1;
	}
	else{
		if((nowNode->flag)!=1){
			int nowcol=(dep%2==1)?(player^1):player;
			for(int i=0;ison[cnt]=malloc(sizeof(struct Tree_Node));
							memset(nowNode->son[cnt],0,sizeof(struct Tree_Node));
							nowNode->son[cnt]->x=i;
							nowNode->son[cnt]->y=j;
							nowNode->son[cnt]->sum=sum;
							for(int i=cnt-1;i>=1;i--){
								if((nowNode->son[i]->sum)<(nowNode->son[i+1]->sum)){
									struct Tree_Node* tmp=nowNode->son[i+1];
									nowNode->son[i+1]=nowNode->son[i];
									nowNode->son[i]=tmp;
								}
							}
						}
						else{
							if(nowNode->son[cnt]->sumson[cnt],0,sizeof(struct Tree_Node));
								nowNode->son[cnt]->x=i;
								nowNode->son[cnt]->y=j;
								nowNode->son[cnt]->sum=sum;
								for(int i=cnt-1;i>=1;i--){
									if((nowNode->son[i]->sum)<(nowNode->son[i+1]->sum)){
										struct Tree_Node* tmp=nowNode->son[i+1];
										nowNode->son[i+1]=nowNode->son[i];
										nowNode->son[i]=tmp;
									}						
								}
							}
						}
					}
				}		
			}
			nowNode->cnt=cnt;
			if((player==0&&(dep%2==0))||(player==1&&(dep%2==1))){
				for(int i=1;i<=cnt;i++){
					nowNode->son[i]->ban=checkBan(nowNode->son[i]->x,nowNode->son[i]->y);
				}	
			}
			nowNode->flag=1; 
		}
	}
	//doing alpha and beta search
	if(dep%2==1){
		ret.sum=beta;
	} 
	else ret.sum=alpha;
	int tot=0;
	for(int i=1;i<=nowNode->cnt;i++){
		if(nowNode->son[i]==NULL)continue; 
		++tot;
		if(tot>(*Limit)[depth-dep])break;
		int x=nowNode->son[i]->x;
		int y=nowNode->son[i]->y;
		if(((player==0&&(dep%2==0))||(player==1&&(dep%2==1)))&&nowNode->son[i]->ban){
				continue;
		}
		if(dep%2==0){//max node
			B.Array[x][y]=player;
			UpdateV(x,y,player);
			if(CheckCHENG_5(x,y,player)){
					ret.x=x;
					ret.y=y;
					ret.sum=5000000;
					alpha=5000000;
			}
			else{
				struct Node now=GetNext(alpha,beta,player,dep-1,nowNode->son[i]);
				if(now.sum>ret.sum){
					ret.x=x;
					ret.y=y;
					ret.sum=now.sum;
					alpha=now.sum;
				}	
				if(dep==depth){
					printf("%d %c sum=%d\n",15-x,(char)('A'+y),now.sum);
				}					
			}
			B.Array[x][y]=2;
			UpdateV(x,y,player);
			if(beta<=alpha)break;
		}
		else{//min node
			B.Array[x][y]=(1-player);
			UpdateV(x,y,(player^1));
			if(CheckCHENG_5(x,y,1-player)){
				ret.x=x;
				ret.y=y;
				ret.sum=-5000000;
				beta=-5000000;
			}
			else{
				struct Node now=GetNext(alpha,beta,player,dep-1,nowNode->son[i]);
				if(now.sumcnt;i++){
		if(now->son[i]!=NULL){
			Tree_DFS(now->son[i]);
		}
	}
	free(now);
}
int GETSCORE(char s[]){
	int ret=0;
	if(AC_Quary(s,T8))ret+=CHENG_5_SCORE;
	if(AC_Quary(s,T7))ret+=MIAN_2_SCORE;
	if(AC_Quary(s,T6))ret+=HUO_4_SCORE;
	if(AC_Quary(s,T5))ret+=DAN_HUO_3_SCORE;
	if(AC_Quary(s,T4))ret+=TIAO_HUO_3_SCORE;
	if(AC_Quary(s,T3))ret+=CHONG_4_SCORE;
	if(AC_Quary(s,T2))ret+=HUO_2_SCORE;
	if(AC_Quary(s,T1))ret+=MIAN_3_SCORE;		
	return ret;
}
void SCORE_init(){//prepare for the F
	for(int i=0;i<=262143;i++){
		int x=i;
		char s[10];
		int flag=1;
		for(int i=0;i<9;++i){
			int now=x&3;
			if(now==3)flag=0;
			x>>=2;
		}
		if(flag==0)continue;
		x=i;
		for(int i=0;i<9;++i){
			int now=x&3;
			if(now==0)s[i]='0';
			if(now==1)s[i]='1';
			if(now==2)s[i]='2';
			x>>=2;
		}
		s[9]='\0';
		SCORE_V[i]=GETSCORE(s);
		CHANGLIAN[i]=AC_Quary(s,T9);
		CHENG5[i]=AC_Quary(s,T8);
		CHONG4[i]=((AC_Quary(s,T6)+AC_Quary(s,T3))>=1);
		HUO3[i]=((AC_Quary(s,T5)+AC_Quary(s,T4))>=1); 
		SHUANGCHONG4[i]=AC_Quary(s,T10);
	}
}
inline int Get_Val(int x,int y,int col){//the same col return 1, blank point return 0 other return 2
	if(!inX(x)||!inY(y))return 2;
	if(B.Array[x][y]==2)return 0;
	return B.Array[x][y]==col?1:2;
}
int F(int x,int y,int col){//get F
	int ret=0;
	for(int dir=0;dir<4;++dir){
		int dx=DirX[dir];
		int dy=DirY[dir];
		int now=0;
		for(int i=-4;i<=4;++i){
			int nowx=x+i*dx;
			int nowy=y+i*dy;
			now|=Get_Val(nowx,nowy,col);
			now<<=2;
		}
		now>>=2;
		ret+=SCORE_V[now];
	}
	return ret;
}
int CheckCHENG_5(int x,int y,int col){
	// 1 col 0 blank - other 
	for(int dir=0;dir<4;++dir){
		int dx=DirX[dir];
		int dy=DirY[dir];
		int now=0;
		for(int i=-4;i<=4;++i){
			if(i==0){
				now|=1;
				now<<=2;
				continue;
			}
			int nowx=x+i*dx;
			int nowy=y+i*dy;
			now|=Get_Val(nowx,nowy,col);
			now<<=2;
		}
		now>>=2;		
		if(CHENG5[now])return 1;
	}
	return 0;
}
int JudgeBan(int x,int y){//judge a point  
	int ret=0;//0 not ban 1 ban
	int cntCHANGLIAN=0;
	int cntCHENG5=0;
	int cntCHONG4=0;
	int cntSHUANGCHONG4=0;
	int cntHUO3=0; 
	for(int dir=0;dir<4;++dir){
		int dx=DirX[dir];
		int dy=DirY[dir];
		int now=0;
		for(int i=-4;i<=4;++i){
			int nowx=x+i*dx;
			int nowy=y+i*dy;
			now|=Get_Val(nowx,nowy,0);
			now<<=2;
		}
		now>>=2; 
		if(CHANGLIAN[now]){
			cntCHANGLIAN++;
		}
		else{
			if(CHENG5[now]){
				cntCHENG5++;
			}
			else{
				if(CHONG4[now]){
					cntCHONG4++;
				}
				else{
					if(HUO3[now]){
						cntHUO3++;
					}
				}
			}
		}
		if(SHUANGCHONG4[now]){
			cntSHUANGCHONG4++;
		}
	}	
	if(cntCHANGLIAN)return 1;
	if(cntCHENG5)return 0;
	return ((cntHUO3>=2)||(cntCHONG4>=2)||(cntSHUANGCHONG4>=1));
}
int checkBan(int x,int y){
	B.Array[x][y]=0;
	if(JudgeBan(x,y)){
		B.Array[x][y]=2;		
		return 1;
	}
	B.Array[x][y]=2;
	return 0;
}
int checkwin(){//check the whether winner exists
	for(int i=0;i

tree.h

#ifndef _Tree_
#define _Tree_
struct Tree_Node{
	int x,y,flag,sum,ban,cnt;
	struct Tree_Node* son[11];
};
#endif 

heap.h

#ifndef heap
#define heap 
struct Heap{
	struct HeapNode{
		int x;
		int y;
		int sum;
	}h[10];
	int heapcnt;	
};
void push(struct HeapNode t,struct HeapNode h[], int *heapcnt){
	(*heapcnt)++;
	int now=*heapcnt;
	h[*heapcnt]=t;
	while(now>1&&h[now].sum>1].sum){
		swap(h[now],h[now>>1]);
		now=now>>1;
	}
}
void pop(struct HeapNode h[],int *heapcnt){
	h[1]=h[*heapcnt];
	(*heapcnt)--;
	int now=1;
	int son;
	while(now*2<=*heapcnt){
		son=now*2;
		if(son+1<=*heapcnt&&h[son].sum>h[son+1].sum){
			son++;
		}
		if(h[now].sum

增加编译速度的opt.h

#pragma once
#ifdef __GNUC__
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#endif

交互库IO.h

#ifndef IO
#define IO
#define SIZE 15
#define MAXSTEP 15*15+1
struct{
	int cntstep[MAXSTEP][2];
	int Array[SIZE][SIZE];//0 black 1 white 2 blank	
	int cnt,curx,cury;
}B;
int DirX[8]={-1,0,1,1,1,0,-1,-1};
int DirY[8]={1,1,1,0,-1,-1,-1,0};
int val[SIZE][SIZE];
int val0[SIZE][SIZE];
int val1[SIZE][SIZE];
int Board[SIZE][SIZE]={};
int Ban[SIZE][SIZE];
int neighbor[SIZE][SIZE]={};
void print_int(int x,int y);//print x y for debug
void print_board(); 
void print_step(); 
int GETX(char c[]);
char GETY(char c[]);
void InitBoardArray(); 
void DisplayBoard();	
void Bclear();	
void Bclear(){//initial the board
	B.cnt=B.curx=B.cury=0;
	memset(B.cntstep,0,sizeof(B.cntstep));
	for(int i=0;i'9')&&pos='0'&&c[pos]<='9'&&pos'o')&&pos

基本算法库:

#ifndef algorithm
#define algorithm
#define min(x,y) ({            \
    int __min1 = (x);          \
    int __min2 = (y);          \
    __min1 < __min2 ? __min1 : __min2; })
 
#define max(x,y) ({            \
    int __max1 = (x);          \
    int __max2 = (y);          \
    __max1 > __max2 ? __max1 : __max2; })
    
#define swap(x,y)   {struct Node t;t=x;x=y;y=t;}

#define inX(x) ((x)>=0&&(x)=0&&(y)

你可能感兴趣的:(剪枝,c语言,算法)