剪枝算法实现一字棋-C++

博弈树

alpha & beta剪枝算法实现一字棋

剪枝算法首先就是要理解,把这个算法彻底弄清楚,我觉得这是一件非常有意义的事情!为后续书写其它棋类的AI打下了坚实的基础

剪枝操作的实现,遍历下一步所有可能取到的点,找出评估值最大的那一步就是我们下一步所需要的做的。
剪枝算法

int Tree::alphaBeta(int &value,int deep,bool MAX){
	if(isWin()==1){
		value=10000;
		return 0;
	}
	//递归的终点
	if(deep+this->count==9){
		return this->evaluate();
	}
	//一开始不剪枝
	bool prune=false;
	int temp,flag;

	//max结点我开始落子,电脑希望flag越大越好
	if(MAX)
		flag=10000;
	//min结点电脑开始落子,我希望flag越小越好
	else
		flag=-10000;
	for(int i=0;i<NUM && !prune;i++){
		for(int j=0;j<NUM && !prune;j++){
			//找出一个空位置下棋
			if(this->s[i][j]==' '){
				//如果当前结点是max结点,下一步是我下棋
				if(MAX){
					this->s[i][j]='X';
					//如果我下这一步我赢了,是电脑最不希望看到的,直接值取-100
					if(this->isWin()==-1)
						temp=-10000;
					else
						temp=this->alphaBeta(flag,deep+1,!MAX);
					if(temp<flag)	flag=temp;
					//如果我下棋让评分变的低了,电脑完全没必要走这一步,剪枝
					if(flag<=value) prune=true;
				}
				//min结点电脑开始下棋
				else{
					this->s[i][j]='O';
					//如果这一步对于电脑来说直接取得胜利,对于机器来说是十分想看到的
                    if(this->isWin()==1)
						temp=10000;
					else
						temp=this->alphaBeta(flag,deep+1,!MAX);
					//我们希望的flag小于实际的评分,此时flag应该更新
					if(temp>flag)	flag=temp;
					//此时对于我来说是十分不利的,我不可能走这一步让电脑获取胜利,我这一步应该被剪枝
					//或结点的alpha值不能降低其父结点的beta值,剪枝
					if(flag>=value) prune=true;
				}
				this->s[i][j]=' ';
			}
		}
	}
	//max(或)结点的扩展要是能提高value值
	if(MAX){
		if(flag>value)
			value=flag;
	}
	//min(与)结点的扩展要是能降低value值
	else{
		if(flag<value)
			value=flag;
	}
	return flag;
}

剪枝算法是一字棋程序中的核心部分,此外还需要定义一个棋类,用于初始化和实现下棋操作
棋类部分代码以及所有函数和变量

class Chess{
private:
	char a[3][3];		//棋盘的状态
	int count;          //已经下棋的步数
public:
	std::string computer,player;        //电脑与玩家
	int x,y;            				//下棋的位置
	std::string str,winner;       		//当前落子的对象
	void initial();     				//初始化函数
	void getMove();     				//获取走棋的位置
	bool makeMove(int,int,std::string);	//走棋函数
	void showStatus();  				//展示棋盘当前的状态
	bool isGameOver();  				//判断游戏是否结束
	void getStatus(char[][3]);          //获取当前的状态
	int getCount();                     //获取当前已经走棋的步数
};
void Chess::initial(){
	this->computer="Computer";
	this->player="Player";
	this->winner=" ";
	this->count=0;
	this->str=this->player;
	for(int i=0;i<NUM;i++){
		for(int j=0;j<NUM;j++){
			this->a[i][j]=' ';
		}
	}
}

主函数部分

	Onechess.initial();
	while(!Onechess.isGameOver() && Onechess.getCount()!=9){
		Onechess.showStatus();
		if(Onechess.str==Onechess.player){
			Onechess.getMove();
			Onechess.makeMove(Onechess.x,Onechess.y,Onechess.str);
		}
		else{
			tree.getChessStatus(Onechess);
			//不断的去试探,找出一个最大的value的值的走法
			for(int i=0;i<NUM;i++){
				for(int j=0;j<NUM;j++){
					if(tree.s[i][j]==' '){
						tree.s[i][j]='O';
						tree.alphaBeta(value,deep,1);
						if(value>temp){
							temp=value;
							row=i;
							column=j;
						}
						tree.s[i][j]=' ';
					}
				}
			}
			value=-10000;
			temp=-10000;
			Onechess.makeMove(row+1,column+1,Onechess.str);
		}
		printf("\n**************");
	}
	Onechess.showStatus();
	//并没有分出胜负,但是下棋的步数已经到达了9步,此时判定平局
	if(!Onechess.isGameOver() && Onechess.getCount()==9){
		printf("There are no winner! Is Draw!!!");
	}
	else
		printf("The winner is %s,let's congratulate!",Onechess.winner.c_str());

通过此次书写一字棋的博弈树,我对人工智能有了一个很好的了解。
部分运行截图。程序运行,结果最多就是平局,然后就是玩家输掉游戏。
在这里插入图片描述

  • 2
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是基于alpha-beta剪枝算法实现C++五子棋代码,供您参考: ```c++ #include <iostream> #include <vector> #include <algorithm> #include <cstring> using namespace std; const int N = 15; int board[N][N]; // 棋盘 int score[N][N]; // 每个位置的得分 int dx[] = {-1, -1, 0, 1, 1, 1, 0, -1}; int dy[] = {0, 1, 1, 1, 0, -1, -1, -1}; int max_depth = 3; // 最大搜索深度 int best_x, best_y; // 记录最优落子位置 // 初始化棋盘 void init() { memset(board, 0, sizeof board); memset(score, 0, sizeof score); best_x = best_y = N / 2; board[N/2][N/2] = 1; // 中心落子 } // 检查(x, y)是否越界 bool check(int x, int y) { return x >= 0 && x < N && y >= 0 && y < N; } // 判断是否有五子连珠 bool win(int x, int y) { for (int i = 0; i < 8; i++) { int cnt = 1; for (int j = 1; j <= 4; j++) { int nx = x + j * dx[i], ny = y + j * dy[i]; if (check(nx, ny) && board[nx][ny] == board[x][y]) cnt ++; else break; } for (int j = 1; j <= 4; j++) { int nx = x - j * dx[i], ny = y - j * dy[i]; if (check(nx, ny) && board[nx][ny] == board[x][y]) cnt ++; else break; } if (cnt >= 5) return true; } return false; } // 计算(x, y)的得分 int calc(int x, int y) { int res = 0; for (int i = 0; i < 8; i++) { int cnt = 0; bool flag1 = true, flag2 = true; for (int j = 1; j <= 4; j++) { int nx = x + j * dx[i], ny = y + j * dy[i]; if (check(nx, ny)) { if (board[nx][ny] == 1) cnt ++; else if (board[nx][ny] == 2) {flag1 = false; break;} } else {flag1 = false; break;} } if (flag1) res += cnt * cnt; cnt = 0; for (int j = 1; j <= 4; j++) { int nx = x - j * dx[i], ny = y - j * dy[i]; if (check(nx, ny)) { if (board[nx][ny] == 1) cnt ++; else if (board[nx][ny] == 2) {flag2 = false; break;} } else {flag2 = false; break;} } if (flag2) res += cnt * cnt; } return res; } // 计算每个位置的得分 void get_score() { for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { if (board[i][j] == 0) { score[i][j] = calc(i, j); } } } } // alpha-beta剪枝搜索 int dfs(int depth, int alpha, int beta) { if (depth == max_depth) return calc(best_x, best_y); vector<pair<int, int>> v; for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { if (board[i][j] == 0) { v.push_back({i, j}); } } } sort(v.begin(), v.end(), [](pair<int, int> a, pair<int, int> b) { return score[a.first][a.second] > score[b.first][b.second]; }); int res = -1e9; for (auto [x, y] : v) { board[x][y] = depth % 2 + 1; if (win(x, y)) { // 有必胜局面,直接返回 board[x][y] = 0; return depth % 2 == 0 ? 1e9 : -1e9; } get_score(); int t = dfs(depth + 1, alpha, beta); board[x][y] = 0; if (depth % 2 == 0) { // MAX节点 if (t > res) { res = t; if (depth == 0) { best_x = x; best_y = y; } } alpha = max(alpha, t); } else { // MIN节点 if (t < res) { res = t; } beta = min(beta, t); } if (alpha >= beta) break; // alpha剪枝或beta剪枝 } return res; } int main() { init(); get_score(); dfs(0, -1e9, 1e9); cout << best_x << " " << best_y << endl; return 0; } ``` 在以上代码中,我们使用了alpha-beta剪枝算法进行搜索。搜索过程中,我们先计算每个位置的得分,然后按照得分从高到低对所有空位进行排序。在搜索时,我们依次枚举每个空位,对于每个空位,我们先尝试在该位置落子,然后计算该位置落子后的得分,然后进入下一层搜索。如果搜索到达了最大深度,我们就返回该位置的得分。如果该位置可以使当前玩家获胜,我们直接返回极大值或极小值。如果该位置不是必胜局面,我们继续搜索下一层。在搜索下一层时,我们需要将当前玩家交换为对手玩家,并更新alpha和beta。如果当前节点是MAX节点,则更新alpha,并进行alpha剪枝。如果当前节点是MIN节点,则更新beta,并进行beta剪枝。最后,我们返回当前节点的值。 由于五子棋的搜索空间非常庞大,因此我们需要设置一个最大搜索深度,以避免搜索时间过长。在以上代码中,我们设置了最大搜索深度为3。如果您的电脑性能较好,您可以适当增加最大搜索深度,以提高搜索质量。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值