博弈树搜索黑白棋

115 篇文章 3 订阅
#include<bits/stdc++.h>
using namespace std;
const double pi = acos(-1);
const double eps=1e-7;
const int base=131;
#define YES cout<<"YES"<<endl
#define NO cout<<"NO"<<endl
#define x first
#define y second
#define int long long
#define lb long double
#define pb push_back
#define endl '\n'//交互题删掉此 
#define all(v) (v).begin(),(v).end()
#define PII pair<int,int>
#define rep(i,x,n) for(int i=x;i<=n;i++)
#define dwn(i,n,x) for(int i=n;i>=x;i--)
#define ll_INF 0x7f7f7f7f7f7f7f7f
#define INF 0x3f3f3f3f
#define debug(x) cerr << #x << ": " << x << endl
#define io ios_base::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
int Mod(int a,int mod){return (a%mod+mod)%mod;}
int lowbit(int x){return x&-x;}//最低位1及其后面的0构成的数值
int qmi(int a, int k, int p){int res = 1 % p;while (k){if (k & 1) res = Mod(res * a , p);a = Mod(a * a , p);k >>= 1;}return res;}
int inv(int a,int mod){return qmi(a,mod-2,mod);}
#define BOUNDARY(x,y) ((x)>=1&&(x)<=8&&(y)>=1&&(y)<=8)
 
//开局介绍 
int introduce()
{ 
	printf(" &:black    *:white       \n\n");

	system("pause");
	return 0;
}

//重置并搜索可落子位置 
int search( int * const piece , const int color ) 
{
	int exist = 0;
	for( int i=0 ; i<=63 ; i++ )
	{
		if( piece[i]==1 || piece[i]==-1 )  continue;//有子跳过 
		if( piece[i]==2*color || piece[i]==-2*color )  piece[i]=0;//重置标记 
		for( int dx=-1 ; dx<=1 ; dx++ )//八向搜索 
		for( int dy=-1 ; dy<=1 ; dy++ )
		{
			if( dx==0 && dy==0 )  continue;
			for( int row = i/8+1+dx, col = i%8+1+dy ; BOUNDARY(row,col) ; row+=dx, col+=dy ) 
				if( piece[row*8+col-9] != -color )  break;//不是反色棋子就退出 
				else if( BOUNDARY(row+dx,col+dy) && piece[(row+dx)*8+col+dy-9]==color )
				{	//若反色棋子下一格是同色,则该点可落子;否则无操作 
					piece[i] = 2*color;
					exist = 1;
					goto finish;
				}
		}
		finish: ;
	}
	return exist;//存在可落子位置则返回1,不存在则返回0
} 

//输出棋盘界面 
int gui( int * const piece )
{
	system("cls");
	int score_black = 0, score_white = 0;
	printf("\033[0m\n        [黑白棋]\n\n    1 2 3 4 5 6 7 8 \n  ┌─────────────────┐\n");
	for( int i=0 ; i<=63 ; i++ )
	{
		if( i%8 == 0 )  printf(" %d│ ", i/8+1 );
		switch ( piece[i] )
		{
			case  1:
				printf("& ");		//黑棋 
				score_black++; break;
			case -1:
				printf("* ");		//白棋 
				score_white++; break;
			case  2:
			case -2:
				printf("\033[32m+ \033[0m"); break;	//提示位置 
			default:
				printf("+ ");		//空位 
		}
		if( i%8 == 7 ) printf("│\n");
	}
	printf("  └─────────────────┘\n   黑棋:%2d | 白棋:%2d \n", score_black, score_white);
	printf("─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─\n");
	return score_black==score_white ? 0 : ( score_black>score_white ? 1 : -1 ) ;
}
//输出信息,在gui()后 
int info( int * const piece, const int sign, const int color )
{
	static int cnt[3] = {0};
	for(int i=0;i<3;i++)if(cnt[i]>10){printf("再玩就坏了\n");cnt[i]=0;return 0;}
	switch( sign>=64 ? sign-80 : sign )
	{
		case -1:
			printf("%s方悔棋!\n", color==1 ? "黑" : "白" ); break;
		case -2:
			printf("无效操作!\n"); cnt[0]++; break;
		case -3:
			printf("该位置已有棋子!\n"); cnt[1]++; break;
		case -4:
			printf("该位置不可落子!\n"); cnt[1]++; break;
		case -5:
			printf("开局不能悔棋哦!\n"); cnt[0]++; break;
		case -6:
			introduce(); gui(piece); cnt[2]++; break;
		default: //sign>=0 
			if( sign < 64 ) printf("%s方在[%c%c]落子\n", color==1 ? "白" : "黑" , sign/8+'A' , sign%8+'1' );
			else printf("%s方在[%c%c]落子\n%s方无可落子位置!\n", color==1 ? "黑":"白" , sign/8-10+'A' , sign%8+'1', color==1 ? "白":"黑" );
			cnt[0]=cnt[1]=cnt[2]=0;
	}
	return 0;
}

//复制棋盘,用于悔棋  
int retract( int * const piece, int * const piece_last )
{
	int sign = -2;
	for( int i=0 ; i<64 ; i++ )
	{
		if( piece[i] != piece_last[i] ) sign = -1;
		piece[i] = piece_last[i];
	}
	
	return sign;
}

//落子操作,落子前备份棋盘 
int place( int * const piece, int * const piece_last, const int color )//棋盘,备份棋盘,颜色
{
	int row = 0, col = 0; char ch;
	printf("请%s方落子:\n", color==1 ? "黑" : "白" );
	fflush(stdin);
	while( ( ch=getchar() ) == '\n' || ch == ' ' );//第一次输入 
	if( ch=='R' || ch=='r' ) return -1;//悔棋 
	if( ch=='P' || ch=='p' ) return -6;//游戏规则
	if( ch>='A' && ch<='H' )	  row = ch+1-'A';
	else if( ch>='a' && ch<='h' ) row = ch+1-'a';
	else if( ch>='1' && ch<='8' ) row = ch-'0';
	while( ( ch=getchar() ) == '\n' || ch == ' ' );//第二次输入 
	if( ch>='A' && ch<='H' )	  col = ch+1-'A';
	else if( ch>='a' && ch<='h' ) col = ch+1-'a';
	else if( ch>='1' && ch<='8' ) col = ch-'0';
	if( !BOUNDARY(row,col) ) return -2;//无效操作 
	int loc = row*8+col-9;//数组格式位置 loc=0~63 
	if( piece[loc]==1 || piece[loc]==-1 ) return -3;//已有棋子 
	if( piece[loc]==0 || piece[loc]==-2*color ) return -4;//不可落子 
	retract(piece_last, piece);
	piece[loc] = color;//落子操作 
	for( int dx=-1 ; dx<=1 ; dx++ )//八向搜索,翻转棋子  
	for( int dy=-1 ; dy<=1 ; dy++ )
	{
		if( dx==0 && dy==0 )  continue;
		for( int rowp = row+dx, colp = col+dy ; BOUNDARY(rowp,colp) ; rowp+=dx, colp+=dy ) 
			if( piece[rowp*8+colp-9] != -color )  break;//不是反色就退出 
			else if( BOUNDARY(rowp+dx,colp+dy) && piece[(rowp+dx)*8+colp+dy-9]==color )
				for( ; rowp!=row || colp!=col ; rowp-=dx, colp-=dy )
					piece[rowp*8+colp-9] = color;//存在反色棋子则搜寻同色,并翻转中间的所有反色棋子 
	}
	return loc;//返回落子位置 
}

signed main() 
{
	int piece[64] = {0}, piece_last[64], color=1, sign=-1;
	piece[27]=piece[36]=-1; piece[28]=piece[35]=1;//预设棋子位置 
	gui(piece);
	introduce();
	start: piece[64]=0 ;
	piece[28]=piece[35]=color=1; piece[27]=piece[36]=sign=-1;
	search(piece,color);//首次落子 
	do{
		gui(piece);
		if( sign <= -2 ) info(piece, sign, color);
		sign = place(piece, piece_last, color);
		if( sign == -1 ) sign = -5;
	}while( sign <= -1 );//直到落子成功,sign为位置,才退出 
	while(1)//后续落子 
		if( search(piece, color *= -1) || ( sign+=80, search(piece, color *= -1) ) )//判断是否可落子 
			do{
				gui(piece);
				info(piece, sign, color);
				sign = place(piece, piece_last, color);
				if( sign == -1 ) sign = retract(piece, piece_last);
			}while( sign <= -2 );
		else break;//双方都不可落子则结束;若一方无棋子,同样满足双方都不可落子 
	int outcome = gui(piece);
	printf("%s方在[%c%c]落子\n",color==1 ? "黑" : "白" , sign/8+'A' , sign%8+'1' );//黑白要颠倒一下 
	printf("游戏结束, %s\n再来一局吗? (Y|N 或 1|0)\n", outcome==0 ? "平局!" : ( outcome==1 ? "黑方胜!" : "白方胜!" ) );
	char ch;
	for( fflush(stdin) ; (ch=getchar())!='0' && ch!='n' && ch!='N' ; )
		if( ch=='1' || ch=='y' || ch=='Y' ) goto start;
	system("pause");
	return 0;
}
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

leimingzeOuO

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值