项目代码如下
//Board类
package AIGobang;
import java.awt.*;
import java.util.Arrays;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Jianxin.You
*/
public class Board {
// 棋型信息
public static enum Level {
CON_5("长连", 0, new String[] { "11111", "22222" }, 100000), ALIVE_4(
"活四", 1, new String[] { "011110", "022220" }, 10000), GO_4(
"冲四", 2, new String[] { "011112|0101110|0110110",
"022221|0202220|0220220" }, 500), DEAD_4("死四", 3,
new String[] { "211112", "122221" }, -5), ALIVE_3("活三", 4,
new String[] { "01110|010110", "02220|020220" }, 200), SLEEP_3(
"眠三", 5, new String[] {
"001112|010112|011012|10011|10101|2011102",
"002221|020221|022021|20022|20202|1022201" }, 50), DEAD_3(
"死三", 6, new String[] { "21112", "12221" }, -5), ALIVE_2("活二",
7, new String[] { "00110|01010|010010", "00220|02020|020020" },
5), SLEEP_2("眠二", 8, new String[] {
"000112|001012|010012|10001|2010102|2011002",
"000221|002021|020021|20002|1020201|1022001" }, 3), DEAD_2(
"死二", 9, new String[] { "2112", "1221" }, -5), NULL("null", 10,
new String[] { "", "" }, 0);
private String name;
private int index;
private String[] regex;// 正则表达式
int score;// 分值
// 构造方法
private Level(String name, int index, String[] regex, int score) {
this.name = name;
this.index = index;
this.regex = regex;
this.score = score;
}
// 覆盖方法
@Override
public String toString() {
return this.name;
}
};
// 方向
private static enum Direction {
HENG, SHU, PIE, NA
};
// 位置分
private static int[][] position = {
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 },
{ 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0 },
{ 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0 },
{ 0, 1, 2, 3, 4, 4, 4, 4, 4, 4, 4, 3, 2, 1, 0 },
{ 0, 1, 2, 3, 4, 5, 5, 5, 5, 5, 4, 3, 2, 1, 0 },
{ 0, 1, 2, 3, 4, 5, 6, 6, 6, 5, 4, 3, 2, 1, 0 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 3, 2, 1, 0 },
{ 0, 1, 2, 3, 4, 5, 6, 6, 6, 5, 4, 3, 2, 1, 0 },
{ 0, 1, 2, 3, 4, 5, 5, 5, 5, 5, 4, 3, 2, 1, 0 },
{ 0, 1, 2, 3, 4, 4, 4, 4, 4, 4, 4, 3, 2, 1, 0 },
{ 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0 },
{ 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0 },
{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } };
public static final int BOARD_SIZE = 15;// 棋盘格数
public static final int BT = BOARD_SIZE + 2;
public static final int CENTER = BOARD_SIZE / 2 + 1;// 中心点
private int minx, maxx, miny, maxy; // 当前棋局下所有棋子的最小x,最大x,最小y,最大y,用于缩小搜索落子点的范围
private int currentPlayer = 0;// 当前玩家
private Stack<Point> history;// 落子历史记录
private Chess[][] data;// 1-15
private Chess[] sorted;// 根据各点的落子估值从大到小排序的数组
public Board() {
data = new Chess[BT][BT];
for (int i = 0; i < BT; i++)
for (int j = 0; j < BT; j++) {
data[i][j] = new Chess(i, j);
if (i == 0 || i == BT - 1 || j == 0 || j == BT - 1)
data[i][j].setSide(Chess.BORDER);// 边界
}
history = new Stack<Point>();
}
public Board(Board b) {// 深度拷贝
Chess[][] b_data = b.getData();
Chess[] b_sorted = b.getSorted();
data = new Chess[BT][BT];
for (int i = 0; i < BT; i++)
for (int j = 0; j < BT; j++) {
data[i][j] = new Chess(i, j);
Chess c = b_data[i][j];
data[i][j].sum = c.sum;
data[i][j].defence = c.defence;
data[i][j].offense = c.offense;
data[i][j].side = c.side;
}
sorted = new Chess[b_sorted.length];
for (int i = 0; i < sorted.length; i++) {
Chess c = b_sorted[i];
sorted[i] = new Chess(c.x, c.y);
sorted[i].sum = c.sum;
sorted[i].defence = c.defence;
sorted[i].offense = c.offense;
sorted[i].side = c.side;
}
currentPlayer = b.getPlayer();
minx = b.minx;
maxx = b.maxx;
miny = b.miny;
maxy = b.maxy;
history = new Stack<Point>();
}
public void start() {
currentPlayer = Chess.BLACK;// 默认黑子先行
putChess(CENTER, CENTER);// 默认第一步落在中心
minx = maxx = miny = maxy = CENTER;
}
public void reset() {
for (int i = 1; i < BT - 1; i++)
for (int j = 1; j < BT - 1; j++) {
data[i][j].reset();
}
history.clear();
}
public Point undo() {// 悔棋
if (!history.isEmpty()) {
Point p1 = history.pop();
Point p2 = history.pop();
data[p1.x][p1.y].setSide(Chess.EMPTY);
data[p2.x][p2.y].setSide(Chess.EMPTY);
return history.peek();
}
return null;
}
public Chess[][] getData() {
return data;
}
public Chess[] getSorted() {
return sorted;
}
public int getPlayer() {
return currentPlayer;
}
public int[][] getHistory() {
int length = history.size();
int[][] array = new int[length][2];
for (int i = 0; i < length; i++)
for (int j = 0; j < 2; j++) {
Point p = history.get(i);
array[i][0] = (int) p.getX();
array[i][1] = (int) p.getY();
}
return array;
}
/**
* 在点(x,y)落子
*/
public boolean putChess(int x, int y) {
if (data[x][y].isEmpty()) {
// 棋盘搜索范围限制
minx = Math.min(minx, x);
maxx = Math.max(maxx, x);
miny = Math.min(miny, y);
maxy = Math.max(maxy, y);
data[x][y].setSide(currentPlayer);
history.push(new Point(x, y));
trogglePlayer();
sorted = getSortedChess(currentPlayer);// 重要
System.out.printf(" 【" + (char) (64 + x) + (16 - y) + "】");
return true;
}
return false;
}
private void trogglePlayer() {
currentPlayer = 3 - currentPlayer;
};
private int check(int x, int y, int dx, int dy, int chess) {
int sum = 0;
for (int i = 0; i < 4; ++i) {
x += dx;
y += dy;
if (x < 1 || x > BOARD_SIZE || y < 1 || y > BOARD_SIZE) {
break;
}
if (data[x][y].getSide() == chess) {
sum++;
} else {
break;
}
}
return sum;
}
public int isGameOver() {
if (!history.isEmpty()) {
int chess = (history.size() % 2 == 1) ? Chess.BLACK : Chess.WHITE;
Point lastStep = history.peek();
int x = (int) lastStep.getX();
int y = (int) lastStep.getY();
if (check(x, y, 1, 0, chess) + check(x, y, -1, 0, chess) >= 4) {
return chess;
}
if (check(x, y, 0, 1, chess) + check(x, y, 0, -1, chess) >= 4) {
return chess;
}
if (check(x, y, 1, 1, chess) + check(x, y, -1, -1, chess) >= 4) {
return chess;
}
if (check(x, y, 1, -1, chess) + check(x, y, -1, 1, chess) >= 4) {
return chess;
}
}
// 进行中
for (int i = 0; i < BOARD_SIZE; ++i) {
for (int j = 0; j < BOARD_SIZE; ++j)
if (data[i][j].isEmpty()) {
return 0;
}
}
// 平局
return 3;
}
/**
* 玩家(player)轮,根据各点的落子估值从大到小排序
*
*/
public Chess[] getSortedChess(int player) {
// 限制范围
int px = Math.max(minx - 5, 1);
int py = Math.max(miny - 5, 1);
int qx = Math.min(maxx + 5, Board.BT - 1);
int qy = Math.min(maxy + 5, Board.BT - 1);
Chess[] temp = new Chess[(qx - px + 1) * (qy - py + 1)];
int count = 0;
for (int x = px; x <= qx; x++) {
for (int y = py; y <= qy; y++) {
temp[count] = new Chess(x, y);
if (data[x][y].isEmpty()) {
data[x][y].clearDetail();
data[x][y].append("================================\n");
int o = getScore(x, y, player) + 1;// 攻击分,优先
data[x][y].append("\n");
int d = getScore(x, y, 3 - player);// 防守分
data[x][y].append("\n");
String cs = "【" + (char) (64 + x) + (16 - y) + "】 ";
data[x][y].append(cs).append(" 攻击:" + o).append(" 防守:" + d)
.append("\n\n");
data[x][y].offense = temp[count].offense = o;
data[x][y].defence = temp[count].defence = d;
data[x][y].sum = temp[count].sum = o + d;// 综合分
}
count++;
}
}
Arrays.sort(temp);
return temp;
}
/**
* 在点(x,y)落下棋子(chess)后的落子估值
*
*/
public int getScore(int x, int y, int chess) {
data[x][y].append("-");
Level l1 = getLevel(x, y, Direction.HENG, chess);
data[x][y].append("|");
Level l2 = getLevel(x, y, Direction.SHU, chess);
data[x][y].append("/");
Level l3 = getLevel(x, y, Direction.PIE, chess);
data[x][y].append("\\");
Level l4 = getLevel(x, y, Direction.NA, chess);
return level2Score(l1, l2, l3, l4) + position[x - 1][y - 1];
}
/**
* 在点(x,y)落下棋子(chess)后, 方向(direction)形成的棋型
*
*/
public Level getLevel(int x, int y, Direction direction, int chess) {
String seq, left = "", right = "";
if (direction == Direction.HENG) {
left = getHalfSeq(x, y, -1, 0, chess);
right = getHalfSeq(x, y, 1, 0, chess);
} else if (direction == Direction.SHU) {
left = getHalfSeq(x, y, 0, -1, chess);
right = getHalfSeq(x, y, 0, 1, chess);
} else if (direction == Direction.PIE) {
left = getHalfSeq(x, y, -1, 1, chess);
right = getHalfSeq(x, y, 1, -1, chess);
} else if (direction == Direction.NA) {
left = getHalfSeq(x, y, -1, -1, chess);
right = getHalfSeq(x, y, 1, 1, chess);
}
seq = left + chess + right;
String rseq = new StringBuilder(seq).reverse().toString();
data[x][y].append("\t" + seq + "\t");
// seq2Level
for (Level level : Level.values()) {
Pattern pat = Pattern.compile(level.regex[chess - 1]);
Matcher mat = pat.matcher(seq);
boolean rs1 = mat.find();
mat = pat.matcher(rseq);
boolean rs2 = mat.find();
if (rs1 || rs2) {
data[x][y].append(level.name).append("\n");
return level;
}
}
return Level.NULL;
}
private String getHalfSeq(int x, int y, int dx, int dy, int chess) {
String sum = "";
boolean isR = false;
if (dx < 0 || (dx == 0 && dy == -1))
isR = true;
for (int i = 0; i < 5; ++i) {
x += dx;
y += dy;
if (x < 1 || x > BOARD_SIZE || y < 1 || y > BOARD_SIZE) {
break;
}
if (isR) {
sum = data[x][y].getSide() + sum;
} else
sum = sum + data[x][y].getSide();
}
return sum;
}
/**
* 将各方向的棋型统计成初步的打分
*/
public int level2Score(Level l1, Level l2, Level l3, Level l4) {
int size = Level.values().length;
int[] levelCount = new int[size];
for (int i = 0; i < size; i++) {
levelCount[i] = 0;
}
levelCount[l1.index]++;
levelCount[l2.index]++;
levelCount[l3.index]++;
levelCount[l4.index]++;
int score = 0;
if (levelCount[Level.GO_4.index] >= 2
|| levelCount[Level.GO_4.index] >= 1
&& levelCount[Level.ALIVE_3.index] >= 1)// 双活4,冲4活三
score = 10000;
else if (levelCount[Level.ALIVE_3.index] >= 2)// 双活3
score = 5000;
else if (levelCount[Level.SLEEP_3.index] >= 1
&& levelCount[Level.ALIVE_3.index] >= 1)// 活3眠3
score = 1000;
else if (levelCount[Level.ALIVE_2.index] >= 2)// 双活2
score = 100;
else if (levelCount[Level.SLEEP_2.index] >= 1
&& levelCount[Level.ALIVE_2.index] >= 1)// 活2眠2
score = 10;
score = Math.max(
score,
Math.max(Math.max(l1.score, l2.score),
Math.max(l3.score, l4.score)));
return score;
}
}
//Brain类
package AIGobang;
/**
* @author Jianxin.You
*/
public class Brain {
private Board bd;
private int INFINITY = 1000000;
private int movex, movey;
private int level;// 深度
private int node;// 每层结点
public Brain(Board bd, int level, int node) {
this.bd = bd;
this.level = level;
this.node = node;
}
// 估值函数
public int[] findOneBestStep() {
Chess[] arr = bd.getSortedChess(bd.getPlayer());
Chess c = bd.getData()[arr[0].x][arr[0].y];
int[] result = { c.x, c.y };
return result;
}
// 估值函数+搜索树
public int[] findTreeBestStep() {
alpha_beta(0, bd, -INFINITY, INFINITY);
int[] result = { movex, movey };
return result;
}
// alpha-beta剪枝搜索算法
public int alpha_beta(int depth, Board board, int alpha, int beta) {
if (depth == level || board.isGameOver() != 0) {
Chess[] sorted = board.getSorted();
Chess move = board.getData()[sorted[0].x][sorted[0].y];
// 搜索树辅助输出
System.out.println("\t- " + "【" + (char) (64 + move.x)
+ (16 - move.y) + "】," + move.getSum());
return move.getSum();// 局面估分
}
// 对局面下得分最高的几个点进行拓展
Board temp = new Board(board);
Chess[] sorted = temp.getSorted();
int score;
for (int i = 0; i < node; i++) {
int x = sorted[i].x;
int y = sorted[i].y;
// 搜索树辅助输出
if (depth >= 1) {
System.out.println();
for (int k = 0; k < depth; k++)
System.out.printf("\t");
}
// 走这个走法
if (!temp.putChess(x, y))
continue;
if (sorted[i].getOffense() >= Board.Level.ALIVE_4.score) {
System.out.println("我们快要赢啦!");
score = INFINITY + 1;
} else if (sorted[i].getDefence() >= Board.Level.ALIVE_4.score) {
System.out.println("对方快要赢啦!");
score = INFINITY;
} else {
score = alpha_beta(depth + 1, temp, alpha, beta);
}
temp = new Board(board);// 撤消这个走法
if (depth % 2 == 0) {// MAX
if (score > alpha) {
alpha = score;
if (depth == 0) {
movex = x;
movey = y;
}
}
if (alpha >= beta) {
score = alpha;
// System.out.println(" beta剪枝");
return score;
}
} else {// MIN
if (score < beta) {
beta = score;
}
if (alpha >= beta) {
score = beta;
// System.out.println(" alpha剪枝");
return score;
}
}
}
return depth % 2 == 0 ? alpha : beta;
}
}
package AIGobang;
//Chess类
/**
* @author Jianxin.You
*/
public class Chess implements Comparable<Chess> {
public static final int BLACK = 1;
public static final int WHITE = 2;
public static final int BORDER = -1;
public static final int EMPTY = 0;
protected int x;
protected int y;
protected int offense;//攻击分
protected int defence;//防守分
protected int sum;//综合分
protected int side;//落子
private StringBuilder detail;//该点的落子估值
public Chess(int x, int y) {
this.x = x;
this.y = y;
detail = new StringBuilder();
}
public int getOffense() {
return offense;
}
public void setOffense(int offense) {
this.offense = offense;
}
public int getDefence() {
return defence;
}
public void setDefence(int defence) {
this.defence = defence;
}
public int getSum() {
return sum;
}
public void setSum(int sum) {
this.sum = sum;
}
public int getSide() {
return side;
}
public void setSide(int side) {
this.side = side;
}
public String getDetail() {
return detail.toString();
}
public StringBuilder append(String more) {
return this.detail.append(more);
}
//清空
public void reset() {
clearDetail();
offense = defence = sum = 0;
side = EMPTY;
}
public void clearDetail() {
detail = new StringBuilder();
}
public String toString() {
return String.format(x + "," + y + "-(" + (char) (64 + x) + ","
+ (16 - y) + ") " + offense + "," + defence + "," + sum);
}
public boolean isEmpty() {
return side == EMPTY ? true : false;
}
//重写比较,从大到小
@Override
public int compareTo(Chess o) {
if (o == null)
return 0;
int val1 = sum;
int val2 = o.getSum();
if (val1 == val2)
return 0;
else if (val1 < val2)
return 1;
else
return -1;
}
}
//GobangFrame类
package AIGobang;
import javax.swing.*;
import javax.swing.border.TitledBorder;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
* @author Jianxin.You
*/
public class GobangFrame extends JFrame {
private static final long serialVersionUID = -7844061449912554572L;
JRadioButton manualBtn = new JRadioButton("双人");
JRadioButton halfAutoBtn = new JRadioButton("人机", true);
JRadioButton autoBtn = new JRadioButton("双机");
JCheckBox orderBtn = new JCheckBox("显示落子顺序");
JRadioButton oneBtn = new JRadioButton("估值函数");
JRadioButton treeBtn = new JRadioButton("估值函数+搜索树", true);
JComboBox<Integer> levelCombo = new JComboBox<Integer>(new Integer[] { 1,
2, 3 });
JComboBox<Integer> nodeCombo = new JComboBox<Integer>(new Integer[] { 3, 5,
10 });
JButton btn = new JButton("新游戏");
JButton undoBtn = new JButton("悔棋");
TextArea area = new TextArea();
GobangPanel panel = new GobangPanel(area);// 棋盘面板
public GobangFrame() {
super("智能五子棋");
add(panel, BorderLayout.WEST);
ButtonGroup grp_mode = new ButtonGroup();
grp_mode.add(manualBtn);
grp_mode.add(halfAutoBtn);
grp_mode.add(autoBtn);
ButtonGroup grp_alg = new ButtonGroup();
grp_alg.add(oneBtn);
grp_alg.add(treeBtn);
JPanel rightPanel = new JPanel();
area.setEditable(false);
rightPanel.setLayout(new BoxLayout(rightPanel, BoxLayout.Y_AXIS));
JPanel panel1 = new JPanel(new BorderLayout());
panel1.setBorder(new TitledBorder("在棋盘上单击鼠标右键,查看各点估值"));
panel1.add(area);
rightPanel.add(panel1);
JPanel optPanel = new JPanel();
optPanel.setLayout(new BoxLayout(optPanel, BoxLayout.Y_AXIS));
optPanel.setBorder(new TitledBorder("游戏设置"));
JPanel panel2 = new JPanel();
panel2.setBorder(new TitledBorder("模式"));
panel2.add(manualBtn);
panel2.add(halfAutoBtn);
panel2.add(autoBtn);
optPanel.add(panel2);
JPanel panel3 = new JPanel();
panel3.setBorder(new TitledBorder("智能"));
panel3.add(oneBtn);
panel3.add(treeBtn);
optPanel.add(panel3);
JPanel panel4 = new JPanel();
panel4.setBorder(new TitledBorder("搜索树"));
panel4.add(new JLabel("搜索深度"));
panel4.add(levelCombo);
panel4.add(new JLabel("每层节点"));
panel4.add(nodeCombo);
optPanel.add(panel4);
optPanel.add(btn);
rightPanel.add(optPanel);
JPanel panel5 = new JPanel();
panel5.setBorder(new TitledBorder("其他"));
panel5.add(orderBtn);
panel5.add(undoBtn);
rightPanel.add(panel5);
add(rightPanel);
btn.addActionListener(l);
orderBtn.addActionListener(l);
undoBtn.addActionListener(l);
setSize(900, 700);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
private ActionListener l = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if (source == btn) {
int mode = -1, intel = -1, level, node;
if (manualBtn.isSelected())
mode = GobangPanel.MANUAL;
else if (halfAutoBtn.isSelected())
mode = GobangPanel.HALF;
else if (autoBtn.isSelected())
mode = GobangPanel.AUTO;
if (oneBtn.isSelected())
intel = GobangPanel.EVAL;
else if (treeBtn.isSelected())
intel = GobangPanel.TREE;
level = (Integer) levelCombo.getSelectedItem();
node = (Integer) nodeCombo.getSelectedItem();
panel.startGame(mode, intel, level, node);
} else if (source == orderBtn) {
panel.troggleOrder();
} else if (source == undoBtn) {
panel.undo();
}
}
};
}
//GobangPanel类
package AIGobang;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Timer;
import java.util.TimerTask;
/**
* @author Jianxin.You
*/
public class GobangPanel extends JPanel {
private static final long serialVersionUID = 667503661521167626L;
private final int OFFSET = 40;// 棋盘偏移
private final int CELL_WIDTH = 40;// 棋格宽度
private int computerSide = Chess.BLACK;// 默认机器持黑
private int humanSide = Chess.WHITE;
private int cx = Board.CENTER, cy = Board.CENTER;
private boolean isShowOrder = false;// 显示落子顺序
private int[] lastStep;// 上一个落子点
private Board bd;// 棋盘,重要
private Brain br;// AI,重要
public static final int MANUAL = 0;// 双人模式
public static final int HALF = 1;// 人机模式
public static final int AUTO = 2;// 双机模式
public static final int EVAL = 3;// 估值函数
public static final int TREE = 4;// 估值函数+搜索树
private int mode;// 模式
private int intel;// 智能
private boolean isGameOver = true;
private TextArea area;
// 显示落子顺序
public void troggleOrder() {
isShowOrder = !isShowOrder;
repaint();
}
// 悔棋
public void undo() {
Point p = bd.undo();
lastStep[0] = p.x;
lastStep[1] = p.y;
repaint();
}
public GobangPanel(TextArea area) {
this.area = area;
lastStep = new int[2];
addMouseMotionListener(mouseMotionListener);
addMouseListener(mouseListener);
this.setBackground(Color.ORANGE);
setPreferredSize(new Dimension(650, 700));
bd = new Board();
}
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
super.paintComponent(g2d);
g2d.setStroke(new BasicStroke(2));
g2d.setFont(new Font("April", Font.BOLD, 12));
// 画棋盘
drawBoard(g2d);
// 画天元和星
drawStar(g2d, Board.CENTER, Board.CENTER);
drawStar(g2d, (Board.BOARD_SIZE + 1) / 4, (Board.BOARD_SIZE + 1) / 4);
drawStar(g2d, (Board.BOARD_SIZE + 1) / 4,
(Board.BOARD_SIZE + 1) * 3 / 4);
drawStar(g2d, (Board.BOARD_SIZE + 1) * 3 / 4,
(Board.BOARD_SIZE + 1) / 4);
drawStar(g2d, (Board.BOARD_SIZE + 1) * 3 / 4,
(Board.BOARD_SIZE + 1) * 3 / 4);
// 画数字和字母
drawNumAndLetter(g2d);
// 画提示框
drawCell(g2d, cx, cy, 0);
if (!isGameOver) {
// 画所有棋子
for (int x = 1; x <= Board.BOARD_SIZE; ++x) {
for (int y = 1; y <= Board.BOARD_SIZE; ++y) {
drawChess(g2d, x, y, bd.getData()[x][y].getSide());
}
}
// 画顺序
if (isShowOrder)
drawOrder(g2d);
else {
if (lastStep[0] > 0 && lastStep[1] > 0) {
g2d.setColor(Color.RED);
g2d.fillRect((lastStep[0] - 1) * CELL_WIDTH + OFFSET
- CELL_WIDTH / 10, (lastStep[1] - 1) * CELL_WIDTH
+ OFFSET - CELL_WIDTH / 10, CELL_WIDTH / 5,
CELL_WIDTH / 5);
}
}
}
}
// 画棋盘
private void drawBoard(Graphics g2d) {
for (int x = 0; x < Board.BOARD_SIZE; ++x) {
g2d.drawLine(x * CELL_WIDTH + OFFSET, OFFSET, x * CELL_WIDTH
+ OFFSET, (Board.BOARD_SIZE - 1) * CELL_WIDTH + OFFSET);
}
for (int y = 0; y < Board.BOARD_SIZE; ++y) {
g2d.drawLine(OFFSET, y * CELL_WIDTH + OFFSET,
(Board.BOARD_SIZE - 1) * CELL_WIDTH + OFFSET, y
* CELL_WIDTH + OFFSET);
}
}
// 画天元和星
private void drawStar(Graphics g2d, int cx, int cy) {
g2d.fillOval((cx - 1) * CELL_WIDTH + OFFSET - 4, (cy - 1) * CELL_WIDTH
+ OFFSET - 4, 8, 8);
}
// 画数字和字母
private void drawNumAndLetter(Graphics g2d) {
FontMetrics fm = g2d.getFontMetrics();
int stringWidth, stringAscent;
stringAscent = fm.getAscent();
for (int i = 1; i <= Board.BOARD_SIZE; i++) {
String num = String.valueOf(Board.BOARD_SIZE - i + 1);
stringWidth = fm.stringWidth(num);
g2d.drawString(String.valueOf(Board.BOARD_SIZE - i + 1), OFFSET / 4
- stringWidth / 2, OFFSET + (CELL_WIDTH * (i - 1))
+ stringAscent / 2);
String letter = String.valueOf((char) (64 + i));
stringWidth = fm.stringWidth(letter);
g2d.drawString(String.valueOf((char) (64 + i)), OFFSET
+ (CELL_WIDTH * (i - 1)) - stringWidth / 2, OFFSET * 3 / 4
+ OFFSET + CELL_WIDTH * (Board.BOARD_SIZE - 1)
+ stringAscent / 2);
}
}
// 画棋子
private void drawChess(Graphics g2d, int cx, int cy, int player) {
if (player == 0)
return;
int size = CELL_WIDTH * 5 / 6;
g2d.setColor(player == Chess.BLACK ? Color.BLACK : Color.WHITE);
g2d.fillOval((cx - 1) * CELL_WIDTH + OFFSET - size / 2, (cy - 1)
* CELL_WIDTH - size / 2 + OFFSET, size, size);
}
// 画预选框
private void drawCell(Graphics g2d, int x, int y, int c) {// c 是style
int length = CELL_WIDTH / 4;
int xx = (x - 1) * CELL_WIDTH + OFFSET;
int yy = (y - 1) * CELL_WIDTH + OFFSET;
int x1, y1, x2, y2, x3, y3, x4, y4;
x1 = x4 = xx - CELL_WIDTH / 2;
x2 = x3 = xx + CELL_WIDTH / 2;
y1 = y2 = yy - CELL_WIDTH / 2;
y3 = y4 = yy + CELL_WIDTH / 2;
g2d.setColor(Color.RED);
g2d.drawLine(x1, y1, x1 + length, y1);
g2d.drawLine(x1, y1, x1, y1 + length);
g2d.drawLine(x2, y2, x2 - length, y2);
g2d.drawLine(x2, y2, x2, y2 + length);
g2d.drawLine(x3, y3, x3 - length, y3);
g2d.drawLine(x3, y3, x3, y3 - length);
g2d.drawLine(x4, y4, x4 + length, y4);
g2d.drawLine(x4, y4, x4, y4 - length);
}
// 画落子顺序
private void drawOrder(Graphics g2d) {
int[][] history = bd.getHistory();
if (history.length > 0) {
g2d.setColor(Color.RED);
for (int i = 0; i < history.length; i++) {
int x = history[i][0];
int y = history[i][1];
String text = String.valueOf(i + 1);
// 居中
FontMetrics fm = g2d.getFontMetrics();
int stringWidth = fm.stringWidth(text);
int stringAscent = fm.getAscent();
g2d.drawString(text, (x - 1) * CELL_WIDTH + OFFSET
- stringWidth / 2, (y - 1) * CELL_WIDTH + OFFSET
+ stringAscent / 2);
}
}
}
// 开始游戏
public void startGame(int mode, int intel, int level, int node) {
if (isGameOver) {
this.mode = mode;
this.intel = intel;
bd.reset();
area.setText("");
lastStep[0] = lastStep[1] = Board.CENTER;
br = new Brain(bd, level, node);
bd.start();
isGameOver = false;
JOptionPane.showMessageDialog(GobangPanel.this, "游戏开始!");
repaint();
if (mode == AUTO) {// 双机
Timer t = new Timer(true);
t.schedule(new ComputurTask(), 0, 500);
}
} else {
JOptionPane.showMessageDialog(GobangPanel.this,
"游戏进行中...这局完了再重新开始吧!");
}
}
// 鼠标移动
private MouseMotionListener mouseMotionListener = new MouseMotionAdapter() {
public void mouseMoved(MouseEvent e) {
int tx = Math.round((e.getX() - OFFSET) * 1.0f / CELL_WIDTH) + 1;
int ty = Math.round((e.getY() - OFFSET) * 1.0f / CELL_WIDTH) + 1;
if (tx != cx || ty != cy) {
if (tx >= 1 && tx <= Board.BOARD_SIZE && ty >= 1
&& ty <= Board.BOARD_SIZE) {
setCursor(new Cursor(Cursor.HAND_CURSOR));
repaint();
} else
setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
cx = tx;
cy = ty;
}
}
};
// 鼠标点击
private MouseListener mouseListener = new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (isGameOver) {
JOptionPane.showMessageDialog(GobangPanel.this, "请开始新游戏!");
return;
}
int x = Math.round((e.getX() - OFFSET) * 1.0f / CELL_WIDTH) + 1;
int y = Math.round((e.getY() - OFFSET) * 1.0f / CELL_WIDTH) + 1;
if (cx >= 1 && cx <= Board.BOARD_SIZE && cy >= 1
&& cy <= Board.BOARD_SIZE) {
if (mode == MANUAL) {// 双人
int mods = e.getModifiers();
if ((mods & InputEvent.BUTTON3_MASK) != 0) {// 鼠标右键
area.append(bd.getData()[x][y].getDetail());
} else if ((mods & InputEvent.BUTTON1_MASK) != 0)// 鼠标左键
putChess(x, y);
} else if (mode == HALF) {// 人机
if (bd.getPlayer() == humanSide) {
int mods = e.getModifiers();
if ((mods & InputEvent.BUTTON3_MASK) != 0) {// 鼠标右键
area.append(bd.getData()[x][y].getDetail());
} else if ((mods & InputEvent.BUTTON1_MASK) != 0) {// 鼠标左键
if (putChess(x, y)) {
System.out.println("\n----白棋完毕----");
if (intel == EVAL) {
int[] bestStep = br.findOneBestStep();// 估值函数AI
putChess(bestStep[0], bestStep[1]);
} else if (intel == TREE) {
int[] bestStep = br.findTreeBestStep();// 估值函数+搜索树AI
putChess(bestStep[0], bestStep[1]);
}
System.out.println("\n----黑棋完毕----");
}
}
}
}
}
}
};
private boolean putChess(int x, int y) {
if (bd.putChess(x, y)) {
lastStep[0] = x;// 保存上一步落子点
lastStep[1] = y;
repaint();
int winSide = bd.isGameOver();// 判断终局
if (winSide > 0) {
if (winSide == humanSide) {
JOptionPane.showMessageDialog(GobangPanel.this, "白方赢了!");
} else if (winSide == computerSide) {
JOptionPane.showMessageDialog(GobangPanel.this, "黑方赢了!");
} else {
JOptionPane.showMessageDialog(GobangPanel.this, "双方平手");
}
// 清除
bd.reset();
area.setText("");
isGameOver = true;
repaint();
return false;
}
return true;
}
return false;
}
// 双机
private class ComputurTask extends TimerTask {
@Override
public void run() {
int[] bestStep = br.findTreeBestStep();
if (!putChess(bestStep[0], bestStep[1]))
this.cancel();
}
}
}
//GobangTest类
package AIGobang;
public class GobangTest {
public static void main(String args[]) {
GobangFrame frame = new GobangFrame();
}
}