import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.lang.Math;
/**
* @author yeeku.H.lee [email protected]
* @version 1.0
* <br>Copyright (C), 2005-2008, yeeku.H.Lee
* <br>This program is protected by copyright laws.
* <br>Program Name:
* <br>Date:
*/
class GobangAI
{
//每个棋局要找出COUNT个得分最高的空格
protected static int COUNT = 6;
//考虑到DEPTH步棋
protected static int DEPTH = 5;
//定义棋盘的大小
protected static int BOARD_SIZE = 15;
//定义一个二维数组来充当棋盘,其中0是空位,1是电脑,2是玩家
protected int[][] table = new int [BOARD_SIZE][BOARD_SIZE];
protected static final int NOTHING = 0;
protected static final int COMPUTER = 1;
protected static final int PLAYER = 2;
//定义一个二维数组,暂存棋盘情况(以防求AI的时候改变了table)
protected int[][] tableAI = new int [BOARD_SIZE][BOARD_SIZE];
//定义空位、玩家用的棋和电脑的棋
protected String[] stone = new String[]{"╋","■","●"};
//记录玩家和电脑上一步下的棋的行数
protected int[] iLast = new int[]{0,0,0};
//记录玩家和电脑上一步下的棋的列数
protected int[] jLast = new int[]{0,0,0};
//初始化单个方向的常量
protected final int DIR = 8; //方向的总数
protected final int UP = 0;
protected final int UP_RIGHT = 1;
protected final int RIGHT = 2;
protected final int DOWN_RIGHT = 3;
protected final int DOWN = 4;
protected final int DOWN_LEFT = 5;
protected final int LEFT = 6;
protected final int UP_LEFT = 7;
//初始化空位的单个方向的情况(这是下棋前的情况)
int[][][][] situation = new int[3][BOARD_SIZE][BOARD_SIZE][DIR];
protected final int LIFE_ZERO = 0; //邻近为空格
protected final int LIFE_ONE = 1; //活一
protected final int LIFE_TWO = 2; //活二
protected final int LIFE_THREE = 3; //活三
protected final int DEAD_ZERO = 10; //邻近有对方的棋或边界
protected final int DEAD_ONE = 11; //堵一
protected final int DEAD_TWO = 12; //堵二
protected final int DEAD_THREE = 13; //堵三
protected final int FINISH_BANG = 100; //连珠
//初始化空位的四个方向(即在一条直线上)的评分(这是下棋后的情况)
int[][][][] markLink = new int[3][BOARD_SIZE][BOARD_SIZE][DIR];
protected final int LINK_DEAD = 0; //邻近都被堵
protected final int LINK_DEAD_ONE = 1; //死一(其中一边为空)
protected final int LINK_LIFE_ONE = 2; //活一(两边都空)
protected final int LINK_DEAD_TWO = 3; //死二(其中一边为空)
protected final int LINK_LIFE_TWO = 4; //活二(两边都空)
protected final int LINK_DEAD_THREE = 5; //死三(其中一边为空)
protected final int LINK_LIFE_THREE = 6; //活三(两边都空)
protected final int LINK_DEAD_FOUR = 7; //死四(其中一边为空)
protected final int LINK_LIFE_FOUR = 8; //活四(两边都空)
protected final int LINK_BANG = 9; //连珠
//初始化空位的总评分(这是下棋后的情况)
int[][][] mark = new int[3][BOARD_SIZE][BOARD_SIZE]; //每个空位总评分
protected final int MARK_BANG = 2000; //连珠
protected final int MARK_L4_D4D4_D4L3 = 512; //活4或者是双死4或者是死4活3
protected final int MARK_L3L3 = 256; //双活3
protected final int MARK_D3L3 = 128; //死3活3
protected final int MARK_D4 = 64; //死4
protected final int MARK_L3 = 32; //单活3
protected final int MARK_L2L2 = 16; //双活2
protected final int MARK_D3 = 8; //死3
protected final int MARK_L2 = 4; //单活2
protected final int MARK_D2 = 2; //死2
//电脑的进攻性WEIGHT。即求利益的时候,加权平均值的权数(范围0到10)
protected final int WEIGHT = 6;
//对于最高分点记录点maxPoints,其第二个索引中3个值的含义
protected final int I_MAX = 0;
protected final int J_MAX = 1;
protected final int PROFIT_MAX = 2;
/*=======================以下是实现五子棋的方法============================*/
/**
*在控制台输出棋盘的方法
*/
public void printBoard()
{
System.out.print(" ");
for (int i = 0; i < BOARD_SIZE ; i++)
{
System.out.print(i);
if (i < 10)
{
System.out.print(" ");
}
}
System.out.println();
//打印每个数组元素
for (int i = 0 ; i < BOARD_SIZE ; i++)
{
System.out.print(i);
if (i < 10)
{
System.out.print(" ");
}
for (int j = 0 ; j < BOARD_SIZE ; j++)
{
System.out.print(stone[table[i][j]]);
}
System.out.print("\n");
}
}
/**
*用户输入棋子的坐标,并作记录
*/
public void inputStone()
{
int i = 0;
int j = 0;
//判断是否成功输入的标识符
boolean ifInput = false;
BufferedReader br = new BufferedReader
(new InputStreamReader(System.in));
String inputStr = null;
inputAgain:
while (! ifInput)
{
try
{
System.out.println("请输入您下棋的座标,应以x,y的格式:");
inputStr = br.readLine();
//将用户输入的字符串以逗号(,)作为分隔符,分隔成2个字符串
String[] posStrArr = inputStr.split(",");
//将2个字符串转换成用户下棋的座标
i = Integer.parseInt(posStrArr[0]);
j = Integer.parseInt(posStrArr[1]);
}
catch (Exception e)
{
System.out.println("输入格式有误!需要从新输入!");
}
//判断坐标是否超出范围
if (! ifIn(i,j))
{
System.out.println("坐标超出范围!需要从新输入!");
continue inputAgain;
}
//判断坐标是否为空位
if (table[i][j] != NOTHING)
{
System.out.println("该位置已经有棋!需要从新输入!");
continue inputAgain;
}
//当输入正常时,记录输入的坐标
table[i][j] = PLAYER;
iLast[PLAYER] = i;
jLast[PLAYER] = j;
ifInput = true;
}
}
/**
*电脑随机生成棋子的坐标,并作记录
*/
public void randomStone()
{
//判断是否成功输入的标识符
boolean ifInput = false;
while (! ifInput)
{
//以下随机生成电脑下棋的坐标
double temp;
temp = Math.random();
int i = (int) (temp * BOARD_SIZE);
temp = Math.random();
int j = (int) (temp * BOARD_SIZE);
//判断坐标是否符合要求,并作记录
if (table[i][j] == NOTHING && ifIn(i,j))
{
iLast[COMPUTER] = i;
jLast[COMPUTER] = j;
table[i][j] = COMPUTER;
ifInput = true;
}
}
System.out.println("电脑下棋以后");
}
/**
*电脑的人工智能方法产生坐标(要调用到后半部分的AI方法),并作记录
*/
public void getAIStone()
{
int player = COMPUTER; //当前角色为电脑
int[] solution = GobangAImain();
int i = solution[0];
int j = solution[1];
iLast[player] = i;
jLast[player] = j;
table[i][j] = COMPUTER;
System.out.println("电脑下棋在:" + i +"," + j);
}
/**
*判断棋局胜负
*@param player 代表下棋的人
*@return 返回棋局情况。若结束,返回true
*/
public boolean ifFinish(int player)
{
int i = iLast[player];
int j = jLast[player];
//检查纵向的路是否五子连珠
for (int iFirst = i-4; iFirst <= i; iFirst ++)
{
if (ifIn(iFirst, j) && ifIn(iFirst + 4, j)) //待检查的坐标都在范围内
{
boolean ifLink = true; //先假设它连珠
for (int k = 0; k < 5; k ++)
{
if (table[iFirst + k][j] != player)
//若有一个位置没有该角色的棋
{
ifLink = false; //取消连珠的判断
}
}
if (ifLink) //找到连珠
{
return true;
}
}
}
//检查横向的路是否五子连珠
for (int jFirst = j-4; jFirst <= j; jFirst ++)
{
if (ifIn(i, jFirst) && ifIn(i, jFirst + 4)) //待检查的坐标都在范围内
{
boolean ifLink = true; //先假设它连珠
for (int k = 0; k < 5; k ++)
{
if (table[i][jFirst + k] != player)
//若有一个位置没有该角色的棋
{
ifLink = false; //取消连珠的判断
}
}
if (ifLink) //找到连珠
{
return true;
}
}
}
//检查捺向的路�