这实际上是我学校的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));
}
一些值得注意的点:
最终这份代码得到了最后的冠军(并列第一,因为我和对手都能持黑击败对方,但事实上我的代码持黑可以用更少步数击败对手)
核心代码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)