基于alpha-beta剪枝的井字棋博弈

5 篇文章 0 订阅

       本程序使用alpha-beta算法解决井字棋人机对弈的问题,运行环境要求是jdk1.8。

       初始化时,玩家需要选择棋子种类,输入1代表选择X,输入2代表选择O,输入其他的属于错误输入,默认选O。初始时玩家需要选择先手还是后手,输入1表示选择先手,输入2表示选择后手,输入其他为错误操作,默认是先手。棋盘为3*3大小,分别用1-9表示,按1-9在对应的位置下棋。输入1-9以外的按键或者在有棋子的地方输入属于非法操作,系统会要求重新输入。

程序设计说明

      1、棋盘采用的存储结构:3*3的二维数组。

      2、涉及角色:玩家、电脑两方,使用O和X区分。初始化时玩家可以选择自己的符号,默认为O;玩家同时也可以选择先手还是后手,默认是先手。

      3、判断程序结束条件:玩家或电脑其中一方取得胜利,用数组表示为a11a12a13、a21a22a23、a31a32a33、a11a22a33、a13a22a31、a11a21a31、a12a22a32、a13a23a33其中一组的符号相等。或者棋盘已满。

      

Alpha-beta剪枝的过程主要应用在回溯遍历所有生成的可能结果中,各个节点的取值为-1,0,1,。1表示电脑取得胜利,-1表示玩家取得胜利,0表示平局。遍历的过程与下述例子一致:

设当前棋盘为:

 

回溯法生成的树结构如下:

 

 

初始时alpha为-∞,beta为+∞,为树的所有节点从上到下从左到右标号为0-11。

      1、从第一棵子树开始使用回溯法遍历,第一颗子树只有一个节点,值为1,根节点暂时为1,MAX层改变alpha的值,此时alpha为1,beta为-∞。

      2、开始用回溯法遍历第二棵子树,第8个节点值为0,第4个节点是第8个节点的父节点,且4只有一个子节点,故4值为0,第2个节点暂时为0,此时alpha为1,beta为0,beta<alpha,需要进行剪枝,剪掉2的右子树。

      3、开始用回溯法遍历第三棵子树,第10个节点值为0,第6个节点值为0,第三个节点值暂时为0,alpha>beta开始剪枝,3的右子树减去,根的值为1,所以后一步结果为第1个节点,电脑胜利。

代码:

package homework;

import java.util.Random;
import java.util.Scanner;

public class Chess {
	char[][] chess = new char[4][4];
	char player,computer;
	boolean playerF;
	boolean detectWin(char player) {//判断玩家player是否胜利
		for(int i=1;i<4;i++)
			if(chess[i][1]==player&&chess[i][2]==player&&chess[i][3]==player) {
				return true;
			}else {
				if(chess[1][i]==player&&chess[2][i]==player&&chess[3][i]==player)
					return true;
			}
		if(chess[1][1]==player&&chess[2][2]==player&&chess[3][3]==player)
			return true;
		if(chess[1][3]==player&&chess[2][2]==player&&chess[3][1]==player)
			return true;
		return false;
	}
	boolean isEmpty() {//判断棋盘是否为空
		for(int i=1;i<4;i++) {
			for(int j=1;j<4;j++) {
				if(chess[i][j]=='-')return false;
			}
		}
		return true;
	}
	
	//初始化游戏
	public void startGame() {
		for(int i=1;i<4;i++)
			for(int j=1;j<4;j++)
				chess[i][j]='-';
		Scanner input = new Scanner(System.in);
		player = 'O';
		computer='X';
		System.out.print("请选择玩家符号X/O,(输入1代表选择X,输入2代表选择O,默认为O):");
		int get = input.nextInt();
		if(get==1) {
			player = 'X';
			computer = 'O';
		}else if(get!=2) {
			System.out.println("输入有误,默认为O");
		}
		playerF = true;
		System.out.println("是否先手1/2(1代表是,2代表否,默认是):");
		get = input.nextInt();
		if(get==2)playerF=false;
		else if(get!=1) {
			System.out.println("输入有误,默认玩家先手!");
		}
		if(playerF) {
			Print();
		}
		else {
			Random rand = new Random();
			int startPoint = rand.nextInt(9)+1;
			int row;
			if(startPoint%3==0)row=startPoint/3;
			else row = startPoint/3+1;
			int col = startPoint-(row-1)*3;
			chess[row][col]=computer;
			Print();
		}
	}
	void Print() {
		System.out.println("-------------");
		for(int i=1;i<4;i++) {
			for(int j=1;j<4;j++) {
				System.out.print("| ");
				System.out.print(chess[i][j]+" ");
				if(j==3)System.out.println("|");
			}
			if(i==3)System.out.println("-------------");
		}
	}
	void playerInput() {
		System.out.print("轮到你走了,请输入棋的位置:");
		int row,col;
		Scanner input = new Scanner(System.in);
		while(true) {
			int num = input.nextInt();
			if(num>=1&&num<=9) {
				if(num%3==0)row = num/3;
				else row = num/3+1;
				col = num-3*(row-1);
				if(chess[row][col]!='-')System.out.println("该位置已有棋子");
				else break;
			}else {
				System.out.println("输入有误,请重新输入");
				continue;
			}
		}
		chess[row][col]=player;
		Print();
//		input.close();
	}
	//-1,0,1分别代表玩家玩家胜利,平局,电脑胜利时节点的值
	int bestInput(String state,String nextState,int alpha,int beta) {//输入,调用剪枝的过程
		char ch;
		if(state.equals("computer"))ch=computer;
		else ch=player;
		if(detectWin(ch)) {
			if(state.equals("computer"))return 1;
			else  return -1;
		}else if(isEmpty()) {
			return 0;
		}
		else {
			int score;
			for(int i=1;i<4;i++) {
				for(int j=1;j<4;j++) {
					if(chess[i][j]=='-') {
						chess[i][j]=ch;
						score=bestInput(nextState,state,alpha,beta);
						chess[i][j]='-';
						if(state.equals("computer")) {
							if(score>=alpha)alpha=score;
							if(alpha>beta)return beta;
						}else {
							if(score<beta)beta=score;
							if(beta<=alpha)return alpha;
						}
					}
				}
			}
			if(state.equals("computer"))return alpha;
			else return beta;
		}
	}
	
	void computerInput() {
		int best=0;
		int bestScore=-1000; 
		int score;
		for(int i=1;i<=3;i++) {
			for(int j=1;j<=3;j++) {
				if(chess[i][j]=='-') {
					chess[i][j]=computer;
					score = bestInput("player","computer",-1000,1000);//alpha-beta剪枝是一个根据上下界限剪枝的算法,初始的上下界限为无穷
					if(score>bestScore) {//在同一层的节点里面需要不断试探性递归,用回溯法找到最合适的下棋点使自己胜算最大
						bestScore=score;
						best=(i-1)*3+j;
					}
					chess[i][j]='-';
				}
			}
		}
		int row,col;
		if(best%3==0)row = best/3;
		else row = best/3+1;
		col = best-(row-1)*3;
		chess[row][col]=computer;
		Print();
	}
	
	public static void main(String[] args) {
		Chess c = new Chess();
		c.startGame();
		String current = "player";
		while(!c.detectWin(c.computer)&&!c.detectWin(c.player)&&!c.isEmpty()) {//终止条件是当前棋盘为空或者有一方胜利
			switch(current) {
			case "player":
				c.playerInput();current="computer";break;//当玩家下完后轮到电脑下
			case "computer":
				c.computerInput();current="player";break;
			default:break;
			}
		}
		if(c.detectWin(c.computer))System.out.println("电脑胜利!");
		else if(c.detectWin(c.player))System.out.println("玩家胜利");
		else System.out.println("平局!");
	}
}

 

  • 15
    点赞
  • 66
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
五子棋是一种两人对弈的棋类游戏,使用黑白两种颜色的棋子在棋盘上交替落子,目标是先在任意一个方向上连成五个棋子的一方获胜。 为了提高人工智能在五子棋中的水平,可以运用alpha-beta剪枝技术进行优化。Alpha-beta剪枝是一种搜索算法,在搜索树中减少计算量的同时,保证结果的正确性。 在基于alpha-beta剪枝技术的五子棋游戏中,首先通过评估函数对当前棋盘局势进行评估,形成一个状态值。然后,利用alpha-beta剪枝技术,在搜索树上进行深度优先搜索,从而找到最佳的下一步棋。 在搜索过程中,通过设定alphabeta值,可以及时剪枝,减少不必要的搜索。如果某个节点的值能够被剪枝,则该节点以及其子节点将不再被继续搜索,从而减少了计算量。根据当前搜索的深度,可以调整alphabeta的值,进一步优化搜索效率。 评估函数在判断当前局势时非常重要。它可以根据棋盘上棋子的分布、连子的情况以及对手的威胁程度来进行评估。通过不断地调整评估函数的权重,使得AI的决策更加合理有效。 基于alpha-beta剪枝技术的五子棋游戏可以提供更具挑战性的对战体验。通过优化搜索算法和评估函数,AI可以更高效地进行决策,提高胜率和游戏水平。此外,Alpha-beta剪枝技术还可以应用在其他棋类游戏中,为人工智能算法的发展和应用提供了思路和参考。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值