1、 掌握JavaSwing
2、 掌握 Java 基本语法
3、 设计游戏算法
本项目使用一个游戏界面,在游戏界面中实现人机对战功能,同时还需要有“重来一局”,“玩家先手”,“机器先手”,“退出游戏“的功能。
首先我们要设计一个游戏界面,定义一个类GameUI,用来作为游戏的界面。一般来讲,我们可以让GameUI类继承JFrame直接作为窗口的子类,但对于复杂的界面设计我们往往需要对布局管理器组合使用,达到较为复杂的布局效果。所以此时我们就需要借助容器类JPanel来达到这一目的。
使用语句:public class GameUI extends JPanel
在GameUI中有JFrame类成员变量frame,用来显示游戏界面,同时需要定义方法来初始化游戏界面。还需要在该窗口中设置菜单栏,用来控制游戏的先后顺序,重新开局以及退出游戏的功能菜单。
public void initUI() {
//GameUI继承自JPanel容器类,类似于JavaFX中的Scene
//在GameUI中创建一个JFrame,并让GameUI成为其容器,来显示容器中的节点
// 设置游戏窗口的尺寸
frame.setSize(800, 850);
// 设置居中显示
frame.setLocationRelativeTo(null);
// 设置退出进程,参数为3,仅在应用程序中使用,结束应用程序。
frame.setDefaultCloseOperation(3);
//边框布局
frame.setLayout(new BorderLayout());
//在JavaSwing中,要想能够不让节点占满整个窗口,必须设置布局类
//使用与JPanel相关的类时,使用的布局为BorderLayout(边框布局)
//北边的窗口默认是流式布局
JPanel northPanel = new JPanel();
//设置窗口上方容器的背景颜色
northPanel.setBackground(Color.green);
//在窗口中添加菜单栏
//菜单栏的结构为:子菜单(JMenuItem)-->菜单(JMenu)-->菜单栏(JMenuBar)
//注意,在菜单栏中,只有子菜单(JMenuItem)才可以添加事件监听器。
JMenuBar jbr = new JMenuBar();
JMenu menu1 = new JMenu("顺序");
JMenu menu2 = new JMenu("操作");
//这里是给菜单栏添加菜单
jbr.add(menu1);
jbr.add(menu2);
JMenuItem jm1 = new JMenuItem("玩家先手");
JMenuItem jm2 = new JMenuItem("机器先手");
JMenuItem jm3 = new JMenuItem("悔棋");
JMenuItem jm4 = new JMenuItem("重来");
//这里是给菜单添加子菜单
menu1.add(jm1);
menu1.add(jm2);
menu2.add(jm3);
menu2.add(jm4);
//使用边框布局将菜单栏设置在窗口的“北方”
frame.add(jbr, BorderLayout.NORTH);
this.setBackground(Color.YELLOW);
GameMouse mouse = new GameMouse(this,chessValue);
//给子菜单添加事件监听器,用于实现相应的功能
jm1.addActionListener(mouse);
jm2.addActionListener(mouse);
jm3.addActionListener(mouse);
jm4.addActionListener(mouse);
//给窗口添加容器,并设置容器在窗口中的位置,因为将该容器设置在窗口的上方,默认为流式布局
frame.add(northPanel,BorderLayout.NORTH);
// 设置游戏界面容器的尺寸
this.setPreferredSize(new Dimension(800, 700));
//设置GameUI容器类的背景颜色,用来与上面定义的窗口容器做区分。
this.setBackground(Color.YELLOW);
//给按钮添加事件监听器(这个事件监听器是我们自己重新定义的监听器的子类,在下方会讲解)
GameMouse mouse = new GameMouse(this,chessValue);
bt1.addActionListener(mouse);
bt2.addActionListener(mouse);
bt3.addActionListener(mouse);
//给窗口添加这个容器,并将该容器类放在窗口中间。
frame.add(this, BorderLayout.CENTER);
//设置窗体可见,必须有该语句,否则窗体将不可见,界面将没有意义。
frame.setVisible(true);
//画笔:图形画在那个组件上,画笔就从该组件上获取
//从窗体获取画笔对象,一定要在窗体显示可见之后
//在界面中,我们需要将棋盘和棋子显示出来,我们需要借助画笔来完成。
//将画笔定义在我们自定义的GameUI上,在容器中画图。
Graphics g = this.getGraphics();
//将棋盘传到GameUI中,获取当前棋局,用于画出棋盘以及判断输赢。
chess = mouse.setChess();
//用于获取当前棋子的坐标
xx = mouse.setX();
yy = mouse.setY();
//给窗体添加鼠标监听器方法
this.addMouseListener(mouse);
mouse.setGr(g);
在JavaSwing中,当我们改变窗口的状态,窗口将会重新绘制,而如果我们没有重新绘制棋盘和棋子,则一旦我们移动,或是拉伸游戏界面,游戏界面中相关的游戏元素(棋盘,棋子)都将会消失。所以为防止这个问题,我们需要重写绘制窗体的paint方法。(这个paint方法不是由用户调用的,而是由虚拟机自动调用的,所以当我们运行整个程序时,paint方法将会自动执行)
在paint方法中,我们需要绘制棋盘以及棋子。但在此之前,我们可以定义一个接口来存储一些棋盘大小,间隔以及棋子大小之类的参数,以便后续对棋盘大小进行修改。
public interface Config {
//定义棋盘最左上角顶点的坐标
public static final int X0 = 25;
public static final int Y0 = 25;
//定义棋盘线条之间的宽度
public static final int SIZE = 50;
//定义棋盘中线条个数
public static final int COUNT = 15;}
在paint方法中借助Config接口中的参数,来绘制棋局
public void paint(Graphics g){
//首先调用父类的绘图方法
super.paint(g);
//给窗口添加背景图片
//ImageIcon image = new ImageIcon("d:/res/1.jpg");
//g.drawImage(image.getImage(), 0, 0, 800, 780, null);
//借助Grapjics.drawLine(起点横坐标,起点纵坐标,终点横坐标,终点纵坐标)绘制棋盘
for(int i = 0; i < 15; i++) {
g.drawLine(X0, Y0 + SIZE * i, X0 + ( COUNT - 1) * SIZE, Y0 + SIZE * i);
}
for(int i = 0; i < 15; i++) {
g.drawLine(X0 + SIZE * i, Y0, X0 + SIZE * i, Y0 + SIZE * ( COUNT - 1));
}
//我们使用一个15*15的二维数组来存储棋盘,通过遍历这个二维数组来绘制棋局中的棋子
for(int i = 0; i < 15; i++) {
for(int j = 0; j < 15; j++) {
if(chess[i][j] == 1) {
//在整形数组中,我们使用1表示白棋,使用-1表示黑棋。
//并将数组坐标转换成像素坐标,在窗口相应的位置上显示相应颜色的棋子
g.setColor(Color.white);
g.fillOval(X0 + i * SIZE - 15, Y0 + j * SIZE - 15, 30, 30);
}
else if(chess[i][j] == -1) {
g.setColor(Color.black);
g.fillOval(X0 + i * SIZE - 15, Y0 + j * SIZE - 15, 30, 30);
}
}
}
//用于在控制台监督是否成功执行以上程序。
System.out.println("绘制棋盘");
}
在之前我们在GameUI模板子类中设置了菜单栏,菜单栏中的子菜单需要绑定事件监听器来实现相应的功能,对于菜单,按钮等窗口部件我们要对其设置动作事件监听器。同时,棋子是下在我们鼠标点击的位置上,所以还需要对面板,而如果我们一个一个地定义动作事件监听器的子类,程序将会变得非常麻烦。所以我们可以在同一个事件监听器的子类中,根据按钮的“名字”的不同来设置相应的功能,则将会很好的简化程序。
使用语句:public class GameMouse implements MouseListener, ActionListener, Config{}
在这个事件监听器子类中,我们需要四个成员变量
private Graphics gr;
private GameUI ui;
private int xx, yy
这两个变量一个是画笔,用来画棋子,另一个是游戏界面,用来时刻更新画面。
后面的两个整形变量是用来存储当前棋子的数组坐标
这两个成员变量的初始化我们放在构造方法中。同时我们还需要定义一个二维数组来存储棋局。二维数组中的元素可以为0,1,-1,其中0表示此处没有棋子,是空位;1表示此处是白棋,-1表示此处是黑棋。
定义一个方法,可以将GameMouse类中的画笔传给GameUI在GameUI(容器子类)所在的界面中显示棋子。
public GameMouse(GameUI ui,int[][] chessValue) {
this.ui = ui;
this.chessValue = chessValue;
}
public int [][] chess = new int[15][15];
public void setGr(Graphics g){
gr = g;
}
继承了接口需要重写其中的抽象函数
首先是mouseClicked(MouseEvent e)方法,这个方法是在鼠标事件发生时所进行的操作
首先我们要获取鼠标在窗口中点击处的坐标,由于棋子只能下在棋盘中横线和竖线的交点处,所以我们必须改正棋子的坐标,使之能落在交点处。其次我们还需要将像素坐标转换成数组坐标,同时在相应的下标元素中存储相应颜色的棋子。由于我们只能在空位处下棋,所以用画笔在鼠标点击位置(改正后)画下棋子,需要以chess[i][j]为前提
在每下一刻棋子后,我们都需要判断当前棋局是否结束(即有五子相连的情况)所以在mouseClicked(MouseEvent e)这个方法中,我们必须时刻监视棋局。而至于判断输赢,我们可以从水平,竖直,主对角线,次对角线这四个方向来判断。
具体的算法为:从当前所下的棋子开始遍历,以水平方向为例,可以先向左遍历
,当遍历到与该棋子颜色不同的棋子时,我们回到原先的棋子位置,并从他的右面的那个棋子开始遍历,直到遇到颜色与之不同的棋子。在遍历期间,我们需要使用一个变量来记录同色棋子的个数。当连续同色棋子达到5个时,会跳出提示窗口,并重新开始棋局。
public void mouseClicked(MouseEvent e) {
System.out.println("点击");
x1 = e.getX();
y1 = e.getY();
//计算交点坐标
//如果鼠标点击处位于网格中下方,则棋子应落在下面的交点处
//如果鼠标点击处位于网格上方,则棋子应落在上面的交点处,纵坐标同理
if((x1 - X0) % SIZE > SIZE / 2)
{
xx = (x1 - X0)/ SIZE + 1;
}
else
{
xx = (x1 - X0) / SIZE;
}
if((y1 - Y0) % SIZE > SIZE / 2)
{
yy = (y1 - Y0) / SIZE + 1;
}
else
{
yy = (y1 - Y0) / SIZE;
}
System.out.println("xx = " + xx + " yy = " + yy);
//画椭圆
if(chess[xx][yy] == 0) {
if(turn % 2 == 0) {
gr.setColor(Color.white);
gr.fillOval(X0 + xx * SIZE - 15, Y0 + yy * SIZE - 15, 30, 30);
chess[xx][yy] = 1;
}
else {
gr.setColor(Color.black);
gr.fillOval(X0 + xx * SIZE - 15, Y0 + yy * SIZE - 15, 30, 30);
chess[xx][yy] = -1;
}
}
//在玩家每下一颗棋子后,都要进行人机算法
ai();
printArray(chessValue);
checkSpWin(xx, yy);
checkVWin(xx, yy);
checkWin1(xx,yy);
checkWin2(xx, yy);
ui.repaint();
}
下面为四个方向上判断输赢的方法
//判断输赢
public void checkSpWin(int xx, int yy) {
int count = 0;
//判断水平方向输赢
//向左
for(int i = xx; i >= 0; i--) {
if(chess[i][yy] == chess[xx][yy])
count++;
else{
break;
}
}
//向右
for(int i = xx + 1; i < 15; i++) {
if(chess[i][yy] == chess[xx][yy])
count++;
else{
break;
}
}
if(count == 5) {
if(chess[xx][yy] == 1) {
JOptionPane.showMessageDialog(null,"白棋获胜");
for(int i = 0; i < 15; i++) {
for(int j = 0; j < 15; j++) {
chess[i][j] = 0;
}
}
}
else {
JOptionPane.showMessageDialog(null,"黑棋获胜");
for(int i = 0; i < 15; i++) {
for(int j = 0; j < 15; j++) {
chess[i][j] = 0;
}
}
}
}
}
public void checkVWin(int xx, int yy) {
int count = 0;
//判断垂直方向输赢
//向上
for(int i = yy; i >= 0; i--) {
if(chess[xx][i] == chess[xx][yy]) {
count++;
}
else
break;
}
//向下
for(int i = yy + 1; i < 15; i++) {
if(chess[xx][i] == chess[xx][yy]) {
count++;
}
else
break;
}
if(count == 5) {
if(chess[xx][yy] == 1) {
JOptionPane.showMessageDialog(null,"白棋获胜");
for(int i = 0; i < 15; i++) {
for(int j = 0; j < 15; j++) {
chess[i][j] = 0;
}
}
}
else {
JOptionPane.showMessageDialog(null,"黑棋获胜");
for(int i = 0; i < 15; i++) {
for(int j = 0; j < 15; j++) {
chess[i][j] = 0;
}
}
}
}
}
//判断主对角线方向
public void checkWin1(int xx, int yy) {
int count = 0;
//左上方向
for(int i = xx, j = yy; i >= 0&&j >= 0; i--,j--) {
if(chess[i][j] == chess[xx][yy]) {
count++;
}
else
break;
}
//右下方向
for(int i = xx + 1, j = yy + 1; i < 15&&j < 15; i++,j++) {
if(chess[i][j] == chess[xx][yy]) {
count++;
}
else
break;
}
if(count == 5) {
if(chess[xx][yy] == 1) {
JOptionPane.showMessageDialog(null,"白棋获胜");
for(int i = 0; i < 15; i++) {
for(int j = 0; j < 15; j++) {
chess[i][j] = 0;
}
}
}
else {
JOptionPane.showMessageDialog(null,"黑棋获胜");
for(int i = 0; i < 15; i++) {
for(int j = 0; j < 15; j++) {
chess[i][j] = 0;
}
}
}
}
}
//判断斜对角线方向
public void checkWin2(int xx, int yy) {
int count = 0;
//右上方向
for(int i = xx, j = yy; i < 15&&j >= 0; i++, j--) {
if(chess[i][j] == chess[xx][yy]) {
count++;
}
else
break;
}
//左下方向
for(int i = xx - 1, j = yy + 1; i >= 0 && j < 15; i--,j++) {
if(chess[i][j] == chess[xx][yy]) {
count++;
}
else
break;
}
if(count == 5) {
if(chess[xx][yy] == 1) {
JOptionPane.showMessageDialog(null,"白棋获胜");
for(int i = 0; i < 15; i++) {
for(int j = 0; j < 15; j++) {
chess[i][j] = 0;
}
}
}
else {
JOptionPane.showMessageDialog(null,"黑棋获胜");
for(int i = 0; i < 15; i++) {
for(int j = 0; j < 15; j++) {
chess[i][j] = 0;
}
}
}
}
}
除此之外,我们还需要重写ActionListener中的方法actionPerformed(ActionEvent e)。在这个方法中,是为了实现子菜单的功能。而为了在同一个动作监听器中给不同的子菜单实现不同的功能,我们需要借助他们之间唯一的不同点———名称不同来实现。我们通过ActionEvent.getActionCommand()方法来获取当前发生事件的事件源组件的名称,并借助条件分支语句根据不同的名称实现相应的功能。而且每个功能都会改变窗口的状态,所以需要重绘窗口,必须要用repaint()方法,否则窗口将无法实现其功能
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
String str = e.getActionCommand();
System.out.println("No Wrong");
if(str.equals("重来一局")) {
for(int i = 0; i < 15; i++) {
for(int j = 0; j < 15; j++) {
chess[i][j] = 0;
}
}
System.out.println("重来");
}
else if(str.equals("退出游戏")){
ui.close();
}
else if(str.equals("玩家先手")) {
turn = 1; //黑棋
for(int i = 0; i < 15; i++) {
for(int j = 0; j < 15; j++)
chess[i][j] = 0;
}
}
else if(str.equals("机器先手")) {
turn = 2; //下白棋
for(int i = 0; i < 15; i++) {
for(int j = 0; j < 15; j++)
chess[i][j] = 0;
}
chess[7][7] = -1;//在机器先手的情况下,我们可以让他下在棋盘的中央位置处。
}
ui.repaint();//每次改变都需要重新绘制棋盘。
}
由于我们将GameMouse的画笔传给GameUI,为了使得画笔可以在GameUI(容器)中画出同样的棋局,所以需要将存储棋局的二维数组chess[][]传递到GameUI中,并且我们还需要将当前棋子的坐标传递到GameUI中,以便实时监督棋局的输赢。定义方法如下:
public int[][] setChess(){
return this.chess;
}
public int setX() {
return this.xx;
}
public int setY() {
return this.yy;
}
到目前为止我们实现了大部分的功能,而现在我们只剩下最后的部分人机对战,这也是整个项目的核心部分。人机对战是指当玩家下完一个棋子后,计算机根据玩家所下棋子的位置来下对手棋,所以AI下棋肯定不是随意地去下,而是富有策略的。所以我们必须设计一个较为完美的算法,可以使得AI下棋更有难度,提高用户的游戏体验。
我们通常会采用“权值法”来设计AI算法
所谓“权值法”,是指我们给每种情况的棋局设置权值,获胜的概率越大,所设置的权值越大,然后遍历整个棋盘,计算每个空位的权值。然后在权值最大的位置下棋。同时我们还要注意下棋的顺序以及相对应棋子的颜色。而存储棋局我们可以使用“哈希表”,具体语句如下
private HashMap
将每一种棋局都转换成字符串的表示形式,例如两个白棋相连就表示成“11”,一黑一白则表示成“-11”或“11”以此类推,将大部分的情况都列出来,并赋予相应的权值。
我们举例:
hm.put(“1”,20);
hm.put(“11”,200);
hm.put(“111”,2000);
hm.put(“1111”,20000);
hm.put(“1-1”, 10);
hm.put("-1", 20);
hm.put("-1-11", 100);
hm.put("-111",1000 );
hm.put("-1111", 2000);
hm.put("-11111", 20000);
hm.put("-1-1-1-11",20000);
可以采用该形式来设置权值
//这部分的权值设置是随便写的,仅供测试。
public void ai(){
hm.put("1",20);
hm.put("11",200);
hm.put("111",2000);
hm.put("1111",20000);
hm.put("1-1", 10);
hm.put("-1", 20);
hm.put("-1-11", 100);
hm.put("-111",1000 );
hm.put("-1111", 2000);
hm.put("-11111", 20000);
hm.put("-1-1-1-11",20000);
//遍历整个棋盘
for(int i = 0; i < chess.length; i++) {
for(int j = 0; j < chess[i].length; j++) {
//判断此处是否为空位
if(chess[i][j] == 0) {
//搜索八个方向上的棋局情况
//定义两个变量。用来记录棋局情况以及棋子颜色。
String code = "";
int color = 0;
//向右
for(int k = i + 1; k < chess.length; k++) {
if(chess[k][j] == 0) {
break;//如果相邻出没下棋,则此空位不下棋
}
else {
if(color == 0) {
color = chess[k][j];//保存第一颗棋子的颜色
code = chess[k][j] + "";
}
else if(color == chess[k][j]) {
//如果机器所下的棋子的颜色与相邻处的棋子颜色相同,则记录该处的棋局,并继续循环记录
code += chess[k][j];
}
else {
//如果机器所下的棋子的颜色与相邻处的棋子颜色不同,则记录该处的棋局,并跳出循环停止记录
code += chess[k][j];
break;
}
}
}
//取出权值,累加
Integer value1 = hm.get(code);
if(value1 != null) {
chessValue[i][j] += value1;
}
code = "";
color = 0;
//向左
for(int k = i - 1; k >= 0; k--) {
if(chess[k][j] == 0) {
break;//如果相邻出没下棋,则此空位不下棋
}
else {
if(color == 0) {
color = chess[k][j];//保存第一颗棋子的颜色
code = chess[k][j] + "";
}
else if(color == chess[k][j]) {
//如果机器所下的棋子的颜色与相邻处的棋子颜色相同,则记录该处的棋局,并继续循环记录
code += chess[k][j];
}
else {
//如果机器所下的棋子的颜色与相邻处的棋子颜色不同,则记录该处的棋局,并跳出循环停止记录
code += chess[k][j];
break;
}
}
}
//取出权值,累加
Integer value2 = hm.get(code);
if(value2 != null) {
chessValue[i][j] += value2;
}
code = "";
color = 0;
//向上
for(int k = j - 1; k > 0; k--) {
if(chess[i][k] == 0) {
break;//如果相邻出没下棋,则此空位不下棋
}
else {
if(color == 0) {
color = chess[i][k];//保存第一颗棋子的颜色
code = chess[i][k] + "";
}
else if(color == chess[i][k]) {
//如果机器所下的棋子的颜色与相邻处的棋子颜色相同,则记录该处的棋局,并继续循环记录
code += chess[i][k];
}
else {
//如果机器所下的棋子的颜色与相邻处的棋子颜色不同,则记录该处的棋局,并跳出循环停止记录
code += chess[i][k];
break;
}
}
}
//取出权值,累加
Integer value3 = hm.get(code);
if(value3 != null) {
chessValue[i][j] += value3;
}
code = "";
color = 0;
//向下
for(int k = j + 1; k < chess.length - 1; k++) {
if(chess[i][k] == 0) {
break;//如果相邻出没下棋,则此空位不下棋
}
else {
if(color == 0) {
color = chess[i][k];//保存第一颗棋子的颜色
code = chess[i][k] + "";
}
else if(color == chess[i][k]) {
//如果机器所下的棋子的颜色与相邻处的棋子颜色相同,则记录该处的棋局,并继续循环记录
code += chess[i][k];
}
else {
//如果机器所下的棋子的颜色与相邻处的棋子颜色不同,则记录该处的棋局,并跳出循环停止记录
code += chess[i][k];
break;
}
}
}
//取出权值,累加
Integer value4 = hm.get(code);
if(value4 != null) {
chessValue[i][j] += value4;
}
code = "";
color = 0;
//左上
for(int k = i - 1, h = j - 1; k >= 0 && h >= 0; k--,h--) {
if(chess[k][h] == 0) {
break;//如果相邻出没下棋,则此空位不下棋
}
else {
if(color == 0) {
color = chess[k][h];//保存第一颗棋子的颜色
code = chess[k][h] + "";
}
else if(color == chess[k][h]) {
//如果机器所下的棋子的颜色与相邻处的棋子颜色相同,则记录该处的棋局,并继续循环记录
code += chess[k][h];
}
else {
//如果机器所下的棋子的颜色与相邻处的棋子颜色不同,则记录该处的棋局,并跳出循环停止记录
code += chess[k][h];
break;
}
}
}
//取出权值,累加
Integer value5 = hm.get(code);
if(value5 != null) {
chessValue[i][j] += value5;
}
code = "";
color = 0;
//左下
for(int k = i - 1, h = j + 1; k >= 0 && h <= chess[i].length - 1; k--,h++) {
if(chess[k][h] == 0) {
break;//如果相邻出没下棋,则此空位不下棋
}
else {
if(color == 0) {
color = chess[k][h];//保存第一颗棋子的颜色
code = chess[k][h] + "";
}
else if(color == chess[k][h]) {
//如果机器所下的棋子的颜色与相邻处的棋子颜色相同,则记录该处的棋局,并继续循环记录
code += chess[k][h];
}
else {
//如果机器所下的棋子的颜色与相邻处的棋子颜色不同,则记录该处的棋局,并跳出循环停止记录
code += chess[k][h];
break;
}
}
}
//取出权值,累加
Integer value6 = hm.get(code);
if(value6 != null) {
chessValue[i][j] += value6;
}
code = "";
color = 0;
//右上
for(int k = i + 1, h = j - 1; k <= chess[i].length - 1 && h >= 0; k++,h--) {
if(chess[k][h] == 0) {
break;//如果相邻出没下棋,则此空位不下棋
}
else {
if(color == 0) {
color = chess[k][h];//保存第一颗棋子的颜色
code = chess[k][h] + "";
}
else if(color == chess[k][h]) {
//如果机器所下的棋子的颜色与相邻处的棋子颜色相同,则记录该处的棋局,并继续循环记录
code += chess[k][h];
}
else {
//如果机器所下的棋子的颜色与相邻处的棋子颜色不同,则记录该处的棋局,并跳出循环停止记录
code += chess[k][h];
break;
}
}
}
//取出权值,累加
Integer value7 = hm.get(code);
if(value7 != null) {
chessValue[i][j] += value7;
}
code = "";
color = 0;
//右下
for(int k = i + 1, h = j + 1; k <= chess[i].length - 1 && h <= chess[i].length - 1; k++,h++) {
if(chess[k][h] == 0) {
break;//如果相邻出没下棋,则此空位不下棋
}
else {
if(color == 0) {
color = chess[k][h];//保存第一颗棋子的颜色
code = chess[k][h] + "";
}
else if(color == chess[k][h]) {
//如果机器所下的棋子的颜色与相邻处的棋子颜色相同,则记录该处的棋局,并继续循环记录
code += chess[k][h];
}
else {
//如果机器所下的棋子的颜色与相邻处的棋子颜色不同,则记录该处的棋局,并跳出循环停止记录
code += chess[k][h];
break;
}
}
}
//取出权值,累加
Integer value = hm.get(code);
if(value != null) {
chessValue[i][j] += value;
}
code = "";
color = 0;
}
}
}
//遍历整个棋局权值数组,寻找当前棋盘权值最大的位置来让机器下棋
int max = chessValue[0][0];
int a = 0,b = 0;
for(int i = 0; i < chessValue.length; i++) {
for(int j = 0; j < chessValue[i].length; j++) {
if(max < chessValue[i][j] && chess[i][j] == 0) {
max = chessValue[i][j];
a = i;
b = j;
}
}
}
System.out.println("a = " + a + " b = " + b + " max = " + max);
if(turn == 1) {
gr.setColor(Color.white);
gr.fillOval(X0 + a * SIZE - 15, Y0 + b * SIZE - 15, 30, 30);
chess[a][b] = 1;
}
else{
gr.setColor(Color.black);
gr.fillOval(X0 + a * SIZE - 15, Y0 + b * SIZE - 15, 30, 30);
chess[a][b] = -1;
}
checkSpWin(a, b);
checkVWin(a, b);
checkWin1(a,b);
checkWin2(a, b);
}
至此,本项目就实现完成了。
备注:这是我第一次写博客,若有不足之处欢迎大家批评指正,希望可以和大家一起学习,一起进步!