📄 ai.java~9~
字号:
package wzq;
/**
* <p>Title:五子棋人工智能部分 </p>
*
* <p>Description:实现了最基本的人工智能 </p>
*
* <p>Copyright: Copyright (c) 2005</p>
*
* <p>Company: Star Group</p>
*
* @author: wangyaobsz
* @version 1.0
*/
public class AI {
/**
* 找到最佳下棋点。
* 基本思路是, 先计算每个点的权值,在权值最高的位置下棋
*/
public static Point findBestLocation(Chesses chess) {
//权值数组
int[][] power = new int[Chesses.BOARD_SIZE][Chesses.BOARD_SIZE];
for (short i = 0; i < Chesses.BOARD_SIZE; i++) {
for (short j = 0; j < Chesses.BOARD_SIZE; j++) {
// 当已有子时将该点的权值设为-1
if (chess.getChess()[i][j] != 0) {
power[i][j] = -1;
}
// 否则计算该点权值
else {
power[i][j] = (short) calcPower(i, j, chess.getCurrentType(),
chess);
}
}
}
//计算完所有点的权值后, 再找出其中权值最大的点
Point bestLoc = calcMaxPowerLocation(power);
power = null;
return bestLoc;
}
/**
* 遍历权值数组,找出权值最大点.
* @param power
* @return
*/
private static Point calcMaxPowerLocation(int[][] power) {
int max = 0;
short x = 0, y = 0;
for (short i = 0; i < Chesses.BOARD_SIZE; i++) {
for (short j = 0; j < Chesses.BOARD_SIZE; j++) {
if (power[i][j] > max) {
x = i;
y = j;
max = power[i][j];
}
}
}
return new Point(x, y);
}
/**
* 检查m,n点的权值.<p>
* 思路是, 假定在m,n位置下棋后,计算4个方向经过该点,同色相连的棋子数量, 不同的数量有不同的
* 权值,将四个方向上权值相加即为该点的权值.计算完后恢复该点的状态.
* @param m
* @param n
* @param currentType:当前棋子的类型
* @param chess
* @return
*/
private static int calcPower(short m, short n, short currentType,
Chesses chess) {
int p = 0;
//找取胜点,
int p1 = 1000;
//找三个相连的点
int p3 = 60;
//找两个相连的点
int p5 = 20;
//找相连的点
int p7 = 10;
//找对手的取胜点
int p2 = 85;
//找对手的三个相连的点
int p4 = 45;
//找对手的两个相连的点
int p6 = 15;
//找对方的相连的点
int p8 = 5;
short[] arrLinks = new short[4];
//首先模拟我方下棋,在该点预下一子,预测棋局的权值分布,然后进行后续计算.
chess.setChessFeeler(m, n, currentType);
// 计算4个方向上同色相连棋子的数量.
arrLinks = calcLinkCount(m, n, chess.getChess());
//如果m,n是中心点, 将权值加1
if (m == Chesses.BOARD_SIZE / 2 &&
n == Chesses.BOARD_SIZE / 2) {
p += 1;
}
//计算我方在该点四个方向的权值
for (short i = 0; i < 4; i++) {
if (Math.abs(arrLinks[i]) == 5) {
p += p1;
}
if (arrLinks[i] == 4) {
p += p3;
}
if (arrLinks[i] == 3) {
p += p5;
}
if (arrLinks[i] == 2) {
p += p7;
}
}
//首先模拟我方下棋,在该点预下一子,预测棋局的权值分布,然后进行后续计算.
if (currentType == Chesses.BLACK_CHESS) {
//如果对方是白子,
chess.setChessFeeler(m, n, Chesses.WHITE_CHESS);
} else {
//如果对方是黑子,
chess.setChessFeeler(m, n, Chesses.BLACK_CHESS);
}
arrLinks = calcLinkCount(m, n, chess.getChess());
//计算对手在该点四个方向的权值
for (short i = 0; i < 4; i++) {
if (Math.abs(arrLinks[i]) == 5) {
p += p2;
}
if (arrLinks[i] == 4) {
p += p4;
}
if (arrLinks[i] == 3) {
p += p6;
}
if (arrLinks[i] == 2) {
p += p8;
}
}
//计算完后恢复该点的原来状态.
chess.setChessFeeler(m, n, 0);
arrLinks = null;
return p;
}
/**
* 计算4个方向相连棋子的个数
* @param m
* @param n
* @param arrchessboard
* @return 返回一个4元素的数据,分别代表(m,n)点上四个方向听相连子的个数.
*/
private static short[] calcLinkCount(short m, short n,short[][] arrchessboard)
{
short[] counts = new short[4];
//检查是否无子可下(当flag=2时表示无子可下)
short flag = 0;
//连子个数
short num = 1;
//检查正东方向
short x = (short) (m + 1);
int y = n + 1;
//不超出棋格
for (; x < Chesses.BOARD_SIZE; ) {
//如果前方的棋子与m,n点不同则跳出循环
if (arrchessboard[x][n] == arrchessboard[m][n]) {
num++;
x++;
} else {
break;
}
}
//正东方向超出棋格
if (x == Chesses.BOARD_SIZE) {
flag++;
} else {
//正东方向有别的子不可再下
if (arrchessboard[x][n] != 0) {
flag++;
}
}
//检查正西方向
x = (short) (m - 1);
for (; x >= 0; ) {
//前方的棋子与m,n点不同时跳出循环
if (arrchessboard[x][n] == arrchessboard[m][n]) {
num++;
x--;
} else {
break;
}
}
//正西方向超出棋格
if (x == -1) {
flag++;
} else {
//正西方向有别的子不可再下
if (arrchessboard[x][n] != 0) {
flag++;
}
}
if (flag == 2) {
counts[0] = (short) - num;
} else {
if (flag == 1 && num == 3) {
//连子数为3时有一边不能下就不是活三
counts[0] = (short) - num;
} else {
counts[0] = num;
}
}
//检查是否无子可下(当flag=2时表示无子可下)
flag = 0;
//连子个数
num = 1;
//检查正南方向
x = (short) (n + 1);
for (; x < Chesses.BOARD_SIZE; ) {
//前方的棋子与m,n点不同时跳出循环
if (arrchessboard[m][x] == arrchessboard[m][n]) {
num++;
x++;
} else {
break;
}
}
//正南方向超出棋格
if (x == Chesses.BOARD_SIZE) {
flag++;
} else {
//正南方向有别的子不可在下
if (arrchessboard[m][x] != 0) {
flag++;
}
}
//检查正北方向
x = (short) (n - 1);
for (; x >= 0; ) {
//前方的棋子与m,n点不同时跳出循环
if (arrchessboard[m][x] == arrchessboard[m][n]) {
num++;
x--;
} else {
break;
}
}
//正北方向超出棋格
if (x == -1) {
flag++;
} else {
//正北方向有别的子不可在下
if (arrchessboard[m][x] != 0) {
flag++;
}
}
if (flag == 2) {
counts[1] = (short) - num;
} else {
if (flag == 1 && num == 3) {
//连子数为3时有一边不能下就不是活三
counts[1] = (short) - num;
} else {
counts[1] = num;
}
}
//检查是否无子可下(当flag=2时表示无子可下)
flag = 0;
//连子个数
num = 1;
//检查东南方向
x = (short) (m + 1);
//不超出棋格
for (; x < Chesses.BOARD_SIZE && y < Chesses.BOARD_SIZE; ) {
//前方的棋子与m,n点不同时跳出循环
if (arrchessboard[x][y] == arrchessboard[m][n]) {
num++;
x++;
y++;
} else {
break;
}
}
//东南方向超出棋格
if (x == Chesses.BOARD_SIZE || y == Chesses.BOARD_SIZE) {
flag++;
} else {
//东南方向有别的子不可在下
if (arrchessboard[x][y] != 0) {
flag++;
}
}
//检查西北方向
x = (short) (m - 1);
y = n - 1;
//不超出棋格
for (; x >= 0 && y >= 0; ) {
//前方的棋子与m,n点不同时跳出循环
if (arrchessboard[x][y] == arrchessboard[m][n]) {
num++;
x--;
y--;
} else {
break;
}
}
//西北方向超出棋格
if (x == -1 || y == -1) {
flag++;
} else {
//西北方向有别的子不可在下
if (arrchessboard[x][y] != 0) {
flag++;
}
}
if (flag == 2) {
counts[2] = (short) - num;
} else {
if (flag == 1 && num == 3) {
//连子数为3时有一边不能下就不是活三
counts[2] = (short) - num;
} else {
counts[2] = num;
}
}
//检查是否无子可下(当flag=2时表示无子可下)
flag = 0;
//连子个数
num = 1;
//检查西南方向
x = (short) (m - 1);
y = n + 1;
//不超出棋格
for (; x >= 0 && y < Chesses.BOARD_SIZE; ) {
//前方的棋子与m,n点不同时跳出循环
if (arrchessboard[x][y] == arrchessboard[m][n]) {
num++;
x--;
y++;
} else {
break;
}
}
//西南方向超出棋格
if (x == -1 || y == Chesses.BOARD_SIZE) {
flag++;
} else {
//西南方向有别的子不可在下
if (arrchessboard[x][y] != 0) {
flag++;
}
}
//检查东北方向(
x = (short) (m + 1);
y = n - 1;
//不超出棋格
for (; x < Chesses.BOARD_SIZE && y >= 0; ) {
//前方的棋子与m,n点不同时跳出循环
if (arrchessboard[x][y] == arrchessboard[m][n]) {
num++;
x++;
y--;
} else {
break;
}
}
//东北方向超出棋格
if (x == Chesses.BOARD_SIZE || y == -1) {
flag++;
} else {
//东北方向有别的子不可在下
if (arrchessboard[x][y] != 0) {
flag++;
}
}
if (flag == 2) {
counts[3] = (short) - num;
} else {
if (flag == 1 && num == 3) {
//连子数为3时有一边不能下就不是活三
counts[3] = (short) - num;
} else {
counts[3] = num;
}
}
// 返回四个方向的相连子的个数。
return counts;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -