人机版五子棋开发之篇一
到如今,写五子棋也有一段时间了,虽然一开始的人人版并没用多长的时间,但后面的人机对战版可没让人头疼。从对思路的一无所知(在此感谢陆亮小盆友 的“精心”指导,呵呵)到了解算法的大概思想,再到真正实现过程中遇到的问题,一路走来,最深的体悟就是,有些错误是想出来而难的调试出来的,而且此种想问题的方法不是对着电脑看着代码想,那样会让人睡觉并且只会感到强烈的挫折感,而是在一个人路上想,去吃饭,去上自习,说不定哪个时候灵光一乍现,突然就发现症结所在了。可惜,经本人不怎么灵泛的大脑,找出问题重见蓝天的同时发现花儿早就谢了,因此也就没有了那种见到新鲜事物时的兴奋激动,唯有的是走出迷雾后的释然。但不管怎么说,现在总算是把那纠结的人机对战五子棋大体完工了。有图有真相,也让自己的思路进入正题。呵呵。
总体来说,它应该算有三岁小孩的智商,会守会攻,而且以攻为主,虽然这攻守都不怎么高级,但一不小心你也是会输的,呵呵。
废话讲了许多,下面进入正题,给这一五子棋来个阶段性的总结:
首先,算法思路:
并没有用到贪心法系统的算法策略,而只是自创的暴力型算法。
首先提供数据结构:一个棋盘二维数组,初始值全为0.用1代表下的黑子,-1代表下的白字。没下一颗子,相应位置上的值改变。 两个权值数组,分别记录玩家的当前棋盘和电脑的当前棋盘。用权值代表该位置的重要性,每放一个棋子,权值数组都重新赋值。
其次就是权值的设置问题,四连的权值最大,其次是活三连,再活二连等等。这里情况分的越细越好,但对本人这类菜鸟,情况越多会把问题搞的越复杂,因此也就作罢。只分了最简单的几种情况:四连,三连,二连,单个子,其中,三连二连每种情况又分双边活和单边活,因此也就六种不同的权值。
最后关键就是找到最大的权值点了。我的思路是,在玩家权值数组中找到权值最大的点,在电脑权值数组中也找到最大的点,再两个比较,谁大电脑就下子在那个权值大的位置。
接下来的问题就是每个权值数组中权值最大点怎么找了。其实无非也就是多次的用两个循环遍历二维数组,在每个点上做四个方向上的判断,求得每个方向上有几个相同 的子,并用四个变量做暂时记录,然后比较这四个变量,在权值数组中赋上这最多棋子个数对应的权值。
代码如下:
else {//人机对战System.out.println(MenuJPanel.jc.getSelectedItem());if(chesses[i][j]==0) {//当前无子时才能放g.setColor(Color.black);//玩家下黑子g.fillOval(x - CHESS_SIZE / 2, y - CHESS_SIZE / 2,CHESS_SIZE, CHESS_SIZE);//下子之后该点权值赋值为1chesses[i][j]=-1;//电脑找权值最大的点放子g.setColor(Color.white);//遍历两棋盘 new MaxValue(VALUES_PALYER).lookforMaxValue(-1);//黑子为-1 new MaxValue(VALUES_COM).lookforMaxValue(1);//白字为1/在两个权值数组中找最大权值的点MaxValuep=getMAXVALUE(VALUES_PALYER);MaxValuec=getMAXVALUE(VALUES_COM);if(VALUES_PALYER[MaxValuep.y][MaxValuep.x]<=VALUES_COM[MaxValuec.y][MaxValuec.x]) {//进攻Max=MaxValuec;}else {//防守Max=MaxValuep;}int xx = X0+Max.x*SIZE;int yy = Y0+Max.y*SIZE;//最大权值坐在点的坐标(由下标转化而来)chesses[Max.y][Max.x]=1;g.fillOval(xx - CHESS_SIZE / 2, yy - CHESS_SIZE / 2,CHESS_SIZE, CHESS_SIZE);
for(int i=0;i<ROWS;i++ ) {for(int j=0;j<COLUMNS;j++) {//给空白处的点赋值if(chesses[i][j]==0) {//System.out.println(chesses[i++][j]);//System.out.println("开始"+ count++);m=i;n=j;num[0]=num[1]=num[2]=num[3]=0;vacant[0]=vacant[1]=vacant[2]=vacant[3]=0;//横向向右while(n<COLUMNS-1&&chesses[m][++n]==color) { num[0]++; if(n<COLUMNS-1&&chesses[m][n+1]==0) vacant[0]++;} if(j>0&&chesses[i][j-1]==0) vacant[0]++; n=j;//横向向左while(n>0&&chesses[m][--n]==color) {num[0]++;if(n>0&&chesses[m][n-1]==0) vacant[0]++; }if(j<COLUMNS-1&&chesses[i][j+1]==0) vacant[0]++;n=j;//纵向向下while(m<ROWS-1&&chesses[++m][n]==color) {num[1]++; if(m<ROWS-1&&chesses[m+1][n]==0) vacant[1]++;}if(i>0&&chesses[i-1][j]==0) vacant[1]++;m=i;//纵向向上 while(m>0&&chesses[--m][n]==color) { num[1]++; if(m>0&&chesses[m-1][n]==0) vacant[1]++;}if(i<ROWS-1&&chesses[i+1][j]==0) vacant[1]++;m=i; //斜向左下while(n>0&&m<ROWS-1&&chesses[++m][--n]==color) { num[2]++;if(m<ROWS-1&&n>0&&chesses[m+1][n-1]==0) vacant[2]++;}if(i>0&&j<ROWS-1&&chesses[i-1][j+1]==0) vacant[2]++;m=i;n=j;//斜向右上while(n<COLUMNS-1&&m>0&&chesses[--m][++n]==color) { num[2]++; if(m>0&&n<COLUMNS-1&&chesses[m-1][n+1]==0) vacant[2]++;}if(i<ROWS-1&&j>0&&chesses[i+1][j-1]==0) vacant[2]++;m=i;n=j; //斜向右下 while(m<ROWS-1&&n<COLUMNS-1&&chesses[++m][++n]==color) {num[3]++;if(m<ROWS-1&&n<COLUMNS-1&&chesses[m+1][n+1]==0) vacant[3]++;}if(i>0&&j>0&&chesses[i-1][j-1]==0) vacant[3]++;m=i;n=j;//斜向左上while(m>0&&n>0&&chesses[--m][--n]==color) {num[3]++;if(m>0&&n>0&&chesses[m-1][n-1]==0) vacant[3]++;}if(i<ROWS-1&&j<COLUMNS-1&&chesses[i+1][j+1]==0) vacant[3]++; m=i;n=j;int max = num[0];int temp=0;//找出有相同棋子最多的边,并给该位置赋权值for(int q=0;q<4;q++ ){if(max<num[q]) {max=num[q];temp=q;}}//给该点设置权值setValue(values,max,vacant[temp],i,j);}
public void setValue(int values[][],int num,int vacant,int i,int j) {if(num==1) {//一连if(vacant==1) {//一活values[i][j]=100;} else if(vacant==2) {//两活values[i][j]=500;} }else if(num==2) {if(vacant==1) {//一活values[i][j]= 200;}else if(vacant==2) {//两活values[i][j]=2400;} }else if(num==3) {if(vacant==1) {//一活values[i][j]=1000;}else if(vacant==2) {//两活values[i][j]=5000;} }else if(num==4) {values[i][j]=10000; }else {values[i][j]=0; }}
//在两个权值数组中找最大权值public Point getMAXVALUE(int values[][]) {Point max = new Point();max.x = 0;max.y = 0;for(int i=0;i<ROWS;i++) {for(int j=0;j<COLUMNS;j++) {if(values[max.y][max.x]<values[i][j]) {max.y = i;max.x = j;}}}return max;}
//添加棋盘chessboard = new ChessJPanel();//得到画布对象g = chessboard.getGraphics();chesslistener = new ChessListener(g,this);//添加监听器public void addListener() {chessboard.addMouseListener(chesslistener);}