c语言编简单博弈小游戏,[2018年最新整理]实验二:利用α-β搜索过程的博弈树搜索算法编写一字棋游戏.doc...

[2018年最新整理]实验二:利用α-β搜索过程的博弈树搜索算法编写一字棋游戏

实验二:利用α-β搜索过程的博弈树搜索算法编写一字棋游戏

一、实验目的与要求

(1)了解极大极小算法的原理和使用方法,并学会用α-β剪枝来提高算法的效率。

(2)使用C语言平台,编写一个智能井字棋游戏。

(3)结合极大极小算法的使用方法和α-β剪枝,让机器与人对弈时不但有智能的特征,而且计算的效率也比较高。

二、实验原理

一字棋游戏是一个流传已久的传统游戏。游戏由两个人轮流来下,分别用“X”和“O”来代替自身的棋子。棋盘分9个格,双方可以在轮到自己下的时候,可以用棋子占领其中一个空的格子。如果双方中有一方的棋子可以连成一条直线,则这一方判胜,对方判负。当所有的格子都被占领,但双方都无法使棋子连成一条直线的话,则判和棋。

这是一个智能型的一字棋游戏,机器可以模拟人与用户对弈。当轮到机器来下的时候,机器会根据当前棋局的形势,利用极大极小算法算出一个评价值,判断如何下才对自身最有利,同时也是对方来说对不利的,然后下在评价值最高的地方。另外利用α-β剪枝,使机器在搜索评价值的时候不用扩展不必要的结点,从而提高机器计算的效率。

在用户界面方法,用一个3×3的井字格来显示用户与机器下的结果。当要求用户输入数据的时候会有提示信息。用户在下的过程中可以中途按下“0”退出。当用户与计算机分出了胜负后,机器会显示出比赛的结果,并按任意键退出。如果用户在下棋的过程中,输入的是非法字符,机器不会做出反应。

三、实验步骤和过程

1.α-β搜索过程  在极小极大搜索方法中,由于要先生成指定深度以内的所有节点,其节点数将随着搜索深度的增加承指数增长。这极大地限制了极小极大搜索方法的使用。能否在搜索深度不变的情况下,利用已有的搜索信息减少生成的节点数呢?

MINIMAX过程是把搜索树的生成和格局估值这两个过程分开来进行,即先生成全部搜索树,然后再进行端节点静态估值和倒推值计算,这显然会导致低效率。如图中,其中一个MIN节点要全部生成A、B、C、D四个节点,然后还要逐个计算其静态估值,最后在求倒推值阶段,才赋给这个MIN节点的倒推值-∞。其实,如果生成节点A后,马上进行静态估值,得知f(A)=-∞之后,就可以断定再生成其余节点及进行静态计算是多余的,可以马上对MIN节点赋倒推值-∞,而丝毫不会影响MAX的最好优先走步的选择。这是一种极端的情况,实际上把生成和倒推估值结合起来进行,再根据一定的条件判定,有可能尽早修剪掉一些无用的分枝,同样可获得类似的效果,这就是α-β过程的基本思想。α-β搜索过程一字棋的

图一字棋第一阶段α-β剪枝方法为了使生成和估值过程紧密结合,采用有界深度优先策略进行搜索,这样当生成达到规定深度的节点时,就立即计算其静态估值函数,而一旦某个非端节点有条件确定其倒推值时就立即计算赋值。从图中标记的节点生成顺序号(也表示节点编号)看出,生成并计算完第6个节点后,第1个节点倒推值完全确定,可立即赋给倒推值-1。这时对初始节点来说,虽然其他子节点尚未生成,但由于s属极大值层,可以推断其倒推值不会小于-1,我们称极大值层的这个下界值为α,即可以确定s的α=-1。这说明s实际的倒推值决不会比-1更小,还取决于其他后继节点的倒推值,因此继续生成搜索树。当第8个节点生成出来并计算得静态估值为-1后,就可以断定第7个节点的倒推值不可能大于-1,我们称极小值层的这个上界值为β,即可确定节点7的β=-1。有了极小值层的β值,很容易发现若α≥β时,节点7的其他子节点不必再生成,这不影响高一层极大值的选取,因s的极大值不可能比这个β值还小,再生成无疑是多余的,因此可以进行剪枝。这样一来,只要在搜索过程记住倒推值的上下界并进行比较,就可以实现修剪操作,称这种操作为α剪枝。类似的还有β剪枝,统称为α-β剪枝技术。在实际修剪过程中,α、β还可以随时修正,但极大值层的倒推值下界α永不下降,实际的倒推值取其后继节点最终确定的倒推值中最大的一个倒推值。而极小值层的倒推值上界β永不上升,其倒推值则取后继节点最终确定的倒推值中最小的一个倒推值。在进行α-β剪枝时,应注意以下几个问题:  (1)比较都是在极小节点和极大节点间进行的,极大节点和极大节点的比较,或者极小节点和极小节点间的比较是无意义的。  (2)在比较时注意是与"先辈层"节点比较,不只是与父辈节点比较。当然,这里的"先辈层"节点,指的是那些已经有了值的节点。  (3)当只有一个节点的"固定"以后,其值才能够向其父节点传递。  (4)α-β剪枝方法搜索得到的最佳走步与极小极大方法得到的结果是一致的,α-β剪枝并没有因为提高效率,而降低得到最佳走步的可能性。  (5)在实际搜索时,并不是先生成指定深度的搜索图,再在搜索图上进行剪枝。如果这样,就失去了α-β剪枝方法的意义。在实际程序实现时,首先规定一个搜索深度,然

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是C语言实现建立博弈树并用&alpha;-&beta;剪枝的六子棋代码: ```c #include <stdio.h> #define DEPTH 4 #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define MIN(a, b) ((a) < (b) ? (a) : (b)) int board[6][6]; // 棋盘 int alpha_beta(int depth, int alpha, int beta, int player); // &alpha;-&beta;剪枝函数 int evaluate(); // 估值函数 void print_board(); // 打印棋盘 int main() { int i, j, x, y; int player = 1; // 玩家 int result = 0; // 结果 printf("六子棋游戏开始!\n"); for(i = 0; i < 6; i++) { for(j = 0; j < 6; j++) { board[i][j] = 0; // 初始化棋盘 } } print_board(); while(1) { if(player == 1) { printf("请玩家1输入下棋位置(x, y):"); scanf("%d%d", &x, &y); if(board[x][y] == 0) { board[x][y] = 1; player = 2; // 转到玩家2 } else { printf("该位置已被占用,请重新输入!\n"); } } else { printf("玩家2正在思考……\n"); result = alpha_beta(0, -1000000, 1000000, 2); printf("玩家2选择了(%d, %d)处下棋,估值为%d\n", x, y, result); board[x][y] = 2; player = 1; // 转到玩家1 } print_board(); if(evaluate() == 1) { printf("玩家1获胜!\n"); break; } else if(evaluate() == 2) { printf("玩家2获胜!\n"); break; } else if(evaluate() == 3) { printf("平局!\n"); break; } } return 0; } int alpha_beta(int depth, int alpha, int beta, int player) { int i, j, k; int value; int max_value = -1000000; int min_value = 1000000; if(depth == DEPTH) { return evaluate(); } for(i = 0; i < 6; i++) { for(j = 0; j < 6; j++) { if(board[i][j] == 0) { if(player == 2) { board[i][j] = 2; value = alpha_beta(depth + 1, alpha, beta, 1); max_value = MAX(max_value, value); alpha = MAX(alpha, value); if(beta <= alpha) { board[i][j] = 0; break; } } else { board[i][j] = 1; value = alpha_beta(depth + 1, alpha, beta, 2); min_value = MIN(min_value, value); beta = MIN(beta, value); if(beta <= alpha) { board[i][j] = 0; break; } } board[i][j] = 0; } } } if(player == 2) { return max_value; } else { return min_value; } } int evaluate() { int i, j, k; int count1, count2; // 判断行 for(i = 0; i < 6; i++) { for(j = 0; j < 2; j++) { count1 = 0; count2 = 0; for(k = 0; k < 6; k++) { if(board[i][j + k] == 1) { count1++; count2 = 0; } else if(board[i][j + k] == 2) { count2++; count1 = 0; } else { count1 = 0; count2 = 0; } if(count1 == 4) { return 1; } if(count2 == 4) { return 2; } } } } // 判断列 for(i = 0; i < 6; i++) { for(j = 0; j < 2; j++) { count1 = 0; count2 = 0; for(k = 0; k < 6; k++) { if(board[j + k][i] == 1) { count1++; count2 = 0; } else if(board[j + k][i] == 2) { count2++; count1 = 0; } else { count1 = 0; count2 = 0; } if(count1 == 4) { return 1; } if(count2 == 4) { return 2; } } } } // 判断正对角线 for(i = 0; i < 2; i++) { for(j = 0; j < 2; j++) { count1 = 0; count2 = 0; for(k = 0; k < 6; k++) { if(board[i + k][j + k] == 1) { count1++; count2 = 0; } else if(board[i + k][j + k] == 2) { count2++; count1 = 0; } else { count1 = 0; count2 = 0; } if(count1 == 4) { return 1; } if(count2 == 4) { return 2; } } } } // 判断反对角线 for(i = 0; i < 2; i++) { for(j = 4; j < 6; j++) { count1 = 0; count2 = 0; for(k = 0; k < 6; k++) { if(board[i + k][j - k] == 1) { count1++; count2 = 0; } else if(board[i + k][j - k] == 2) { count2++; count1 = 0; } else { count1 = 0; count2 = 0; } if(count1 == 4) { return 1; } if(count2 == 4) { return 2; } } } } // 判断平局 for(i = 0; i < 6; i++) { for(j = 0; j < 6; j++) { if(board[i][j] == 0) { return 0; // 棋盘还有空位,未结束 } } } return 3; // 棋盘已满,平局 } void print_board() { int i, j; printf(" 0 1 2 3 4 5\n"); for(i = 0; i < 6; i++) { printf("%d ", i); for(j = 0; j < 6; j++) { if(board[i][j] == 0) { printf("+ "); } else if(board[i][j] == 1) { printf("O "); } else { printf("X "); } } printf("\n"); } } ``` 在该代码中,我们使用了一个维数组`board`来表示棋盘,其中0表示空位,1表示玩家1的棋子,2表示玩家2的棋子。`alpha_beta`函数是&alpha;-&beta;剪枝函数,其中`depth`表示当前深度,`alpha`和`beta`表示当前的&alpha;和&beta;值,`player`表示当前轮到的玩家。`evaluate`函数是估值函数,用于判断游戏是否结束以及胜负情况。`print_board`函数用于打印当前棋盘状态。 在主函数中,我们先初始化棋盘,然后开始游戏循环,每次循环中根据当前玩家输入下棋位置或者调用`alpha_beta`函数选择下棋位置,然后判断游戏是否结束以及胜负情况,最后打印当前棋盘状态。 在这个六子棋游戏中,我们使用了&alpha;-&beta;剪枝算法来优化博弈树搜索,从而提高了程序的效率,使得程序可以更快地做出决策。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值