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

       本程序使用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剪枝的井字棋博弈_第1张图片

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

 

基于alpha-beta剪枝的井字棋博弈_第2张图片

 

初始时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

      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(scorebestScore) {//在同一层的节点里面需要不断试探性递归,用回溯法找到最合适的下棋点使自己胜算最大
						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("平局!");
	}
}

 

你可能感兴趣的:(算法,Java)