五子棋人机
来源:互联网 发布:帝国文明源码下载 编辑:程序博客网 时间:2024/05/07 18:22
权值法是个什么玩意呢?其实他是基于枚举的暴力的方法。之前说过五子棋的棋盘是15*15的。并且赢得情况是5个相同的棋子连成一块,那么大家就可以想到,我们能枚举出所有赢得情况,大约几千种,在我们看来这个数字比较大,但是对于一秒就可以处理数量级到8的计算机来说,小case是不是?那么有了这个理解我们就可以实现两个表,分别是机器和人的胜利表,也就是储存赢得情况的表,那么有了这个表,最终机器决定下棋是要通过权值判断的,至于权值怎么来,先不用管,我们也要用两个表分别储存机器和人的权值的表,贴出代码:
- private GoBangPanel panel;
- private Graphics2D g;
- private int num;
- private Judge j;
- public class struct
- {
- int last;
- //计算x,y坐标
- int[] x = newint[5];
- int[] y = newint[5];
- //记录每个取胜表的棋子相连的情况
- int[] wn = newint[5];
- }
- struct[] winlistp = new struct[800];
- struct[] winlistc = new struct[800];
- int[][] scorep = newint[Row][Coloum];
- int[][] scorec = new int[Row][Coloum];
理解了winlist的作用,我们就来说一下score的作用,他就是储存权值的表,每次遍历查找出黑棋和白棋的权值的最大值,我们领白棋是计算机,黑棋是人,那么如果权值最大的就是白棋那么就体现了进攻,如果是黑棋就体现的防守,因为我们现在所说的是针对计算机的,因为我们编这套程序是为了让计算机知道怎么下棋。
怎么计算权值呢?我们先不跳着讲,先看看winlist怎么初始化和更新,初始化就是把所有赢的情况全部储存嘛,贴出代码:
- public GoBangAn(GoBangPanel panel)
- {
- //初始化黑棋和白棋各自的评分
- for(int i =0; i < Row; i++)
- {
- for(int j =0; j < Coloum; j++)
- {
- scorep[i][j] = 0;
- scorec[i][j] = 0;
- }
- }
- //初始化黑棋和白棋数组的各个元素
- for(int i =0; i < 800; i++)
- {
- winlistp[i] = new struct();
- winlistc[i] = new struct();
- }
- this.panel = panel;
- g = (Graphics2D)this.panel.getGraphics();
- num = 0;
- //枚举各种情况(有4个大方向)
- //分别计算人和计算机行的赢的情况
- for(int i =0; i < Row; i++)
- {
- for(int j =0; j < 11; j++)
- {
- for(int k = j; k < j+5; k++)
- {
- winlistp[num].x[k-j] = i;
- winlistp[num].y[k-j] = k;
- winlistc[num].x[k-j] = i;
- winlistc[num].y[k-j] = k;
- winlistp[num].last = 0;
- winlistp[num].wn[k-j] = 0;
- winlistc[num].last = 0;
- winlistc[num].wn[k-j] = 0;
- }
- num++;
- }
- }
- //分别计算人和计算机列的赢的情况
- for(int i =0; i < Coloum; i++)
- {
- for(int j =0; j < 11; j++)
- {
- for(int k = j; k < j+5; k++)
- {
- winlistp[num].x[k-j] = k;
- winlistp[num].y[k-j] = i;
- winlistc[num].x[k-j] = k;
- winlistc[num].y[k-j] = i;
- winlistp[num].last = 0;
- winlistp[num].wn[k-j] = 0;
- winlistc[num].last = 0;
- winlistc[num].wn[k-j] = 0;
- }
- num++;
- }
- }
- //分别计算人和计算机右上对角线赢的情况
- for(int i =1; i < 11; i++)
- {
- for(int x = i,y =0; x < 11; x++,y++)
- {
- for(int kx = x,ky = y; kx < x+5; kx++,ky++)
- {
- winlistp[num].x[kx-x] = ky;
- winlistp[num].y[kx-x] = kx;
- winlistc[num].x[kx-x] = ky;
- winlistc[num].y[kx-x] = kx;
- winlistp[num].last = 0;
- winlistp[num].wn[kx-x] = 0;
- winlistc[num].last = 0;
- winlistc[num].wn[kx-x] = 0;
- }
- num++;;
- }
- }
- //分别计算人和计算机左下对角线的情况
- for(int i =1; i < 11; i++)
- {
- for(int y = i,x =0; y < 11; y++,x++)
- {
- for(int kx = x,ky =y; ky < y+5; kx++,ky++)
- {
- winlistp[num].x[kx-x] = ky;
- winlistp[num].y[kx-x] = kx;
- winlistc[num].x[kx-x] = ky;
- winlistc[num].y[kx-x] = kx;
- winlistp[num].last = 0;
- winlistp[num].wn[kx-x] = 0;
- winlistc[num].last = 0;
- winlistc[num].wn[kx-x] = 0;
- }
- num++;
- }
- }
因为代码很长但是不难,所以就贴出一部分,大家懂了之后剩下的代码自己补上绝对不是问题。看一下代码应该清楚,枚举所有赢的情况。分别是横着的方向和竖着的方向以及两个斜着的方向,这样就可以通过for循环直接全部初始化。score数组的初始化当然是0啦。
那么怎么更新winlist数组呢,很简单,假如更新白棋,那么就遍历棋盘找黑棋的位置,然后遍历winlist表,看看这个黑棋的坐标被哪些情况包含了,那么这个情况就无效了,贴出代码:
- //分别更新人和计算机的取胜表的情况
- public void update(int sitx,int sity)
- {
- if(array[sitx][sity]%2 ==0)
- {
- for(int i =0; i < num; i++)
- {
- if(winlistp[i].last == 0)
- {
- for(int j =0; j < 5; j++)
- {
- if((winlistp[i].x[j] == sitx) && (winlistp[i].y[j] == sity))
- {
- winlistp[i].last = 1;
- break;
- }
- }
- }
- if(winlistc[i].last == 0)
- {
- for(int j =0; j < 5; j++)
- {
- if((winlistc[i].x[j] == sitx) && (winlistc[i].y[j] == sity))
- {
- winlistc[i].wn[j] = 1;
- break;
- }
- }
- }
- }
- }else
- {
- for(int i =0; i < num; i++)
- {
- if(winlistc[i].last == 0)
- {
- for(int j =0; j < 5; j++)
- {
- if((winlistc[i].x[j] == sitx) && (winlistc[i].y[j] == sity))
- {
- winlistc[i].last = 1;
- }
- }
- }
- if(winlistp[i].last == 0)
- {
- for(int j =0; j < 5; j++)
- {
- if((winlistp[i].x[j] == sitx) && (winlistp[i].y[j] == sity))
- {
- winlistp[i].wn[j] = 1;
- }
- }
- }
- }
- }
根据我说的再去看看代码就很简单了是不是?
那么接下来说一下怎么更新score数组,一个很显然的情况就是如果这个坐标被winlist里面的情况包含的越多那么下棋在这个位置的用处就越大。这是一个方面,为什么winlist还有一个wn数组呢,那就是判断是不是3个棋子连在一起了?4个棋子连在一起了??等等。因为是权值,每种情况都要有一定的数值,比如活三就给的大一点,活四直接认输就好了等等,权值怎么给确实很大的影响结果,自己到现在也没有找到很好的分配方式。这个怎么给大家自己决定吧,剩下的我就不多说了,每次更行权值列表,挑出最大的位置下棋就好了,不过因为把所有的情况都考虑了,之前有一个人说过,如果计算机先手不能保证赢但是能保证不输。哈哈哈不过我没有实现的这个程度,还是要加强的。那五子棋就讲到这里了。
- 五子棋人机
- 人机对战五子棋
- 五子棋人机对弈
- 人机简单五子棋!
- canvas简易人机五子棋
- 五子棋(人机)-只算杀棋
- 【java】五子棋人机对弈
- 五子棋 人机对弈
- 五子棋人机对战思想
- 人工智能 - 五子棋人机对战
- 五子棋人机对战详解;
- 人工智能 - 五子棋人机对战
- 五子棋 人人加人机对弈
- JavaScript实现简单人机五子棋
- 人工智能 - 五子棋人机对战
- 五子棋人机对战设计
- [原创]五子棋人机对弈算法设计
- 五子棋人机互弈代码 C
- XListView实现上拉加载下拉刷新,注意事项
- java.util.concurrent.locks
- rs.next()
- Android ffmpeg 3.4 JNI移植 NDK编译播放 ffserver 推送的 Rtsp 视频流
- 【学习贴】Ps终极动画练习
- 五子棋人机
- Python3-搭建Django框架
- windows 2003系统下邮件系统搭建
- Flume安装-配置-调试
- workerman中使用aes加密
- MyBatis Mapper XML 符号处理
- c#反射中GetMethods()和GetCustomAttributes()方法
- nmap核心结构概述
- 几十部以程序员为主角的影片