这一篇接Java之简单人机五子棋(一),讲一下AI算法实现的大致思路。主要思路是分别对黑白棋的局势进行打分,然后在找到评分最高的地方落点。
具体结构如下:
- 首先,point函数负责接收某点坐标和棋子颜色,然后返回对该点的评分。评分函数有四个,分别负责四个方向上的评分,即检测连子情况,依据不同的情况给予相应的分数。
- 其次,wholePoints负责在全局上对每一个点针对某种颜色进行评分,存到形参传入的15*15的评分数组中。
- best_posits负责遍历数组,找到评分最大的点位和个数,放入专门设计用来存储评分最大点的信息的类对象中。
- play 函数则负责对整体局势进行判断,综合比较取评分最高的点进行落子。
代码如下:
package renju;
class BestInfo{
int bestPoint,bestSum;
public BestInfo() {
bestPoint = 0;
bestSum = 0;
// TODO 自动生成的构造函数存根
}
public BestInfo(int i,int j){
bestPoint = i;
bestSum = j;
}
}
public class AI {
int color; //记录AI棋子的颜色
int points_b[][]; //记录黑棋各落点分数
int points_w[][]; //记录白棋各落点分数
position best_b[]; // 记录黑棋最大分数对应的落点位置
position best_w[]; //记录白棋最大分数对应的落点位置
BestInfo blackInfo,whiteInfo; //记录黑白棋分别的最大分数值和最大分数对应的落点位置个数
public AI() {
if(MyControlBoard.whiteC == 1) {
color = 2;
}
else {
color = 1;
}
points_b = new int[15][15]; //记录黑棋各落点分数
points_w = new int[15][15]; //记录白棋各落点分数
best_b = new position[250]; // 记录黑棋最大分数对应的落点位置
best_w = new position[250]; //记录白棋最大分数对应的落点位置
blackInfo = new BestInfo();
whiteInfo = new BestInfo();
}
public void play() {
if(!MyControlBoard.started) {
// System.out.println("didn't start");
return;
}
if(color == 2 && MyChessBoard.isEmpty) {
MyChessBoard.chess[7][7] = color;
MyChessBoard.record(7,7);
// System.out.println("empty");
return;
}
int iC,jC = 0,count = 0;
int xC = 0,yC = 0;
for(iC =0;iC<15;iC++)
for(jC = 0;jC < 15;jC++) {
if(MyChessBoard.chess[iC][jC] != 0) {
count+=1;
if(count==1) {
xC=iC;
yC=jC;
}
}
}
if(count == 1 && color == 1) {
try {
MyChessBoard.chess[xC-1][yC - 1] =color;
MyChessBoard.record(xC-1,yC-1);
// System.out.println("return1");
return;
}catch(Exception e){
MyChessBoard.chess[xC+1][yC + 1] =color;
MyChessBoard.record(xC-1,yC-1);
// System.out.println("return2");
return;
}
}
wholePoints(points_b, 2);
wholePoints(points_w, 1);
best_posits(points_w, best_w,whiteInfo);
best_posits(points_b, best_b,blackInfo);
// System.out.println("color AI ="+color);
// System.out.println("black"+blackInfo.bestPoint+"\twhite"+whiteInfo.bestPoint);
if( blackInfo.bestPoint > whiteInfo.bestPoint ) //黑棋最高分高过白棋,在黑棋最高分对应的位置中选出白棋分数最大的位置落子
{
int a[] = new int[20];
// System.out.println("blackInfo.bestSum"+blackInfo.bestSum);
for(int i = 0;i < blackInfo.bestSum;i++)
{
a[i] = point(best_b[i],1);
}
int max_w = MAX(a, blackInfo.bestSum);
for(int i = 0;i < blackInfo.bestSum;i++)
{
if(a[i] == max_w)
{
MyChessBoard.chess[best_b[i].x][best_b[i].y] = color;
MyChessBoard.record(best_b[i].x,best_b[i].y);
// System.out.println("return3");
return;
}
}
}
if( blackInfo.bestPoint < whiteInfo.bestPoint ) //白棋最高分高过黑棋,在白棋最高分对应的位置中选出黑棋分数最大的位置落子
{
int a[] = new int[20];
for(int i = 0;i < whiteInfo.bestSum;i++)
{
a[i] = point(best_w[i], 2);
}
int max_b = MAX(a, blackInfo.bestSum);
for(int i = 0;i < whiteInfo.bestSum;i++)
{
if(a[i] == max_b)
{
MyChessBoard.chess[best_w[i].x][best_w[i].y] = color;
MyChessBoard.record(best_w[i].x,best_w[i].y);
// System.out.println("return4");
return;
}
}
}
//最高分相等,则优先进行进攻
if( blackInfo.bestPoint == whiteInfo.bestPoint )
{
if(color == 1) {
int a[] = new int[20];
for(int i = 0;i < whiteInfo.bestSum;i++)
{
a[i] = point(best_w[i], 2);
}
int max_b = MAX(a, blackInfo.bestSum);
for(int i = 0;i < whiteInfo.bestSum;i++)
{
if(a[i] == max_b)
{
MyChessBoard.chess[best_w[i].x][best_w[i].y] = color;
MyChessBoard.record(best_w[i].x,best_w[i].y);
return;
}
}
}
if(color == 2) {
int a[] = new int[20];
for(int i = 0;i < blackInfo.bestSum;i++)
{
a[i] = point(best_b[i],1);
}
int max_w = MAX(a, blackInfo.bestSum);
for(int i = 0;i < blackInfo.bestSum;i++)
{
if(a[i] == max_w)
{
MyChessBoard.chess[best_b[i].x][best_b[i].y] = color;
MyChessBoard.record(best_b[i].x,best_b[i].y);
// System.out.println("return6");
return;
}
}
}
}
}
//对某个颜色的棋子进行全局评估,放入分数数组
private void wholePoints(int [][]points,int color){
for( int i =0;i < 15;i++)
{
for(int j = 0;j < 15;j++)
{
position temp = new position(i,j);
points[i][j] = point(temp,color);
}
}
}
//求数组最大值
private int MAX(int[] a, int n) {
int max = a[0];
for(int i =1; i < n ;i++)
{
if(a[i] > max)
max = a[i];
}
return max;
}
//给定位置,返回该点位的分数
int point(position pos, int color)
{
if(MyChessBoard.chess[pos.x][pos.y] != 0)
{
return 0;
}
int sum = 0;
sum += evaluateUp(pos, color);
sum += evaluateLeft(pos, color);
sum += evaluateLeftUp(pos, color);
sum += evaluateRightUp(pos, color);
return sum;
}
long evaluateUp(position pos, int color)
{
position p_i = new position(pos);
int count = 0,mc = 1;
boolean flag = true;
int c_blank = 0;
int judge_t;//记录颜色
int blank = -1;
try
{
do
{
p_i.up(p_i, flag);
judge_t = MyChessBoard.chess[p_i.x][p_i.y]; //颜色
if(judge_t == color)
{
if(c_blank == 1)
{
count += 1;
mc++;
}
else
{
mc++;
if(mc == 5)
return 100000000000l;
count += 2;
}
blank = 0;
}
else
{
if(judge_t == 0)
{
if(c_blank >= 1)
flag = false;
else
{
c_blank++;
}
blank = 1;
}
else
{
count-=2;
flag = false;
if(blank == 1 || count < 0)
count+=2;
blank = 0;
}
}
}while(flag);
}
catch(Exception e)
{
flag = false;
if(blank == 0)count-=2;
}
p_i.x = pos.x;
p_i.y = pos.y;
int b_blank = 0;//记录另一半的空白格子
blank = -1;
try
{
do
{
p_i.up(p_i, flag);
judge_t = MyChessBoard.chess[p_i.x][p_i.y];
if(judge_t == color)
{
if(b_blank == 1)
{
count += 1;
mc++;
}
else
{
if(b_blank == 0)
mc++;
if(mc == 5)
return 100000000000L;
count += 2;
}
blank = 0;
}
else
{
if(judge_t == 0)
{
if(b_blank >= 1)
flag = true;
else
{
b_blank++;
}
blank = 1;
}
else
{
count-=2;
if(blank==1||(count<0&&mc==1))
count+=2;
flag = true;
}
}
}while(!flag);
}
catch(Exception e)
{
if(b_blank == 0)count-=2;
return (long) Math.pow(10,count);
}
return (long) Math.pow(10,count);
}
long evaluateLeft(position pos, int color)
{
position p_i = new position(pos);
int count = 0,mc = 1;
boolean flag = true;
int c_blank = 0;
int judge_t;//记录颜色
int blank = -1;
try
{
do
{
p_i.left(p_i, flag);
judge_t = MyChessBoard.chess[p_i.x][p_i.y]; //颜色
if(judge_t == color)
{
if(c_blank == 1)
{
count += 1;
mc++;
}
else
{
mc++;
if(mc == 5)
return 100000000000l;
count += 2;
}
blank = 0;
}
else
{
if(judge_t == 0)
{
if(c_blank >= 1)
flag = false;
else
{
c_blank++;
}
blank = 1;
}
else
{
count-=2;
flag = false;
if(blank == 1 || count < 0)
count+=2;
blank = 0;
}
}
}while(flag);
}
catch(Exception e)
{
flag = false;
if(blank == 0)count-=2;
}
p_i.x = pos.x;
p_i.y = pos.y;
int b_blank = 0;//记录另一半的空白格子
blank = -1;
try
{
do
{
p_i.left(p_i, flag);
judge_t = MyChessBoard.chess[p_i.x][p_i.y];
if(judge_t == color)
{
if(b_blank == 1)
{
count += 1;
mc++;
}
else
{
if(b_blank == 0)
mc++;
if(mc == 5)
return 100000000000L;
count += 2;
}
blank = 0;
}
else
{
if(judge_t == 0)
{
if(b_blank >= 1)
flag = true;
else
{
b_blank++;
}
blank = 1;
}
else
{
count-=2;
if(blank==1||(count<0&&mc==1))
count+=2;
flag = true;
}
}
}while(!flag);
}
catch(Exception e)
{
if(b_blank == 0)count-=2;
return (long) Math.pow(10,count);
}
return (long) Math.pow(10,count);
}
long evaluateLeftUp(position pos, int color)
{
position p_i = new position(pos);
int count = 0,mc = 1;
boolean flag = true;
int c_blank = 0;
int judge_t;//记录颜色
int blank = -1;
try
{
do
{
p_i.leftUp(p_i, flag);
judge_t = MyChessBoard.chess[p_i.x][p_i.y]; //颜色
if(judge_t == color)
{
if(c_blank == 1)
{
count += 1;
mc++;
}
else
{
mc++;
if(mc == 5)
return 100000000000l;
count += 2;
}
blank = 0;
}
else
{
if(judge_t == 0)
{
if(c_blank >= 1)
flag = false;
else
{
c_blank++;
}
blank = 1;
}
else
{
count-=2;
flag = false;
if(blank == 1 || count < 0)
count+=2;
blank = 0;
}
}
}while(flag);
}
catch(Exception e)
{
flag = false;
if(blank == 0)count-=2;
}
p_i.x = pos.x;
p_i.y = pos.y;
int b_blank = 0;//记录另一半的空白格子
blank = -1;
try
{
do
{
p_i.leftUp(p_i, flag);
judge_t = MyChessBoard.chess[p_i.x][p_i.y];
if(judge_t == color)
{
if(b_blank == 1)
{
count += 1;
mc++;
}
else
{
if(b_blank == 0)
mc++;
if(mc == 5)
return 100000000000L;
count += 2;
}
blank = 0;
}
else
{
if(judge_t == 0)
{
if(b_blank >= 1)
flag = true;
else
{
b_blank++;
}
blank = 1;
}
else
{
count-=2;
if(blank==1||(count<0&&mc==1))
count+=2;
flag = true;
}
}
}while(!flag);
}
catch(Exception e)
{
if(b_blank == 0)count-=2;
return (long) Math.pow(10,count);
}
return (long) Math.pow(10,count);
}
long evaluateRightUp(position pos, int color)
{
position p_i = new position(pos);
int count = 0,mc = 1;
boolean flag = true;
int c_blank = 0;
int judge_t;//记录颜色
int blank = -1;
try
{
do
{
p_i.rightUp(p_i, flag);
judge_t = MyChessBoard.chess[p_i.x][p_i.y]; //颜色
if(judge_t == color)
{
if(c_blank == 1)
{
count += 1;
mc++;
}
else
{
mc++;
if(mc == 5)
return 100000000000l;
count += 2;
}
blank = 0;
}
else
{
if(judge_t == 0)
{
if(c_blank >= 1)
flag = false;
else
{
c_blank++;
}
blank = 1;
}
else
{
count-=2;
flag = false;
if(blank == 1 || count < 0)
count+=2;
blank = 0;
}
}
}while(flag);
}
catch(Exception e)
{
flag = false;
if(blank == 0)count-=2;
}
p_i.x = pos.x;
p_i.y = pos.y;
int b_blank = 0;//记录另一半的空白格子
blank = -1;
try
{
do
{
p_i.rightUp(p_i, flag);
judge_t = MyChessBoard.chess[p_i.x][p_i.y];
if(judge_t == color)
{
if(b_blank == 1)
{
count += 1;
mc++;
}
else
{
if(b_blank == 0)
mc++;
if(mc == 5)
return 100000000000L;
count += 2;
}
blank = 0;
}
else
{
if(judge_t == 0)
{
if(b_blank >= 1)
flag = true;
else
{
b_blank++;
}
blank = 1;
}
else
{
count-=2;
if(blank==1||(count<0&&mc==1))
count+=2;
flag = true;
}
}
}while(!flag);
}
catch(Exception e)
{
if(b_blank == 0)count-=2;
return (long) Math.pow(10,count);
}
return (long) Math.pow(10,count);
}
//给出分数数组,找出最大值对应的位置(可能不止一个),返回分数最大值
void best_posits(int points[][], position p_s[], BestInfo colorInfo)
{
int max_row[] = new int[15];
//找出最大值
for(int i = 0;i < 15;i++)
max_row[i] = MAX(points[i],15);
colorInfo.bestPoint = MAX(max_row,15);
//找出最大值对应的位置,并统计最大值的个数
colorInfo.bestSum = 0;
for(int i = 0;i < 15;i++)
{
for(int j =0;j < 15;j++)
{
if(points[i][j] == colorInfo.bestPoint)
{
p_s[colorInfo.bestSum] = new position(i,j);
colorInfo.bestSum++;
}
}
}
// System.out.println("count = "+colorInfo.bestSum);
return;
}
}
class position{
public int x,y;
public position(int x,int y){
this.x = x;
this.y = y;
}
public position(position p){
x = p.x;
y = p.y;
}
public boolean equals(position p) {
if(x == p.x && y == p.y)
return true;
else
return false;
}
public position up(position p,boolean flag) {
if(flag)
p.y = p.y - 1;
else
p.y =p.y + 1;
return p;
}
public position left(position p,boolean flag) {
if(flag)
p.x = p.x - 1;
else
p.x =p.x + 1;
return p;
}
public position leftUp(position p,boolean flag) {
return up(left(p,flag),flag);
}
public position rightUp(position p,boolean flag) {
return up(left(p,!flag),flag);
}
}
最后,再加入一个main函数类,运行即可:
package renju;
public class renju {
public static void main(String[] args) {
// TODO 自动生成的方法存根
ChessGame myRenju = new ChessGame();
myRenju.play();
}
}