参考博客:https://www.cnblogs.com/songdechiu/p/5768999.html
一、五子棋棋型分析
参考:http://game.onegreen.net/wzq/HTML/142336.html
最常见的基本棋型大体有以下几种:连五,活四,冲四,活三,眠三,活二,眠二。
①连五:顾名思义,五颗同色棋子连在一起,不需要多讲。
②活四:有两个连五点(即有两个点可以形成五),图中白点即为连五点。
稍微思考一下就能发现活四出现的时候,如果对方单纯过来防守的话,是已经无法阻止自己连五了。
③冲四:有一个连五点
如下面三图,均为冲四棋型。图中白点为连五点。
相对比活四来说,冲四的威胁性就小了很多,因为这个时候,对方只要跟着防守在那个唯一的连五点上,冲四就没法形成连五。
④活三:可以形成活四的三
如下图,代表两种最基本的活三棋型。图中白点为活四点。
活三棋型是我们进攻中最常见的一种,因为活三之后,如果对方不以理会,将可以下一手将活三变成活四,而我们知道活四是已经无法单纯防守住了。所以,当我们面对活三的时候,需要非常谨慎对待。在自己没有更好的进攻手段的情况下,需要对其进行防守,以防止其形成可怕的活四棋型。
其中图2-7中间跳着一格的活三,也可以叫做跳活三。
⑤眠三:只能够形成冲四的三
如下各图,分别代表最基础的六种眠三形状。图中白点代表冲四点。眠三的棋型与活三的棋型相比,危险系数下降不少,因为眠三棋型即使不去防守,下一手它也只能形成冲四,而对于单纯的冲四棋型,我们知道,是可以防守住的。
如上所示,眠三的形状是很丰富的。对于初学者,在下棋过程中,很容易忽略不常见的眠三形状,例如图2-13所示的眠三。
有新手学了活三眠三后,会提出疑问,说活三也可以形成冲四啊,那岂不是也可以叫眠三?
会提出这个问题,说明对眠三定义看得不够仔细:眠三的的定义是,只能够形成冲四的三。而活三可以形成眠三,但也能够形成活四。
此外,在五子棋中,活四棋型比冲四棋型具有更大的优势,所以,我们在既能够形成活四又能够形成冲四时,会选择形成活四。
⑥活二:能够形成活三的二
如下图,是三种基本的活二棋型。图中白点为活三点。
活二棋型看起来似乎很无害,因为他下一手棋才能形成活三,等形成活三,我们再防守也不迟。但其实活二棋型是非常重要的,尤其是在开局阶段,我们形成较多的活二棋型的话,当我们将活二变成活三时,才能够令自己的活三绵绵不绝微风里,让对手防不胜防。
⑦眠二:能够形成眠三的二
图中四个为最基本的眠二棋型,细心且喜欢思考的同学会根据眠三介绍中的图2-13找到与下列四个基本眠二棋型都不一样的眠二。图中白点为眠三点。
二、五子棋打分机制
打分思路:
- 每次一个棋子,找出棋盘上全部棋子的旁边位置,下图打勾位置
- 把打勾的位置用一个point类的数组target[]保存起来
- 对target[]中的每个棋子评分
- 取target[]中的棋子各个方向的4个棋子,以横向为例(取三角形位置):
- 根据以上得出八个方向的棋子分布,做出评分(属于哪一类)
评分规定:
综合四个方向后:
棋型 | 分数 |
---|---|
成五(five) | +100000分 |
活四/双眠四/眠四活(alive_4/highdie_4>1/highdie_4&alive_3) | +10000分 |
双活三(alive_3>1) | +5000分 |
眠三活三(die_3&alive_3) | +1000分 |
眠四(highdie_4) | +500分 |
低级眠四(die_4) | +400分 |
单活三(alive_3) | +100分 |
跳活三(tiaoalive_3) | +90分 |
双活二(alive_2>1) | +50分 |
活二(alive_2) | +10分 |
低级活二(lowalive_2) | +9分 |
眠三(die_3) | +5分 |
眠二(die_2) | +2分 |
初始值(无威胁的其他情况) | +1分 |
三、附录代码
在上一篇双人五子棋的基础上添加一个AI判断机制,棋盘和判断方法(Check)、重绘函数等都不变 https://blog.csdn.net/qq_36804363/article/details/86733292
分八个方向判断
可归为横纵左斜右斜四个方向,以黑棋子为例(评定黑棋子分数)
- 先用八个函数分别得出八个方向上除了黑色外的棋盘坐标,此时得出的是最靠黑棋子的坐标
- 得出坐标后,再拓展,相当于以上的八个方向拓展到4个,以横向为例,如下图所示
- 再对应各种不同的棋型判断棋子的位置是否符合条件
AIJudge:
package com.GobandAI;
import java.awt.Point;
import com.GobandAI.Checkerboard.Config;
/**
* 判断是否能成5, 如果是机器方的话给予100000分,如果是人方的话给予100000 分;
* 判断是否能成活4或者是双死4或者是死4活3,如果是机器方的话给予10000分,如果是人方的话给予10000分;
* 判断是否已成双活3,如果是机器方的话给予5000分,如果是人方的话给予5000 分;
* 判断是否成死3活3(高级),如果是机器方的话给予1000分,如果是人方的话给予1000 分;
* 判断是否能成死4,如果是机器方的话给予500分,如果是人方的话给予500分;
* 判断是否能成低级死4,如果是机器方的话给予400分,如果是人方的话给予400分;
* 判断是否能成单活3,如果是机器方的话给予100分,如果是人方的话给予100分; 判断是否能成跳活3,如果是机器方的话给予90分,如果是人方的话给予90分;
* 判断是否能成双活2,如果是机器方的话给予50分,如果是人方的话给予50分; 判断是否能成活2,如果是机器方的话给予10分,如果是人方的话给予10分;
* 判断是否能成低级活2,如果是机器方的话给予9分,如果是人方的话给予9分; 判断是否能成死3,如果是机器方的话给予5分,如果是人方的话给予5分;
* 判断是否能成死2,如果是机器方的话给予2分,如果是人方的话给予2分。
* 判断是否其他情况(nothing),如果是机器方的话给予1分,如果是人方的话给予1分。 有棋子,则直接0分
*
* @author mo
*
*/
public class AIjudge {
private int five, alive_4, highdie_4, die_4, alive_3, die_3, alive_2, die_2, lowalive_2, tiaoalive_3;
public void Init() {
five = 0;
alive_4 = 0;
highdie_4 = 0;
die_4 = 0;
alive_3 = 0;
die_3 = 0;
alive_2 = 0;
die_2 = 0;
lowalive_2 = 0;
tiaoalive_3 = 0;
}
public Point getright(int[][] chesses, int x, int y) {// 右
Point count = new Point();
for (int i = x + 1; i < Config.columns; i++) {
if (chesses[i][y] != chesses[x][y]) {
count = new Point(i, y);
// System.out.println("右:"+count);
return count;
}
}
return count;
}
public Point getleft(int[][] chesses, int x, int y) {// 左
Point count = new Point();
for (int i = x - 1; i >= 0; i--) {
if (chesses[i][y] != chesses[x][y]) {
count = new Point(i, y);
return count;
}
}
return count;
}
public Point getup(int[][] chesses, int x, int y) {// 上
Point count = new Point();
for (int i = y; i >= 0; i--) {
if (chesses[x][i] != chesses[x][y]) {
count = new Point(x, i);
return count;
}
}
return count;
}
public Point getdown(int[][] chesses, int x, int y) {// 下
Point count = new Point();
for (int i = y + 1; i < Config.rows; i++) {
if (chesses[x][i] != chesses[x][y]) {
count = new Point(x, i);
return count;
}
}
return count;
}
public Point getSlashru(int[][] chesses, int x, int y) {// 右上
Point count = new Point();
for (int i = y - 1, j = x + 1; j < Config.rows && i >= 0; j++, i--) {
if (chesses[j][i] != chesses[x][y]) {
count = new Point(j, i);
return count;
}
}
return count;
}
public Point getSlashrd(int[][] chesses, int x, int y) {// 右下
Point count = new Point();
for (int i = y + 1, j = x + 1; j < Config.rows && i < Config.columns; j++, i++) {
if (chesses[j][i] != chesses[x][y]) {
count = new Point(j, i);
return count;
}
}
return count;
}
public Point getSlashlu(int[][] chesses, int x, int y) {// 左上
Point count = new Point();
for (int i = y, j = x; j >= 0 && i >= 0; j--, i--) {
if (chesses[j][i] != chesses[x][y]) {
count = new Point(j, i);
return count;
}
}
return count;
}
public Point getSlashld(int[][] chesses, int x, int y) {// 左下
Point count = new Point();
for (int i = y + 1, j = x - 1; j >= 0 && i < Config.columns; j--, i++) {
if (chesses[j][i] != chesses[x][y]) {
count = new Point(j, i);
return count;
}
}
return count;
}
public int judge(int[][] chesses, int x, int y, int data) {
this.Init();
chesses[x][y] = data;// 给个假设值!
Point index_r = getright(chesses, x, y);// 右
Point index_l = getleft(chesses, x, y);// 左
Point index_u = getup(chesses, x, y);// 上
Point index_d = getdown(chesses, x, y);// 下
Point index_ru = getSlashru(chesses, x, y);// 右上
Point index_rd = getSlashrd(chesses, x, y);// 右下
Point index_lu = getSlashlu(chesses, x, y);// 左上
Point index_ld = getSlashld(chesses, x, y);// 左下
int left = chesses[index_l.x][index_l.y];// 左
int left1 = 9, right1 = 9, left2 = 9, right2 = 9, left3 = 9, right3 = 9;
if (index_l.x > 0)
left1 = chesses[index_l.x - 1][index_l.y];
int right = chesses[index_r.x][index_r.y];// 右
if (index_r.x < Config.columns - 2)
right1 = chesses[index_r.x + 1][index_r.y];
if (index_l.x - 1 > 0)
left2 = chesses[index_l.x - 2][index_l.y];
if (index_r.x < Config.columns - 3)
right2 = chesses[index_r.x + 2][index_r.y];
if (index_l.x - 2 > 0)
left3 = chesses[index_l.x - 3][index_l.y];
if (index_r.x < Config.columns - 4)
right3 = chesses[index_r.x + 3][index_r.y];
// 纵向
int up = chesses[index_u.x][index_u.y];// 上
int up1 = 9, down1 = 9, up2 = 9, down2 = 9, up3 = 9, down3 = 9;
if (index_u.x > 0)
up1 = chesses[index_u.x - 1][index_u.y];
int down = chesses[index_d.x][index_d.y];// 1下
if (index_d.x < Config.rows - 2)
down1 = chesses[index_d.x + 1][index_d.y];
if (index_u.x - 1 > 0)
up2 = chesses[index_u.x - 2][index_u.y];
if (index_d.x < Config.rows - 3)
down2 = chesses[index_d.x + 2][index_d.y];
if (index_u.x - 2 > 0)
up3 = chesses[index_u.x - 3][index_u.y];
if (index_d.x < Config.rows - 4)
down3 = chesses[index_d.x + 3][index_d.y];
// 左斜线
int ld = chesses[index_ld.x][index_ld.y];// 左下
int ld1 = 9, ru1 = 9, ld2 = 9, ru2 = 9, ld3 = 9, ru3 = 9;
if (index_ld.x > 0 && index_ld.y < Config.rows - 2)// 1左下
ld1 = chesses[index_ld.x - 1][index_ld.y + 1];
int ru = chesses[index_ru.x][index_ru.y];// 右上
if (index_ru.x < Config.columns - 2 && index_ru.y > 0)// 右上
ru1 = chesses[index_ru.x + 1][index_ru.y - 1];
if (index_ld.x - 1 > 0 && index_ld.y < Config.rows - 3)// 2左下
ld2 = chesses[index_ld.x - 2][index_ld.y + 2];
if (index_ru.x < Config.columns - 3 && index_ru.y > 1)// 右上
ru2 = chesses[index_ru.x + 2][index_ru.y - 2];
if (index_ld.x - 2 > 0 && index_ld.y < Config.rows - 4)// 3左下
ld2 = chesses[index_ld.x - 3][index_ld.y + 3];
if (index_ru.x < Config.columns - 4 && index_ru.y > 2)// 右上
ru2 = chesses[index_ru.x + 3][index_ru.y - 3];
// 右斜线
int lu = chesses[index_lu.x][index_lu.y];// 右上
int lu1 = 9, rd1 = 9, lu2 = 9, rd2 = 9, lu3 = 9, rd3 = 9;
if (index_lu.x > 0 && index_lu.y > 0)// 1左上
lu1 = chesses[index_lu.x - 1][index_lu.y - 1];
int rd = chesses[index_rd.x][index_rd.y];// 左下
if (index_rd.x < Config.columns - 2 && index_rd.y < Config.rows - 2)// 右下
rd1 = chesses[index_rd.x + 1][index_rd.y + 1];
if (index_lu.x - 1 > 0 && index_lu.y > 1)// 2左上
lu2 = chesses[index_lu.x - 2][index_lu.y - 2];
if (index_rd.x < Config.columns - 3 && index_rd.y < Config.rows - 3)// 右下
rd2 = chesses[index_rd.x + 2][index_rd.y + 2];
if (index_lu.x - 2 > 0 && index_lu.y > 2)// 3左上
lu2 = chesses[index_lu.x - 3][index_lu.y - 3];
if (index_rd.x < Config.columns - 4 && index_rd.y < Config.rows - 4)// 右下
rd2 = chesses[index_rd.x + 3][index_rd.y + 3];
/**
* 五连珠
*/
if (Check.checkfive(chesses, x, y))// 成5
{
five++;
}
/**
* 四连珠
*/
if (Check.checkRow(chesses, x, y) == 4) {// 横向四连珠
System.out.println("四连珠 <" + x + ", " + y + ">");
if (left == 0 && right == 0)// 活四
{
alive_4++;
} else if ((left == 0 && right == -data) || (left == -data && right == 0)) {
highdie_4++;
} // 死4
}
if (Check.checkColumn(chesses, x, y) == 4) {// 纵向四连珠
if (up == 0 && down == 0)// 活四
{
alive_4++;
} else if ((up == 0 && down == -data) || (up == -data && down == 0)) {
highdie_4++;
} // 眠4
}
if (Check.checkIncleft(chesses, x, y) == 4) {// 左斜线:左下右上
if (ld == 0 && ru == 0)// 活四
{
alive_4++;
} else if ((ld == 0 && ru == -data) || (ld == -data && ru == 0)) {
highdie_4++;
} // 眠4
}
if (Check.checkIncright(chesses, x, y) == 4) {// 右斜线:左上右下
if (lu == 0 && rd == 0)// 活四
{
alive_4++;
} else if ((lu == 0 && rd == -data) || (lu == -data && rd == 0)) {
highdie_4++;
} // 眠4
}
/**
* 三连珠
*/
if (Check.checkRow(chesses, x, y) == 3) {// 横向三连珠
if (left == 0 && right == 0) {// 断开处空
if (left1 == 0 || right1 == 0)// 活三
{
alive_3++;
}
if (left1 == data || right == data)// 死4
{
die_4++;
}
if (left1 == -data || right1 == -data)// 眠三
{
die_3++;
}
} else if (left == -data && right == 0) {// 左边被拦
if (right1 == data)// 右边隔一个有棋子,眠四
{
die_4++;
} else if (right1 == 0)// 没有放棋子为眠3
{
die_3++;
}
} else if (right == -data && left == 0) {// 右边被拦
if (left1 == data)// 左边隔一个棋子,眠四
{
die_4++;
} else if (left1 == 0)// 没有放棋子为眠3
{
die_3++;
}
}
}
if (Check.checkColumn(chesses, x, y) == 3) {// 纵向三连珠
if (up == 0 && down == 0) {// 断开处空
if (up1 == 0 || down1 == 0)// 活三
{
alive_3++;
}
if (up1 == data || down == data)// 死4
{
die_4++;
}
if (up1 == -data || down1 == -data)// 眠三
{
die_3++;
}
} else if (up == -data && down == 0) {// 左边被拦
if (down1 == data)// 右边隔一个有棋子,眠四
{
die_4++;
} else if (down1 == 0)// 没有放棋子为眠3
{
die_3++;
}
} else if (down == -data && up == 0) {// 右边被拦
if (up1 == data)// 左边隔一个棋子,眠四
{
die_4++;
} else if (up1 == 0)// 没有放棋子为眠3
{
die_3++;
}
}
}
if (Check.checkIncleft(chesses, x, y) == 3) {// 左斜线三连珠 :左下+右上
if (ld == 0 && ru == 0) {// 断开处空
if (ld1 == 0 || ru1 == 0)// 活三
{
alive_3++;
}
if (ld1 == data || ru == data)// 死4
{
die_4++;
}
if (ld1 == -data || ru1 == -data)// 眠三
{
die_3++;
}
} else if (ld == -data && ru == 0) {// 左边被拦
if (ru1 == data)// 右边隔一个有棋子,眠四
{
die_4++;
} else if (ru1 == 0)// 没有放棋子为眠3
{
die_3++;
}
} else if (ru == -data && ld == 0) {// 右边被拦
if (ld1 == data)// 左边隔一个棋子,眠四
{
die_4++;
} else if (ld1 == 0)// 没有放棋子为眠3
{
die_3++;
}
}
}
if (Check.checkIncright(chesses, x, y) == 3) {// 右斜三连珠:右下+左上
if (lu == 0 && rd == 0) {// 断开处空
if (lu1 == 0 || rd1 == 0)// 活三
{
System.out.println(data + "<" + x + "," + y + ">右斜线活3 右斜线检查" + Check.checkIncright(chesses, x, y)
+ "左斜线检查:" + Check.checkIncleft(chesses, x, y));
System.out.println("<" + x + "," + y + ">" + "" + lu3 + "" + "live2:" + lu2 + " live3:" + lu1
+ " die3:" + lu + " low2:" + rd);
alive_3++;
}
if (lu1 == data || rd == data)// 死4
{
die_4++;
}
if (lu1 == -data || rd1 == -data)// 眠三
{
die_3++;
}
}
if (lu == -data && rd == 0) {// 左边被拦
if (rd1 == data)// 右边隔一个有棋子,眠四
{
die_4++;
} else if (rd1 == 0)// 没有放棋子为眠3
{
die_3++;
}
}
if (rd == -data && lu == 0) {// 右边被拦
if (lu1 == data)// 左边隔一个棋子,眠四
{
die_4++;
} else if (lu1 == 0)// 没有放棋子为眠3
{
die_3++;
}
}
}
/**
* 二连珠
*/
if (Check.checkRow(chesses, x, y) == 2) {// 横向二连珠
if (right == 0 && left == 0) {// 如果两边断开位置都为空
// System.out.println("二连珠"+left2+" "+left1+" "+left+" "+right+"
// "+right1+" "+right2);
if ((right1 == 0 && right2 == data) || (left1 == 0 && left2 == data))// 第三棋子有一个为本色,眠3
{
die_3++;
} else if (right1 == 0 && left1 == 0)// 断开第二个位置都为空,活2
{
// System.out.println("活二!");
alive_2++;
}
if ((right1 == data && right2 == 0) || (left1 == data && left2 == 0))
// 某一边断开第二个位置为本色,第三位置为空,跳活三
{
tiaoalive_3++;
}
if ((right1 == data && right2 == -data) || (left1 == data && left2 == -data))
// 某一边断开第二位置为本色,得三位置为他色,眠三
{
die_3++;
}
if ((right1 == data && right2 == data) || (left1 == data && left2 == data))
// 某一边的12都为本色,眠四
{
die_4++;
}
} else if (right == 0 && left == -data) {// 右边为空左边被拦
if (right1 == data && right2 == data)// 右边12都为本色,眠四
{
die_4++;
} else if (right1 == data || right2 == data)// 右2只要有一个为自己的棋子,眠三
{
die_3++;
} else if (right1 == 0 && right2 == 0)// 右123都为空,眠2
{
die_2++;
}
} else if (left == 0 && right == -data) {// 左边为空右边被拦
if (left1 == data && left2 == data)// 左边12都为本色,眠四
{
die_4++;
} else if (left1 == data || left2 == data)// 左2只要有一个为自己的棋子,眠三
{
die_3++;
} else if (left1 == 0 && left2 == 0)// 左123为空,眠2
{
die_2++;
}
}
}
if (Check.checkColumn(chesses, x, y) == 2) {// 纵向二连珠
if (up == 0 && down == 0) {// 如果两边断开位置都为空
if ((up1 == 0 && up2 == data) || (down1 == 0 && down2 == data))// 第三棋子有一个为本色,眠3
{
die_3++;
} else if (up1 == 0 && down1 == 0)// 断开第二个位置都为空,活2
{
alive_2++;
}
if ((up1 == data && up2 == 0) || (down1 == data && down2 == 0))
// 某一边断开第二个位置为本色,第三位置为空,跳活三
{
tiaoalive_3++;
}
if ((up1 == data && up2 == -data) || (down1 == data && down2 == -data))
// 某一边断开第二位置为本色,得三位置为他色,眠三
{
die_3++;
}
if ((up1 == data && up2 == data) || (down1 == data && down2 == data))
// 某一边的12都为本色,眠四
{
die_4++;
}
} else if (up == 0 && down == -data) {// 上边为空下边被拦
if (up1 == data && up2 == data)// 上边12都为本色,眠四
{
die_4++;
} else if (up1 == data || up2 == data)// 上2只要有一个为自己的棋子,眠三
{
die_3++;
} else if (up1 == 0 && up2 == 0)// 上123都为空,眠2
{
die_2++;
}
} else if (down == 0 && up == -data) {// 下边为空上边被拦
if (down1 == data && down2 == data)// 下边12都为本色,眠四
{
die_4++;
} else if (down1 == data || down2 == data)// 下2只要有一个为自己的棋子,眠三
{
die_3++;
} else if (down1 == 0 && down2 == 0)// 下123为空,眠2
{
die_2++;
}
}
}
if (Check.checkIncleft(chesses, x, y) == 2) {// 左斜线:左下ld+右上ru
if (ld == 0 && ru == 0) {// 如果两边断开位置都为空
if ((ld1 == 0 && ld2 == data) || (ru1 == 0 && ru2 == data))// 第三棋子有一个为本色,眠3
{
die_3++;
} else if (ld1 == 0 && ru1 == 0)// 断开第二个位置都为空,活2
{
alive_2++;
}
if ((ld1 == data && ld2 == 0) || (ru1 == data && ru2 == 0))
// 某一边断开第二个位置为本色,第三位置为空,跳活三
{
tiaoalive_3++;
}
if ((ld1 == data && ld2 == -data) || (ru1 == data && ru2 == -data))
// 某一边断开第二位置为本色,得三位置为他色,眠三
{
die_3++;
}
if ((ld1 == data && ld2 == data) || (ru1 == data && ru2 == data))
// 某一边的12都为本色,眠四
{
die_4++;
}
} else if (ld == 0 && ru == -data) {// 左边为空右边被拦
if (ld1 == data && ld2 == data)// 左边12都为本色,眠四
{
die_4++;
} else if (ld1 == data || ld2 == data)// 左2只要有一个为自己的棋子,眠三
{
die_3++;
} else if (ld1 == 0 && ld2 == 0)// 左123都为空,眠2
{
die_2++;
}
} else if (ru == 0 && ld == -data) {// 右边为空右边被拦
if (ru1 == data && ru2 == data)// 右边12都为本色,眠四
{
die_4++;
} else if (ru1 == data || ru2 == data)// 右2只要有一个为自己的棋子,眠三
{
die_3++;
} else if (ru1 == 0 && ru2 == 0)// 右123为空,眠2
{
die_2++;
}
}
}
if (Check.checkIncright(chesses, x, y) == 2) {// 右斜线:左上lu+右下rd
if (lu == 0 && rd == 0) {// 如果两边断开位置都为空
if ((lu1 == 0 && lu2 == data) || (rd1 == 0 && rd2 == data))// 第三棋子有一个为本色,眠3
{
die_3++;
} else if (lu1 == 0 && rd1 == 0)// 断开第二个位置都为空,活2
{
// System.out.println("<"+x+","+y+"> 检测到右斜线活二");
alive_2++;
}
if ((lu1 == data && lu2 == 0) || (rd1 == data && rd2 == 0))
// 某一边断开第二个位置为本色,第三位置为空,跳活三
{
tiaoalive_3++;
}
if ((lu1 == data && lu2 == -data) || (rd1 == data && rd2 == -data))
// 某一边断开第二位置为本色,得三位置为他色,眠三
{
die_3++;
}
if ((lu1 == data && lu2 == data) || (rd1 == data && rd2 == data))
// 某一边的12都为本色,眠四
{
die_4++;
}
} else if (lu == 0 && rd == -data) {// 左边为空右边被拦
if (lu1 == data && lu2 == data)// 左边12都为本色,眠四
{
die_4++;
} else if (lu1 == data || lu2 == data)// 左2只要有一个为自己的棋子,眠三
{
die_3++;
} else if (lu1 == 0 && lu2 == 0)// 左123都为空,眠2
{
die_2++;
}
} else if (rd == 0 && lu == -data) {// 右边为空左边被拦
if (rd1 == data && rd2 == data)// 右边12都为本色,眠四
{
die_4++;
} else if (rd1 == data || rd2 == data)// 右2只要有一个为自己的棋子,眠三
{
die_3++;
} else if (rd1 == 0 && rd2 == 0)// 右123为空,眠2
{
die_2++;
}
}
}
/**
* 1连珠
*/
if (Check.checkRow(chesses, x, y) == 1) {// 横向1连
// 眠四情况01000
if ((right == 0 && right1 == data && right2 == data && right3 == data)
|| (left == 0 && left1 == data && left2 == data && left3 == data)) {
die_4++;
}
// 跳三101001
if ((right == 0 && left == 0 && left1 == data && left2 == data && left3 == 0)
|| (left == 0 && right == 0 && right1 == data && right2 == data && right3 == 0)) {
tiaoalive_3++;
}
// 眠三
if ((right == 0 && left == 0 && left1 == data && left2 == data && left3 == -data)
|| (right == 0 && left == 0 && right1 == data && right2 == data && right3 == -data))// 101002
{
die_3++;
} else if ((right == -data && left == 0 && left1 == data && left2 == data && left3 == 0)
|| (right == 0 && left == -data && right1 == data && right2 == data && right3 == 0))// 100102
{
die_3++;
} else if ((right == 0 && right1 == 0 && right2 == data && right3 == data)
|| (left == 0 && left1 == 0 && left2 == data && left3 == data))// 01100
{
die_3++;
} else if ((right == 0 && right1 == data && right2 == 0 && right3 == data)
|| (left == 0 && left1 == data && left2 == 0 && left3 == data))
// 活二
if ((left == 0 && right == 0 && left1 == data && left2 == 0 && left3 == 0)
|| (right == 0 && left == 0 && right1 == data && right2 == 0 && right3 == 0))
// 101011
{
lowalive_2++;
} else if ((left == 0 && right == 0 && right1 == 0 && right2 == data && right3 == 0) || (right == 0 && left == 0 && left1 == 0 && left2 == data && left3 == 0))
// 101101
{
lowalive_2++;
}
// 眠二
// 低眠2不考虑
}
if (Check.checkColumn(chesses, x, y) == 1) {// 纵向1连
// 眠四情况01000
if ((up == 0 && up1 == data && up2 == data && up3 == data)
|| (down == 0 && down1 == data && down2 == data && down3 == data)) {
die_4++;
}
// 跳三101001
if ((up == 0 && down == 0 && down1 == data && down2 == data && down3 == 0)
|| (down == 0 && up == 0 && up1 == data && up2 == data && up3 == 0)) {
tiaoalive_3++;
}
// 眠三
if ((up == 0 && down == 0 && down1 == data && down2 == data && down3 == -data)
|| (up == 0 && down == 0 && up1 == data && up2 == data && up3 == -data))// 101002
{
die_3++;
} else if ((up == -data && down == 0 && down1 == data && down2 == data && down3 == 0)
|| (up == 0 && down == -data && up1 == data && up2 == data && up3 == 0))// 100102
{
die_3++;
} else if ((up == 0 && up1 == 0 && up2 == data && up3 == data)
|| (down == 0 && down1 == 0 && down2 == data && down3 == data))// 01100
{
die_3++;
} else if ((up == 0 && up1 == data && up2 == 0 && up3 == data)
|| (down == 0 && down1 == data && down2 == 0 && down3 == data)) {
die_3++;
}
// 活二
if ((down == 0 && up == 0 && down1 == data && down2 == 0 && down3 == 0)
|| (up == 0 && down == 0 && up1 == data && up2 == 0 && up3 == 0))
// 101011
{
lowalive_2++;
} else if ((down == 0 && up == 0 && up1 == 0 && up2 == data && up3 == 0)
|| (up == 0 && down == 0 && down1 == 0 && down2 == data && down3 == 0))
// 101101
{
lowalive_2++;
}
// 眠二
// 低眠2不考虑
}
if (Check.checkIncleft(chesses, x, y) == 1) {// 左斜线:左下+右上
// 眠四情况01000
if ((ru == 0 && ru1 == data && ru2 == data && ru3 == data)
|| (ld == 0 && ld1 == data && ld2 == data && ld3 == data)) {
die_4++;
}
// 跳三101001
if ((ru == 0 && ld == 0 && ld1 == data && ld2 == data && ld3 == 0)
|| (ld == 0 && ru == 0 && ru1 == data && ru2 == data && ru3 == 0)) {
tiaoalive_3++;
}
// 眠三
if ((ru == 0 && ld == 0 && ld1 == data && ld2 == data && ld3 == -data)
|| (ru == 0 && ld == 0 && ru1 == data && ru2 == data && ru3 == -data))// 101002
{
die_3++;
} else if ((ru == -data && ld == 0 && ld1 == data && ld2 == data && ld3 == 0)
|| (ru == 0 && ld == -data && ru1 == data && ru2 == data && ru3 == 0))// 100102
{
die_3++;
} else if ((ru == 0 && ru1 == 0 && ru2 == data && ru3 == data)
|| (ld == 0 && ld1 == 0 && ld2 == data && ld3 == data))// 01100
{
die_3++;
} else if ((ru == 0 && ru1 == data && ru2 == 0 && ru3 == data)
|| (ld == 0 && ld1 == data && ld2 == 0 && ld3 == data)) {
die_3++;
}
// 活二
if ((ld == 0 && ru == 0 && ld1 == data && ld2 == 0 && ld3 == 0)
|| (ru == 0 && ld == 0 && ru1 == data && ru2 == 0 && ru3 == 0))
// 101011
{
lowalive_2++;
} else if ((ld == 0 && ru == 0 && ru1 == 0 && ru2 == data && ru3 == 0)
|| (ru == 0 && ld == 0 && ld1 == 0 && ld2 == data && ld3 == 0))
// 101101
{
lowalive_2++;
}
// 眠二
}
if (Check.checkIncright(chesses, x, y) == 1) {// 右斜线:右下rd+左上lu
// 眠四情况01000
if ((rd == 0 && rd1 == data && rd2 == data && rd3 == data)
|| (lu == 0 && lu1 == data && lu2 == data && lu3 == data)) {
die_4++;
}
// 跳三101001
if ((rd == 0 && lu == 0 && lu1 == data && lu2 == data && lu3 == 0)
|| (lu == 0 && rd == 0 && rd1 == data && rd2 == data && rd3 == 0)) {
tiaoalive_3++;
}
// 眠三
if ((rd == 0 && lu == 0 && lu1 == data && lu2 == data && lu3 == -data)
|| (rd == 0 && lu == 0 && rd1 == data && rd2 == data && rd3 == -data))// 101002
{
die_3++;
} else if ((rd == -data && lu == 0 && lu1 == data && lu2 == data && lu3 == 0)
|| (rd == 0 && lu == -data && rd1 == data && rd2 == data && rd3 == 0))// 100102
{
die_3++;
} else if ((rd == 0 && rd1 == 0 && rd2 == data && rd3 == data)
|| (lu == 0 && lu1 == 0 && lu2 == data && lu3 == data))// 01100
{
die_3++;
} else if ((rd == 0 && rd1 == data && rd2 == 0 && rd3 == data)
|| (lu == 0 && lu1 == data && lu2 == 0 && lu3 == data)) {
die_3++;
}
// 活二
if ((lu == 0 && rd == 0 && lu1 == data && lu2 == 0 && lu3 == 0)
|| (rd == 0 && lu == 0 && rd1 == data && rd2 == 0 && rd3 == 0))
// 101011
{
lowalive_2++;
} else if ((lu == 0 && rd == 0 && rd1 == 0 && rd2 == data && rd3 == 0)
|| (rd == 0 && lu == 0 && lu1 == 0 && lu2 == data && lu3 == 0))
// 101101
{
lowalive_2++;
}
// 眠二
}
chesses[x][y] = 0;// 检查假设值之后返回
return this.getLevel();
}
public int getLevel() {
int count = 1;
if (five > 0)
count += 100000;// 赢
if (alive_4 > 0 || highdie_4 > 1 || (highdie_4 > 0 && alive_3 > 0))// 活4,双死4,死4活3
count += 10000;
if (alive_3 > 1)// 双活3
count += 5000;
if (die_3 > 0 && alive_3 > 0)// 死3活3
count += 1000;
if (highdie_4 > 0)// 死4
count += 500;
if (die_4 > 0)// 低级死4
count += 400;
if (alive_3 > 0)// 单活3
count += 100;
if (tiaoalive_3 > 0)// 跳活3
count += 90;
if (alive_2 > 1)// 双活2
count += 50;
if (alive_2 > 0)// 活2
count += 10;
if (lowalive_2 > 0)// 低活2
count += 9;
if (die_3 > 0)// 死3
count += 5;
if (die_2 > 0)// 死2
count += 2;
// if()
return count;
}
}
在监听器中添加人机对战的模式:
- 人机模式要先找到target数组
- 在target数组中分别对黑白棋评分
- 机器人为白棋,取黑白棋中分数最高的点落子
package com.GobandAI;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextArea;
import com.GobandAI.Checkerboard.Config;
import com.GobandAI.Repaint;
/**
* 五子棋监听器
*
* @author mo
*
*/
public class DrawListener implements MouseListener, ActionListener {
private int count = 0, flag_start = 0, flag_winner = 0, flag_play = -1;
private Graphics g;
private Repaint[] rep;
private int de = 0;
private int[][] chesses;// 1黑 -1白
private int[][] back = new int[256][2];
private Checkerboard board;
private String name;
private JFrame finshjf = new JFrame();
private JTextArea txt = new JTextArea();
public void setGraphics(Graphics g) {
this.g = g;
}
/**
* 为了实现棋盘的重绘
*/
public void setCheckerboard(Checkerboard c) {
this.board = c;
txt = board.getEast();
}
public void setChesses(int[][] c) {
this.chesses = c;
}
/**
* 重绘数组
*
* @param rep
*/
public void setrepaint(Repaint[] rep) {
this.rep = rep;
}
public void actionPerformed(ActionEvent e) {
name = e.getActionCommand();
if (name.equals("开始游戏") || name.equals("重新开始")) {
board.clearChesses();
flag_start = 1;
flag_winner = 0;
count = 0;
finshjf.setVisible(false);
txt.append("游戏开始" + "\n");
}
if (name.equals("返回棋局")) {
finshjf.setVisible(false);
txt.append("返回棋局" + "\n");
}
if (name.equals("悔棋")) {
if (count < 2)
txt.append("不能悔棋!" + "\n");
else txt.append("悔棋成功" + "\n");
this.rep[count - 1] = null;
this.rep[count - 2] = null;
chesses[back[count - 1][0]][back[count - 1][0]] = 0;
chesses[back[count - 1][0]][back[count - 1][1]] = 0;
chesses[back[count - 2][0]][back[count - 2][0]] = 0;
chesses[back[count - 2][0]][back[count - 2][1]] = 0;
count -= 2;
board.paint(board.getGraphics());
}
if (name.equals("玩家对战")) {
flag_play = 0;
txt.append("选择模式为:玩家对战\n");
}
if (name.equals("人机对战")) {
flag_play = 1;
txt.append("选择模式为:人机对战\n");
}
}
/**
* 鼠标点击事件 放下棋子
*/
public void mouseClicked(MouseEvent e) {
int x0 = e.getX();
int y0 = e.getY();
/**
* 判断按下是否有效
*/
if (flag_play == -1)
txt.append("请选择对战模式:人机/玩家\n");
if (flag_start == 0)
txt.append("请点击开始游戏" + "\n");
if (flag_play == 0)
this.Player_against(x0, y0);
if (flag_play == 1)
this.Computer_against(x0, y0);
};
/**
* 玩家对抗
*
* @param x0
* 按下的坐标
* @param y0
* 按下的坐标
*/
public void Player_against(int x0, int y0) {
Image img_b = new ImageIcon("D:/learning/mydemo/Javaworkspace/rect/src/com/goband/黑棋.png").getImage();
Image img_w = new ImageIcon("D:/learning/mydemo/Javaworkspace/rect/src/com/goband/白棋.png").getImage();
if ((flag_start == 1)
&& ((x0 - Config.start) % Config.SIZE < Config.SIZE / 3
|| ((x0 - Config.start) % Config.SIZE > 2 * Config.SIZE / 3)
&& ((y0 - Config.start) % Config.SIZE < Config.SIZE / 3)
|| (y0 - Config.start) % Config.SIZE > 2 * Config.SIZE / 3)
&& (x0 > Config.SIZE * 2 / 3) && (y0 > Config.SIZE * 2 / 3)
&& (x0 < (Config.start + (Config.columns - 1) * Config.SIZE) - 5
&& y0 < (Config.start + (Config.rows - 1) * Config.SIZE) - 5)) {
/**
* x,y保存的是画笔需要绘制的界面坐标
*/
int x = Config.start + Config.SIZE * ((x0 - Config.start) / Config.SIZE);
int y = Config.start + Config.SIZE * ((y0 - Config.start) / Config.SIZE);
if (((x0 - Config.start) % Config.SIZE > 2 * Config.SIZE / 3)) {
x = Config.start + Config.SIZE * (1 + (x0 - Config.start) / Config.SIZE);
}
if (((y0 - Config.start) % Config.SIZE > 2 * Config.SIZE / 3)) {
y = Config.start + Config.SIZE * (1 + (y0 - Config.start) / Config.SIZE);
}
/*
* x,y需减去start再除棋盘大小 对应棋盘数组的索引
*/
int index_x = (x - Config.start) / Config.SIZE;
int index_y = (y - Config.start) / Config.SIZE;
if (chesses[index_x][index_y] == 0) {
System.out.println(index_x + " " + index_y);
if (count % 2 == 0) {
txt.append("当前为白棋" + "\n");
g.drawImage(img_b, x - Config.CHESS_SIZE / 2, y - Config.CHESS_SIZE / 2, null);
chesses[index_x][index_y] = 1;
back[count][0] = index_x;
back[count][1] = index_y;
if (Check.checkfive(chesses, index_x, index_y)) {
System.out.println("黑胜");
txt.append("游戏结束" + "\n");
txt.append("黑棋胜利" + "\n");
flag_winner = 1;
}
} else {
txt.append("当前为黑棋" + "\n");
g.drawImage(img_w, x - Config.CHESS_SIZE / 2, y - Config.CHESS_SIZE / 2, null);
chesses[index_x][index_y] = -1;
back[count][0] = index_x;
back[count][1] = index_y;
if (Check.checkfive(chesses, index_x, index_y)) {
System.out.println("白胜");
txt.append("游戏结束" + "\n");
txt.append("白棋胜利" + "\n");
flag_winner = -1;
}
}
Repaint r = new Repaint(x - Config.CHESS_SIZE / 2, y - Config.CHESS_SIZE / 2,
count % 2 == 0 ? img_b : img_w);
rep[de++] = r;
count++;
}
System.out.println("name:" + name);
if (flag_winner != 0) {
finshjf = this.finshShow();
finshjf.setVisible(true);
}
}
}
/**
* 人机对抗
*
* @param x0
* @param y0
*/
public void Computer_against(int x0, int y0) {
Image img_b = new ImageIcon("D:/learning/mydemo/Javaworkspace/rect/src/com/goband/黑棋.png").getImage();
Image img_w = new ImageIcon("D:/learning/mydemo/Javaworkspace/rect/src/com/goband/白棋.png").getImage();
if ((flag_start == 1)
&& ((x0 - Config.start) % Config.SIZE < Config.SIZE / 3
|| ((x0 - Config.start) % Config.SIZE > 2 * Config.SIZE / 3)
&& ((y0 - Config.start) % Config.SIZE < Config.SIZE / 3)
|| (y0 - Config.start) % Config.SIZE > 2 * Config.SIZE / 3)
&& (x0 > Config.SIZE * 2 / 3) && (y0 > Config.SIZE * 2 / 3)
&& (x0 < (Config.start + (Config.columns - 1) * Config.SIZE - 5)
&& y0 < (Config.start + (Config.rows - 1) * Config.SIZE) - 5)) {
// System.out.println(x0+" "+y0);
/**
* x,y保存的是画笔需要绘制的界面坐标
*/
int x = Config.start + Config.SIZE * ((x0 - Config.start) / Config.SIZE);
int y = Config.start + Config.SIZE * ((y0 - Config.start) / Config.SIZE);
if (((x0 - Config.start) % Config.SIZE > 2 * Config.SIZE / 3)) {
x = Config.start + Config.SIZE * (1 + (x0 - Config.start) / Config.SIZE);
}
if (((y0 - Config.start) % Config.SIZE > 2 * Config.SIZE / 3)) {
y = Config.start + Config.SIZE * (1 + (y0 - Config.start) / Config.SIZE);
}
/*
* x,y需减去start再除棋盘大小 对应棋盘数组的索引
*/
int index_x = (x - Config.start) / Config.SIZE;
int index_y = (y - Config.start) / Config.SIZE;
if (chesses[index_x][index_y] == 0) {
txt.append("当前为白棋" + "\n");
chesses[index_x][index_y] = 1;
// System.out.println("黑"+chesses[index_x][index_y]);
back[count][0] = index_x;
back[count][1] = index_y;
System.out.println("黑 :" + index_x + " " + index_y);
count++;
g.drawImage(img_b, x - Config.CHESS_SIZE / 2, y - Config.CHESS_SIZE / 2, null);
Repaint r = new Repaint(x - Config.CHESS_SIZE / 2, y - Config.CHESS_SIZE / 2, img_b);
rep[de++] = r;
if (Check.checkfive(chesses, index_x, index_y)) {
System.out.println("黑胜");
txt.append("游戏结束" + "\n");
txt.append("黑棋胜利" + "\n");
flag_winner = 1;
}
index_x = this.getTarget().x;
index_y = this.getTarget().y;
if (flag_winner == 0) {
// 输出
System.out.println("白" + index_x + " " + index_y);
txt.append("当前为黑棋" + "\n");
g.drawImage(img_w, (index_x * Config.SIZE + Config.start) - Config.CHESS_SIZE / 2,
(index_y * Config.SIZE + Config.start) - Config.CHESS_SIZE / 2, null);
chesses[index_x][index_y] = -1;
back[count][0] = index_x;
back[count][1] = index_y;
count++;
r = new Repaint((index_x * Config.SIZE + Config.start) - Config.CHESS_SIZE / 2,
(index_y * Config.SIZE + Config.start) - Config.CHESS_SIZE / 2, img_w);
rep[de++] = r;
if (Check.checkfive(chesses, index_x, index_y)) {
System.out.println("白胜");
txt.append("游戏结束" + "\n");
txt.append("白棋胜利" + "\n");
flag_winner = -1;
}
}
}
if (flag_winner != 0 || count == 225) {
finshjf = this.finshShow();
finshjf.setVisible(true);
}
}
}
/**
* 一方胜利后显示
*/
public JFrame finshShow() {
flag_start = 0;
board.initchesses();
JFrame jf = new JFrame("Finsh Game!");
jf.setSize(200, 130);
jf.setDefaultCloseOperation(2);
// 关闭方法 :销毁不结束
jf.setLocationRelativeTo(null);
// 居中显示
jf.setLayout(new FlowLayout());
// 流式布局
JButton yes = new JButton("重新开始");
JButton no = new JButton("返回棋局");
jf.add(yes);
jf.add(no);
yes.addActionListener(this);
no.addActionListener(this);
JLabel jl = new JLabel();
if (flag_winner == 1)
jl = new JLabel(" 黑棋胜利! ", new ImageIcon("D:/learning/mydemo/Javaworkspace/rect/src/com/goband/黑棋.png"), 0);
else if (flag_winner == -1)
jl = new JLabel(" 白棋胜利! ", new ImageIcon("D:/learning/mydemo/Javaworkspace/rect/src/com/goband/白棋.png"), 0);
else if (flag_winner == 0 && count == 225)
jl = new JLabel(" 平局! ");
jf.add(jl);
return jf;
}
public class Target {
public int x;
public int y;
public int score_b;
public int score_w;
public Target(int x, int y, int scoreb, int scorew) {
this.x = x;
this.y = y;
this.score_b = scoreb;
this.score_w = scorew;
}
public Target() {
}
}
/**
* 获取人机评分点
*/
public Target[] getScore() {
Target[] target = new Target[Config.rows * Config.columns];
int index = 0;
AIjudge judge = new AIjudge();
for (int i = 0; i < count; i++) {
int x = back[i][0];
int y = back[i][1];
// System.out.println(chesses[x-1][y-1]+" "+chesses[x][y-1]+"
// "+chesses[x+1][y-1]);
// System.out.println(chesses[x-1][y]+" "+chesses[x][y]+"
// "+chesses[x+1][y]);
// System.out.println(chesses[x-1][y+1]+" "+chesses[x][y+1]+"
// "+chesses[x+1][y+1]);
if (x > 0) {
// 棋子左边有效
// 正左
if (chesses[x - 1][y] == 0) {
Target t = new Target(x - 1, y, judge.judge(chesses, x - 1, y, 1),
judge.judge(chesses, x - 1, y, -1));
target[index++] = t;
}
}
if (x > 0 && y < Config.rows - 2) {
// 棋子下面有效,左下
if (chesses[x - 1][y + 1] == 0) {
Target t = new Target(x - 1, y + 1, judge.judge(chesses, x - 1, y + 1, 1),
judge.judge(chesses, x - 1, y + 1, -1));
target[index++] = t;
}
}
if (y < Config.rows - 2) {
// 正下
if (chesses[x][y + 1] == 0) {
Target t = new Target(x, y + 1, judge.judge(chesses, x, y + 1, 1),
judge.judge(chesses, x, y + 1, -1));
target[index++] = t;
}
}
if (y < Config.rows - 2 && x < Config.columns - 2) {
// 右下
if (chesses[x + 1][y + 1] == 0) {
Target t = new Target(x + 1, y + 1, judge.judge(chesses, x + 1, y + 1, 1),
judge.judge(chesses, x + 1, y + 1, -1));
target[index++] = t;
}
}
if (y > 0 && x > 0) {
// 左上有效
if (chesses[x - 1][y - 1] == 0) {
Target t = new Target(x - 1, y - 1, judge.judge(chesses, x - 1, y - 1, 1),
judge.judge(chesses, x - 1, y - 1, -1));
target[index++] = t;
}
}
if (y > 0 && x < Config.columns - 2) {// 右上
if (chesses[x + 1][y - 1] == 0) {
Target t = new Target(x + 1, y - 1, judge.judge(chesses, x + 1, y - 1, 1),
judge.judge(chesses, x + 1, y - 1, -1));
target[index++] = t;
}
}
if (x < Config.columns - 2) {
// 正右
if (chesses[x + 1][y] == 0) {
// System.out.println("right");
Target t = new Target(x + 1, y, judge.judge(chesses, x + 1, y, 1),
judge.judge(chesses, x + 1, y, -1));
target[index++] = t;
}
}
if (y > 0) {
// 正上
if (chesses[x][y - 1] == 0) {
// System.out.println("up");
Target t = new Target(x, y - 1, judge.judge(chesses, x, y - 1, 1),
judge.judge(chesses, x, y - 1, -1));
target[index++] = t;
}
}
}
return target;
}
// 评分类
public Target getTarget() {
Target[] t = getScore();
Target max_b = new Target();
Target max_w = new Target();
max_b.score_b = 0;
max_w.score_w = 0;
for (int i = 0; i < t.length; i++) {
if (t[i] != null) {
System.out.println("<" + t[i].x + ", " + t[i].y + "> " + t[i].score_b + " " + t[i].score_w);
if (t[i].score_b > max_b.score_b) {
max_b = t[i];
// System.out.println(max_b.score_b);
}
if (t[i].score_w > max_w.score_w) {
max_w = t[i];
// System.out.println(max_w.score_w);
}
}
}
if (max_b.score_b >= max_w.score_w)
return max_b;
if (max_b.score_b < max_w.score_w)
return max_w;
return null;
}
public void mousePressed(MouseEvent e) {
};
public void mouseReleased(MouseEvent e) {
};
public void mouseEntered(MouseEvent e) {
};
public void mouseExited(MouseEvent e) {
};
}
其他的部分跟双人对战没有什么差别,这个AI在判断边角的地方还可以更完善一点,现在先这样吧,最后附一张效果图: