五子棋的简单算法——评分法(人机对抗代码)

之前搞了个五子棋的算法,我在写好算法之前参考网上很多的五子棋算法像是博弈树算法这些的一开始写起来不太好理解,今天就分享一个简单的五子棋算法——评分法。

评分法

原理:
评分法,有的也叫评分表法,不管叫什么,名字不重要,重要的是思路。我们写棋总是下在对自己优势最大的位置上,但是可以下的位置有很多啊,电脑怎么知道下在哪里最好啊?评分法就是给每个可下的位置评分,电脑通过分数高低来判断下在哪个位置。

方法:
评分法的原理是一致的,但方法各种各样,我的方法是这样的(仅供参考)。
1、棋型分析
五子棋的棋型很多很多,在这里不详细介绍,只介绍一些简单的棋型。
连五棋型:有五个相同颜色的棋子连成一线;
活四棋型:有四个相同颜色的棋子连成一线且两端均可下棋;
眠四棋型:有四个相同颜色的棋子连成一线但两端只有一端可下棋;
类似的还有活三、眠三、活二等棋型。
下图,便是我以1为黑棋,2为白棋,0为空位置排列组合所得到的棋型示例,
图一是以所选位置为中心判断的,
图二则是以所选位置为起点判断的,
我们可以把这些棋型分别用一个二维数组来保存,方便与所选位置可组成的棋型比较。
在这里插入图片描述
图一
在这里插入图片描述
图二
2、根据棋型打分(可以自己设置评分标准)
在这里插入图片描述
算法代码怎么写:
每次下棋前扫描棋盘上所有可以下的位置,把它们保存起来,然后用循环得出每一个位置八个方向可组成的棋型,再根据评分标准给位置评分,再判断最高的评分(要考虑有多个的情况)。

步骤

1、创建position类作为下棋的位置,代码如下:

package chess;

public class position {

	private int x;//棋子位置横坐标
	private int y;//棋子位置纵坐标
	//构造方法
	public position(int x,int y) {
		this.x = x;
		this.y = y;
	}
	//通过set和get方法赋值和访问
	public void setX(int x) {
		this.x = x;
	}
	public int getX() {
		return x;
	}
	public void setY(int y) {
		this.y = y;
	}
	public int getY() {
		return y;
	}
}

2、创建chess类
这里是核心,其中包含五子棋游戏初始化、下棋、棋盘情况判断、评分算法等方法,详情见下面代码:

package chess;

import java.util.ArrayList;
import java.util.Arrays;

public class chess {
  
	private int size;//棋盘大小
	private int[][] chessboard;//棋盘
	private int color=1;//1为黑子,2为白子
	/*
	 * 以所选位置为中心的各种棋型,有连5,活4,眠4,活3,眠3,活2,眠2;
	 * 连5:1111,2222;
	 * 活4:1110,0111,2220,0222; 
	 * 眠4:1112,2111,2221,1222; 
	 * 活3:1100,0011,0110,2200,0022,0220;
	 * 眠3:1120,1121,0211,1211,2110,0112,2210,2211,0122,2122,1220,0221;
	 * 活2:0100,0010,0200,0020; 
	 * 眠2:2100,0012,1200,0021;
	 */
	private int[][] stiuation = { { 1, 1, 1, 1 }, { 2, 2, 2, 2 }, { 1, 1, 1, 0 }, { 0, 1, 1, 1 }, { 2, 2, 2, 0 },
			{ 0, 2, 2, 2 }, { 1, 1, 1, 2 }, { 2, 1, 1, 1 }, { 2, 2, 2, 1 }, { 1, 2, 2, 2 }, { 1, 1, 0, 0 },
			{ 0, 0, 1, 1 }, { 0, 1, 1, 0 }, { 2, 2, 0, 0 }, { 0, 0, 2, 2 }, { 0, 2, 2, 0 }, { 1, 1, 2, 0 },
			{ 1, 1, 2, 1 }, { 0, 2, 1, 1 }, { 1, 2, 1, 1 }, { 2, 1, 1, 0 }, { 0, 1, 1, 2 }, { 2, 2, 1, 0 },
			{ 2, 2, 1, 1 }, { 0, 1, 2, 2 }, { 2, 1, 2, 2 }, { 1, 2, 2, 0 }, { 0, 2, 2, 1 }, { 0, 1, 0, 0 },
			{ 0, 0, 1, 0 }, { 0, 2, 0, 0 }, { 0, 0, 2, 0 }, { 2, 1, 0, 0 }, { 0, 0, 1, 2 }, { 1, 2, 0, 0 },
			{ 0, 0, 2, 1 } };
	/*
	 * 以所选位置为起点的棋型,连5,活4,眠4,活3,眠3; 
	 * 连5:1111,2222; 
	 * 活4:1110,2220; 
	 * 眠4:1112,2221;
	 * 活3:1100,1101,1102,2200,2201,2202; 
	 * 眠3:1120,1121,1122,2210,2211,2122;
	 */
	private int[][] stiuation2 = { { 1, 1, 1, 1 }, { 2, 2, 2, 2 }, { 1, 1, 1, 0 }, { 2, 2, 2, 0 }, { 1, 1, 1, 2 },
			{ 2, 2, 2, 1 }, { 1, 1, 0, 0 }, { 1, 1, 0, 1 }, { 1, 1, 0, 2 }, { 2, 2, 0, 0 }, { 2, 2, 0, 1 },
			{ 2, 2, 0, 2 }, { 1, 1, 2, 0 }, { 1, 1, 2, 1 }, { 1, 1, 2, 2 }, { 2, 2, 1, 0 }, { 2, 2, 1, 1 },
			{ 2, 2, 1, 2 } };

	//设置游戏,size为棋盘大小,color为电脑所选择棋子的颜色
	public void setGame(int size,int color) {
		this.size=size;
		this.color=color;
		this.chessboard=new int[this.size][this.size];
		//初始化棋盘
		for (int i = 0; i < chessboard.length; i++) {
			for (int j = 0; j < chessboard.length; j++) {
				this.chessboard[i][j]=0;
			}
		}
	}
	//下棋,x和y分别是人下棋的横坐标和纵坐标,电脑根据坐标来判断下棋位置下棋
	public void getMove(int x,int y) {
		//人下棋
		if(this.color==1)
		this.chessboard[x][y]=2;
		else
		this.chessboard[x][y]=1;
		System.out.println("人下棋:("+x+","+y+")");
		print();
		if(isWin(x,y)) {
			System.out.println("人获胜");
			System.exit(0);
		}
		else if(isFull()) {
			System.out.println("平局");
			System.exit(0);
		}
		//存储所有未下棋的位置
		ArrayList<position> positions=new ArrayList<>();
		//存储每个位置的评分
		ArrayList<Integer> numbers=new ArrayList<>();
		
		for (int i = 0; i < chessboard.length; i++) {
			for (int j = 0; j < chessboard.length; j++) {
				positions.add(new position(i,j));
				numbers.add(numJudge(i,j));
			}
		}
		int index = 0;// 最高评分在numbers中的下标
		for (int i = 0; i < numbers.size(); i++) {
			if (numbers.get(i) > numbers.get(index)) {
				index = i;
			}
		}
		// 储存所有最高评分在numbers中的下标(当最高评分有多个时)
		ArrayList<Integer> max = new ArrayList<>();
		for (int i = 0; i < numbers.size(); i++) {
			if (numbers.get(i) == numbers.get(index)) {
				max.add(i);
			}
		}
		//电脑下棋
		if(max.size()==1){
			System.out.println("电脑下棋:("+positions.get(max.get(0)).getX()+","+positions.get(max.get(0)).getY()+")");
			if(this.color==1)
			this.chessboard[positions.get(max.get(0)).getX()][positions.get(max.get(0)).getY()]=1;
			else
			this.chessboard[positions.get(max.get(0)).getX()][positions.get(max.get(0)).getY()]=2;
			if(isWin(positions.get(max.get(0)).getX(), positions.get(max.get(0)).getY())) {
				System.out.println("平局");
				System.exit(0);
			}
        }
		else{
        	index = (int) (Math.random() * max.size());
        	System.out.println("电脑下棋:("+positions.get(max.get(index)).getX()+","+positions.get(max.get(index)).getY()+")");
        	if(this.color==1)
    		this.chessboard[positions.get(max.get(0)).getX()][positions.get(max.get(0)).getY()]=1;
    		else
    		this.chessboard[positions.get(max.get(0)).getX()][positions.get(max.get(0)).getY()]=2;
    		if(isWin(positions.get(max.get(0)).getX(), positions.get(max.get(0)).getY())) {
				System.out.println("电脑获胜");
				System.exit(0);
			}
			else if(isFull()) {
				System.out.println("平局");
				System.exit(0);
			}
        }
		print();
	}
    //评分算法
	private int numJudge(int x, int y) {
		int sum = 0;
		sum += mark1(x, y);// 左右方向
		sum += mark2(x, y);// 上下方向
		sum += mark3(x, y);// 主对角线方向
		sum += mark4(x, y);// 副对角线方向
		sum += mark5(x, y);// 八个方向
		return sum;
	}
	// 给分标准1,根据棋型给分
		private int calculate(int[] position) {
			int sum = 0;
			int index = -1;
			for (int i = 0; i < this.stiuation.length; i++) {
				if (Arrays.equals(position, this.stiuation[i])) {
					index = i;
					if (i < 2) {
						sum += 100000;// 连5棋型
						if (color == 1) {
							if (i == 0) {
								sum += 10000000;// 我方胜利加分
							}
						} else {
							if (i == 1) {
								sum += 10000000;// 我方胜利加分
							}
						}
					} else if (i < 6) {
						sum += 10000;// 活4棋型
						if(color==1){
							if(i<=3){
								sum+=50000;//我方先连4子加分
							}
						}else{
							if(i>3){
								sum+=50000;//我方先连4子加分
							}
						}
					} else if (i < 10) {
						sum += 5000;// 眠4棋型
					} else if (i < 16) {
						sum += 1000;// 活3棋型
						if(color==1){
							if(i<=12){
								sum+=3000;//我方先连3子加分
							}
						}else{
							if(i>12){
								sum+=3000;//我方先连3子加分
							}
						}
					} else if (i < 28) {
						sum += 500;// 眠3棋型
					} else if (i < 32) {
						sum += 100;// 活2棋型
					} else {
						sum += 50;// 眠2棋型
					}
				}
			}
			if (index < 0) {
				sum += 1;// 其它情况
			}
			return sum;
		}
		// 评分标准2
			private int calculate2(int[] position) {
				int sum = 0;
				for (int i = 0; i < this.stiuation2.length; i++) {
					if (Arrays.equals(position, this.stiuation2[i])) {
						if (i < 2) {
							
							sum += 100000;// 连5棋型
							if (color == 1) {
								if (i == 0) {
									sum += 10000000;// 一子定胜负加分
								}
							} else {
								if (i == 1) {
									sum += 10000000;// 一子定胜负加分
								}
							}
						} else if (i < 4) {
							sum += 10000;// 活4棋型
							if(color==1){
								if(i==2){
									sum+=50000;//我方先连4子加分
								}
							}else{
								if(i==3){
									sum+=50000;//我方先连4子加分
								}
							}
						} else if (i < 6) {
							sum += 5000;// 眠4棋型
						} else if (i < 12) {
							sum += 1000;// 活3棋型
							if(color==1){
								if(i<=8){
									sum+=3000;//我方先连3子加分
								}
							}else{
								if(i>8){
									sum+=3000;//我方先连3子加分
								}
							}
						} else {
							sum += 500;// 眠3棋型
						}
					}
				}
				return sum;
			}

		// 左右方向评分
		private int mark1(int x, int y) {
			int[] position = new int[4];
			if (x - 2 >= 0) {
				position[0] = this.chessboard[x - 2][y];
			} else {
				position[0] = 0;
			}
			if (x - 1 >= 0) {
				position[1] = this.chessboard[x - 1][y];
			} else {
				position[1] = 0;
			}
			if (x + 1 < this.chessboard.length) {
				position[2] = this.chessboard[x + 1][y];
			} else {
				position[2] = 0;
			}
			if (x + 2 < this.chessboard.length) {
				position[3] = this.chessboard[x + 2][y];
			} else {
				position[3] = 0;
			}
			int sum = 0;
			sum += calculate(position);
			return sum;
		}

		// 上下方向评分
		private int mark2(int x, int y) {
			int[] position = new int[4];
			if (y - 2 >= 0) {
				position[0] = this.chessboard[x][y - 2];
			} else {
				position[0] = 0;
			}
			if (y - 1 >= 0) {
				position[1] = this.chessboard[x][y - 1];
			} else {
				position[1] = 0;
			}
			if (y + 1 < this.chessboard.length) {
				position[2] = this.chessboard[x][y + 1];
			} else {
				position[2] = 0;
			}
			if (y + 2 < this.chessboard.length) {
				position[3] = this.chessboard[x][y + 2];
			} else {
				position[3] = 0;
			}
			int sum = 0;
			sum += calculate(position);
			return sum;
		}

		// 主对角线方向评分
		private int mark3(int x, int y) {
			int[] position = new int[4];
			if (x - 2 >= 0 && y - 2 >= 0) {
				position[0] = this.chessboard[x - 2][y - 2];
			} else {
				position[0] = 0;
			}
			if (x - 1 >= 0 && y - 1 >= 0) {
				position[1] = this.chessboard[x - 1][y - 1];
			} else {
				position[1] = 0;
			}
			if (x + 1 < this.chessboard.length && y + 1 < this.chessboard.length) {
				position[2] = this.chessboard[x + 1][y + 1];
			} else {
				position[2] = 0;
			}
			if (x + 2 < this.chessboard.length && y + 2 < this.chessboard.length) {
				position[3] = this.chessboard[x + 2][y + 2];
			} else {
				position[3] = 0;
			}
			int sum = 0;
			sum += calculate(position);
			return sum;
		}

		// 副对角线方向评分
		private int mark4(int x, int y) {
			int[] position = new int[4];
			if (x - 2 >= 0 && y + 2 < this.chessboard.length) {
				position[0] = this.chessboard[x - 2][y + 2];
			} else {
				position[0] = 0;
			}
			if (x - 1 >= 0 && y + 1 < this.chessboard.length) {
				position[1] = this.chessboard[x - 1][y + 1];
			} else {
				position[1] = 0;
			}
			if (x + 1 < this.chessboard.length && y - 1 >= 0) {
				position[2] = this.chessboard[x + 1][y - 1];
			} else {
				position[2] = 0;
			}
			if (x + 2 < this.chessboard.length && y - 2 >= 0) {
				position[3] = this.chessboard[x + 2][y - 2];
			} else {
				position[3] = 0;
			}
			int sum = 0;
			sum += calculate(position);
			return sum;
		}

		
		// 八个方向评分
		private int mark5(int x, int y) {
			int sum = 0;
			int[] position = new int[4];
			// 上方向
			if (x - 1 >= 0) {
				position[0] = this.chessboard[x - 1][y];
			} else {
				position[0] = 0;
			}
			if (x - 2 >= 0) {
				position[1] = this.chessboard[x - 2][y];
			} else {
				position[1] = 0;
			}
			if (x - 3 >= 0) {
				position[2] = this.chessboard[x - 3][y];
			} else {
				position[2] = 0;
			}
			if (x - 4 >= 0) {
				position[3] = this.chessboard[x - 4][y];
			} else {
				position[3] = 0;
			}
			sum += calculate2(position);
			// 下方向
			if (x + 1 < this.chessboard.length) {
				position[0] = this.chessboard[x + 1][y];
			} else {
				position[0] = 0;
			}
			if (x + 2 < this.chessboard.length) {
				position[1] = this.chessboard[x + 2][y];
			} else {
				position[1] = 0;
			}
			if (x + 3 < this.chessboard.length) {
				position[2] = this.chessboard[x + 3][y];
			} else {
				position[2] = 0;
			}
			if (x + 4 < this.chessboard.length) {
				position[3] = this.chessboard[x + 4][y];
			} else {
				position[3] = 0;
			}
			sum += calculate2(position);
			// 左方向
			if (y - 1 >= 0) {
				position[0] = this.chessboard[x][y - 1];
			} else {
				position[0] = 0;
			}
			if (y - 2 >= 0) {
				position[1] = this.chessboard[x][y - 2];
			} else {
				position[1] = 0;
			}
			if (y - 3 >= 0) {
				position[2] = this.chessboard[x][y - 3];
			} else {
				position[2] = 0;
			}
			if (y - 4 >= 0) {
				position[3] = this.chessboard[x][y - 4];
			} else {
				position[3] = 0;
			}
			sum += calculate2(position);
			// 右方向
			if (y + 1 < this.chessboard.length) {
				position[0] = this.chessboard[x][y + 1];
			} else {
				position[0] = 0;
			}
			if (y + 2 < this.chessboard.length) {
				position[1] = this.chessboard[x][y + 2];
			} else {
				position[1] = 0;
			}
			if (y + 3 < this.chessboard.length) {
				position[2] = this.chessboard[x][y + 3];
			} else {
				position[2] = 0;
			}
			if (y + 4 < this.chessboard.length) {
				position[3] = this.chessboard[x][y + 4];
			} else {
				position[3] = 0;
			}
			sum += calculate2(position);
			// 左斜上方向
			if (x - 1 >= 0 && y - 1 >= 0) {
				position[0] = this.chessboard[x - 1][y - 1];
			} else {
				position[0] = 0;
			}
			if (x - 2 >= 0 && y - 2 >= 0) {
				position[1] = this.chessboard[x - 2][y - 2];
			} else {
				position[1] = 0;
			}
			if (x - 3 >= 0 && y - 3 >= 0) {
				position[2] = this.chessboard[x - 3][y - 3];
			} else {
				position[2] = 0;
			}
			if (x - 4 >= 0 && y - 4 >= 0) {
				position[3] = this.chessboard[x - 4][y - 4];
			} else {
				position[3] = 0;
			}
			sum += calculate2(position);
			// 左斜下方向
			if (x + 1 < this.chessboard.length && y + 1 < this.chessboard.length) {
				position[0] = this.chessboard[x + 1][y + 1];
			} else {
				position[0] = 0;
			}
			if (x + 2 < this.chessboard.length && y + 2 < this.chessboard.length) {
				position[1] = this.chessboard[x + 2][y + 2];
			} else {
				position[1] = 0;
			}
			if (x + 3 < this.chessboard.length && y + 3 < this.chessboard.length) {
				position[2] = this.chessboard[x + 3][y + 3];
			} else {
				position[2] = 0;
			}
			if (x + 4 < this.chessboard.length && y + 4 < this.chessboard.length) {
				position[3] = this.chessboard[x + 4][y + 4];
			} else {
				position[3] = 0;
			}
			sum += calculate2(position);
			// 右斜上方向
			if (x - 1 >= 0 && y + 1 < this.chessboard.length) {
				position[0] = this.chessboard[x - 1][y + 1];
			} else {
				position[0] = 0;
			}
			if (x - 2 >= 0 && y + 2 < this.chessboard.length) {
				position[1] = this.chessboard[x - 2][y + 2];
			} else {
				position[1] = 0;
			}
			if (x - 3 >= 0 && y + 3 < this.chessboard.length) {
				position[2] = this.chessboard[x - 3][y + 3];
			} else {
				position[2] = 0;
			}
			if (x - 4 >= 0 && y + 4 < this.chessboard.length) {
				position[3] = this.chessboard[x - 4][y + 4];
			} else {
				position[3] = 0;
			}
			sum += calculate2(position);
			// 右斜下
			if (x + 1 < this.chessboard.length && y - 1 >= 0) {
				position[0] = this.chessboard[x + 1][y - 1];
			} else {
				position[0] = 0;
			}
			if (x + 2 < this.chessboard.length && y - 2 >= 0) {
				position[1] = this.chessboard[x + 2][y - 2];
			} else {
				position[1] = 0;
			}
			if (x + 3 < this.chessboard.length && y - 3 >= 0) {
				position[2] = this.chessboard[x + 3][y - 3];
			} else {
				position[2] = 0;
			}
			if (x + 4 < this.chessboard.length && y - 4 >= 0) {
				position[3] = this.chessboard[x + 4][y - 4];
			} else {
				position[3] = 0;
			}
			sum += calculate2(position);
			return sum;
		}
	//打印棋盘
	public void print() {
	
		for (int i = 0; i < chessboard.length; i++) {
			for (int j = 0; j < chessboard.length; j++) {
				System.out.print(this.chessboard[i][j]+"  ");
			}
			System.out.println();
		}
	}
	//判断输赢
	public Boolean isWin(int x,int y) {
		return false;
	}
	
	//判断棋盘是否满了
	public Boolean isFull() {
		int judge=1;
		for (int i = 0; i < chessboard.length; i++) {
			for (int j = 0; j < chessboard.length; j++) {
				if(this.chessboard[i][j]==0) {
					judge=0;
				}
			}
		}
		return judge==1?true:false;
		
	}
}

3、创建测试类,代码如下:

package chess;

import java.util.Scanner;

public class chessTest {

	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		chess ch=new chess();
		System.out.println("请输入棋盘大小n(n行n列):");
		int size=sc.nextInt();
	    ch.setGame(size,2);
	    ch.print();
        while (true) {
			System.out.println("请输入你想下的位置");
			int x=sc.nextInt();
			int y=sc.nextInt();
			ch.getMove(x, y);
		}
	}

}

测试结果图:
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
算法大概就是这样子了,算法很简单,效果差强人意吧。
PS:后面发现chess类里面有个判断胜负的方法没写,也懒得补上了(就循环判断,很简单,就是耗点时间),希望大家不会介意。

以下是一个基于C语言的五子棋蒙特卡洛树搜索(MCTS)示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <time.h> #define BOARD_SIZE 15 #define MAX_PLAYS 225 #define UCB_C 1.96 typedef struct { int x; int y; } Point; typedef struct Node Node; struct Node { int wins; int plays; Point move; Node *parent; Node *children[MAX_PLAYS]; }; typedef struct { int board[BOARD_SIZE][BOARD_SIZE]; int next_player; } GameState; int opposite(int player) { return 3 - player; } int legal_moves(GameState *state, Point moves[]) { int count = 0; for (int x = 0; x < BOARD_SIZE; x++) { for (int y = 0; y < BOARD_SIZE; y++) { if (state->board[x][y] == 0) { moves[count].x = x; moves[count].y = y; count++; } } } return count; } int winner(GameState *state) { int lines[BOARD_SIZE][BOARD_SIZE][5][2] = {{{{0}}}}; int counts[3] = {0}; for (int x = 0; x < BOARD_SIZE; x++) { for (int y = 0; y < BOARD_SIZE; y++) { int p = state->board[x][y]; if (p == 0) { continue; } for (int i = 0; i < 5; i++) { if (x + i < BOARD_SIZE) { lines[x][y][i][0] = state->board[x + i][y]; } if (y + i < BOARD_SIZE) { lines[x][y][i][1] = state->board[x][y + i]; } } counts[p]++; } } if (counts[1] > counts[2] + 1) { return 2; } if (counts[2] > counts[1]) { return 1; } for (int x = 0; x < BOARD_SIZE; x++) { for (int y = 0; y < BOARD_SIZE; y++) { for (int i = 0; i < 5; i++) { int j; for (j = 0; j < 5; j++) { if (lines[x][y][j][0] != (i + j < 5 ? 0 : lines[x + j - i][y][i + j - 5][0])) { break; } } if (j == 5) { return lines[x][y][0][0]; } for (j = 0; j < 5; j++) { if (lines[x][y][j][1] != (i + j < 5 ? 0 : lines[x][y + j - i][i + j - 5][1])) { break; } } if (j == 5) { return lines[x][y][0][1]; } } } } if (counts[1] + counts[2] == BOARD_SIZE * BOARD_SIZE) { return 0; } return -1; } void play_move(GameState *state, Point move) { state->board[move.x][move.y] = state->next_player; state->next_player = opposite(state->next_player); } Node *new_node(Node *parent, Point move) { Node *node = (Node *) malloc(sizeof(Node)); node->wins = 0; node->plays = 0; node->move = move; node->parent = parent; for (int i = 0; i < MAX_PLAYS; i++) { node->children[i] = NULL; } return node; } void free_tree(Node *node) { for (int i = 0; i < MAX_PLAYS; i++) { if (node->children[i] != NULL) { free_tree(node->children[i]); } } free(node); } int random_playout(GameState *state) { GameState *copy = (GameState *) malloc(sizeof(GameState)); *copy = *state; int result = -1; while (result == -1) { Point moves[MAX_PLAYS]; int count = legal_moves(copy, moves); if (count == 0) { break; } Point move = moves[rand() % count]; play_move(copy, move); result = winner(copy); } free(copy); if (result == -1) { return 0; } if (result == 0) { return 1; } return result == 1 ? -1 : 1; } Node *best_child(Node *node) { double best_score = -1; Node *best_child = NULL; for (int i = 0; i < MAX_PLAYS; i++) { Node *child = node->children[i]; if (child == NULL) { continue; } double score = (double) child->wins / child->plays + UCB_C * sqrt(log(node->plays) / child->plays); if (score > best_score) { best_score = score; best_child = child; } } return best_child; } Node *tree_policy(GameState *state, Node *node) { while (winner(state) == -1) { Point moves[MAX_PLAYS]; int count = legal_moves(state, moves); if (count == 0) { break; } int unexplored = 0; for (int i = 0; i < count; i++) { Point move = moves[i]; int found = 0; for (int j = 0; j < MAX_PLAYS; j++) { if (node->children[j] != NULL && node->children[j]->move.x == move.x && node->children[j]->move.y == move.y) { node = node->children[j]; found = 1; break; } } if (!found) { unexplored = 1; break; } } if (unexplored) { Point move = moves[rand() % count]; node->children[node->plays] = new_node(node, move); node = node->children[node->plays]; } else { node = best_child(node); } play_move(state, node->move); node->plays++; } return node; } void backpropagate(Node *node, int result) { while (node != NULL) { node->wins += result; node->plays++; node = node->parent; result = -result; } } Point select_move(GameState *state, int iterations) { Node *root = new_node(NULL, (Point) {0, 0}); root->plays = 1; for (int i = 0; i < iterations; i++) { GameState *copy = (GameState *) malloc(sizeof(GameState)); *copy = *state; Node *node = tree_policy(copy, root); int result = random_playout(copy); backpropagate(node, result); free(copy); } double best_score = -1; Point best_move = (Point) {-1, -1}; for (int i = 0; i < MAX_PLAYS; i++) { Node *child = root->children[i]; if (child == NULL) { continue; } double score = (double) child->wins / child->plays; if (score > best_score) { best_score = score; best_move = child->move; } } free_tree(root); return best_move; } void print_board(GameState *state) { for (int y = 0; y < BOARD_SIZE; y++) { for (int x = 0; x < BOARD_SIZE; x++) { printf("%c", state->board[x][y] == 1 ? 'X' : state->board[x][y] == 2 ? 'O' : '-'); } printf("\n"); } } int main() { srand(time(NULL)); GameState state = {0}; while (winner(&state) == -1) { print_board(&state); if (state.next_player == 1) { Point move; printf("Enter move: "); scanf("%d %d", &move.x, &move.y); play_move(&state, move); } else { Point move = select_move(&state, 10000); printf("Computer plays: %d %d\n", move.x, move.y); play_move(&state, move); } } print_board(&state); int w = winner(&state); printf("%s wins\n", w == 0 ? "Draw" : w == 1 ? "X" : "O"); return 0; } ``` 该示例代码实现了五子棋蒙特卡洛树搜索,包括游戏状态表示、棋盘的打印、对局的进行(玩家输入和AI自动选择)、胜负判断等功能。其核心是通过蒙特卡洛树搜索来选择AI的下一步棋子位置,具体实现包括: - `new_node`:创建一个新的节点。 - `legal_moves`:获取当前状态下所有合的落子位置。 - `winner`:判断当前状态下的胜负情况。 - `play_move`:在当前状态下落子。 - `random_playout`:执行一次随机模拟,返回胜负结果。 - `best_child`:找到当前节点中最优的子节点。 - `tree_policy`:根据当前状态和节点,选择下一个要扩展的节点,并返回最终的节点。 - `backpropagate`:在树中回溯更新节点的胜负统计信息。 - `select_move`:根据当前状态,执行多次蒙特卡洛树搜索,返回AI的落子位置。 该示例代码使用了UCB算法来计算节点选择的得分,即使用节点的胜率和置信度上限来决定节点的优先级。经过大量的模拟对局,蒙特卡洛树搜索可以搜索到更深的状态空间,从而提高AI的胜率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值