曙光V1_3


                                                 是机器的力量,还是人类的智慧

                                                                               ---分享总结第一个机器学习程序

       宛如婴儿来世的第一声啼哭,今天第一个可以称为智能AI的五子棋程序(曙光)诞生了。就像钢琴家赋予每个美丽的音符跳动的生命,程序员用代码构筑了一个梦幻的世界。不得不说这种让冷冰冰的代码让它在自己手中变得鲜活,富有生气,甚至还有点灵性,这种感觉实在是妙不可言。

        编写一个具有学习能力的程序的想法从去年就有了,具体可以参照2013年10月6日我发的那篇博客。为了完成编写一个打败熊哥的五子棋,一个具有学习能力的五子棋就是必须的。当时我就萌生了两个想法,机器学习就是其中一个,另一种博弈树是由于当时能力不足,我就只做了一个简单的博弈树。好了废话不多说。下面进入正题。

        为了完成一个具有学习能力的五子棋,我们首先需要一些模块。

        1.一个可以判断输赢的五子棋的主程序。(最好具有一定的AI)

        2.每下一步棋数据的采集和存储。

        3.文件的写入还有文件的读出。

        4.对文件数据信息的处理与分析程序。

好了有了这些模块我们就可以写一个具有学习功能的五子棋程序了,具体流程图如下:

大家看到这个图后是不是觉得。切~ 这么简单,不就是文件的读写吗。嗯。其实我想说的是思路就是这么简单,丝毫没有一点高大上的东西。好了下面就让我从头开始讲解代码的编写了。这里才是重点,大家看好咯。

首先介绍一下整个算法的核心我们的棋谱

代码如下

package GobongV1_3;

@SuppressWarnings("serial")
public class Board implements java.io.Serializable {

	private int board[][];

	public Board(int[][] board) {
		this.board = board;
	}

	public int[][] getBoard() {
		return board;
	}

	public void setBoard(int[][] board) {
		this.board = board;
	}

}

我相信各位看官看到这,一定会满头雾水,不就是个序列化的数组吗,有啥好神奇的。没错我们的核心就是一个序列化的数组,别看它麻雀虽小可是五脏俱全,它所包含的信息已经足够我们折腾了。如果是说相声,这时候捧眼一定就会问,“我们下棋不是需要这些信息:第几步?黑棋还是白棋?它的X,Y坐标。这样才对嘛”。“不错问的好”,这是我就好展开我的思路和算法核心了,“我想反问一句,如果先手下棋,最后赢棋,棋盘上是不是有奇数个棋,如果后手下棋,后手赢棋盘上是不是只有偶数个棋子,当电脑先手时,每次玩家落子对棋盘进行遍历,如果有偶数个棋子,我们就让它匹配先手会赢的棋谱(输出的棋谱根据棋子个数自动分类),反之亦然。所以管它是什么黑棋和白棋赢了就是好奇。所以我们只需要第几步?和XY坐标就行了”。

这里是选择部分的核心算法

if (getchessNO() % 2 == 1// 人先下
	&& getCount(chessmanual.get(k)) % 2 == 0 // 后手方赢
	|| getchessNO() % 2 == 0// 电脑先下
	&& getCount(chessmanual.get(k)) % 2 == 1// 先手方赢
)

 知道了核心算法接下来就好说了,先给大家看两张喜闻乐见的流程图

这是存入信息的流程图

 

 

 核心代码如下

public static void addBoard(Board board) {
		ArrayList<Board> b = readFile();//将原来的文件数据读取出来
		if (b == null) {
			b = new ArrayList<Board>();
		}
		b.add(board);//将新的棋谱写入序列
		saveFile(b);//再次将文件读出
	}

 读出信息的流程图



 核心代码如下

读取棋盘

// 读取文件中的数组,将其添加到chessmanual中进行匹配
	public void toArray() {
		ArrayList<Board> step = FileOperation.readFile();
		if (step == null)
			return;
		for (int i = 0; i < step.size(); i++) {
			Board b = step.get(i);
			int array[][] = b.getBoard();
			chessmanual.add(array);
			array = mirsym(array);
			chessmanual.add(array);
			array = horsym(array);
			chessmanual.add(array);
			array = mirsym(array);
			chessmanual.add(array);
			array = versym(array);
			chessmanual.add(array);
			array = mirsym(array);
			chessmanual.add(array);
			array = horsym(array);
			chessmanual.add(array);
			array = mirsym(array);
			chessmanual.add(array);
		}
	}

 这里说明一下,因为五子棋具有极强的对称性,所以我们录入一个棋盘我们可以通过镜像变换,对称变换,得到实际上8个棋谱。感觉是不是很神奇呢?

变换代码如下

// 水平对称
	public int[][] horsym(int[][] array) {
		int[][] temp = new int[N][N];
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < N; j++) {
				temp[i][j] = array[N - 1 - i][j];
			}
		}
		return temp;
	}

	// 垂直对称
	public int[][] versym(int[][] array) {
		int[][] temp = new int[N][N];
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < N; j++) {
				temp[i][j] = array[i][N - 1 - j];
			}
		}
		return temp;
	}

	// 镜像对称
	public int[][] mirsym(int[][] array) {
		int[][] temp = new int[N][N];
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < N; j++) {
				temp[j][i] = array[i][j];
			}
		}
		return temp;
	}

匹配棋盘的核心算法

// 返回是棋盘是否成功
	public boolean pipeiqipan() {
		// 得到棋谱
		for (int k = 0; k < chessmanual.size(); k++) {
			int count = 0;// 计数器
			// 匹配棋谱
			for (int i = 0; i < 15; i++)
				for (int j = 0; j < 15; j++) {
					if (getchessNO() % 2 == 1// 人先下
						&& getCount(chessmanual.get(k)) % 2 == 0 // 后手方赢
						|| getchessNO() % 2 == 0// 电脑先下
						&& getCount(chessmanual.get(k)) % 2 == 1// 先手方赢
					)
						if (data.BOARDSTEP[i][j] != 0
						&& chessmanual.get(k)[i][j] != 0) {
						if (chessmanual.get(k)[i][j] == data.BOARDSTEP[i][j]) {
						count++;

						}
						}
				}
			// 如果步数满足,就按棋谱下
			int step = getchessNO();
			if (count == step) {
				for (int i = 0; i < 15; i++)
					for (int j = 0; j < 15; j++) {
						if (chessmanual.get(k)[i][j] == (count + 1)) {
							step++;
							data.ARRAY[i][j] = 2;
							data.BOARDSTEP[i][j] = step;
							chessboard.appendText("黑:横 " + (i+1) + " 竖 " + (j+1)
									+ " 步数 " + data.BOARDSTEP[i][j]);
						}
					}
				return true;
			}
		}
		return false;
	}

总结:这次我讲了整个机器学习(五子棋板块)的算法核心,还有流程图。基本上可以给大家提供一个很好的思路;本次程序依旧还有不足,例如,电脑下棋只能下在(8,8)这个点,当人第一步不下在(8,8)这个点,录入的棋谱就是无效数据。还有录入棋谱只能是人工,没有实现机器之间的对战,以便快速得到大量的数据。 

最后,还要感谢我的队友 昊神,其中一半的功劳应该归它。

猜你喜欢

转载自xuyi1994.iteye.com/blog/2059271