从头开始编写一个五子棋的博弈游戏(Java)

从头开始编写一个五子棋的博弈游戏(Java)

写在前面

这几天在上人工智能,老师让我们在实验环节做一个博弈类型的游戏,这里老师提示我们可以做一个五子棋的软件,于是我尝试开始自己编写一个五子棋的Java小游戏。

设计棋盘

首先我们先绘制一个面板,我希望上面的功能有:开始游戏、悔棋、模式选择、认输的功能。

利用Swing设计面板代码如下:

public void Init(){

        JFrame jf=new JFrame();
        jf.setTitle("五子棋");
        jf.setSize(650, 580);        //先设大小,再设居中;
        jf.setLocationRelativeTo(null);
        jf.setResizable(false);
        jf.setDefaultCloseOperation(3);
        jf.setLayout(new BorderLayout());
        jf.add(this);

        JPanel eastp=new JPanel();
        eastp.setPreferredSize(new Dimension(100,0));
        JButton buttonStart=new JButton("开始游戏");
        JButton buttonregret=new JButton("悔棋");
        JButton buttonlose=new JButton("认输");
        String[] itemArray = { "人人对战", "人机对战" };
        JComboBox<String> cbItem = new JComboBox<String>(itemArray);
        buttonStart.setPreferredSize(new Dimension(90,40));
        buttonregret.setPreferredSize(new Dimension(90,40));
        buttonlose.setPreferredSize(new Dimension(90,40));
        cbItem.setPreferredSize(new Dimension(90,40));
        eastp.add(buttonStart);
        eastp.add(buttonregret);
        eastp.add(buttonlose);
        eastp.add(cbItem);
        jf.add(eastp,BorderLayout.EAST);

        jf.setVisible(true);

    }

有了面板还不够 这里我们还需要自己绘制棋盘

这里我们采用的方法是重写Swing的paint方法这样每次程序运行是都会执行paint方法

代码如下:

        // 绘制棋盘
    // 重写JPanel的paint方法
    @Override
    public void paint(Graphics g) {
        // 这里由于每次新建JPanel的时候都会调用paint方法我们这里自己重写paint方法
        super.paint(g);
        for(int i =0;i<15;i++){
            g.drawLine(30, 30 + i * 35, 30 + 35 * 14, 30 + i * 35);// 横线
            g.drawLine(30 + i * 35, 30, 30 + i * 35, 30 + 35 * 14);// 竖线
        }

    }

我们运行一个程序试试结果:

如图所示已经成功完成了面板和按钮的绘制

画出棋子

上一步我们已经可以画出棋盘,这里我们对paint方法扩充一下,可以这样来绘制棋子

//重写重绘方法,这里重写的是第一个大的JPanel的方法
    public void paint(Graphics g) {
        super.paint(g);//画出白框

        //重绘出棋盘
        g.setColor(Color.black);
        for(int i=0;i<row;i++) {
            g.drawLine(x, y+size*i, x+size*(column-1), y+size*i);
        }
        for(int j=0;j<column;j++) {
            g.drawLine(x+size*j, y, x+size*j, y+size*(row-1));
        }

        //重绘出棋子
        for(int i=0;i<row;i++) {
            for(int j=0;j<column;j++) {
                if(isAvail[i][j]==1) {
                    int countx=size*j+20;
                    int county=size*i+20;
                    g.setColor(Color.black);
                    g.fillOval(countx-size/2, county-size/2, size, size);
                }
                else if(isAvail[i][j]==2) {
                    int countx=size*j+20;
                    int county=size*i+20;
                    g.setColor(Color.white);
                    g.fillOval(countx-size/2, county-size/2, size, size);
                }
            }
        }
    }

按钮监听

已经可以成功实现一个棋盘了 我们接下来主要来编写键盘的监听方法和其他工具类
如上面所示我们在我们键盘的右边新增了几个按钮 接下来我自己又对按钮进行了一些更改如下所示:

在上面的基础上我自己重新 更改了一些按钮 添加了作者信息显示 游戏说明的按钮

实现方式

键盘的监听实现起来很简单,方法如下:

  • 实例化一个ActionEvent 对象来管理按键
  • 通过e.getActionCommand()来判断按下了哪个按钮
  • 分别实现新游戏、放弃、说明等功能

部分代码如下:


public void actionPerformed(ActionEvent e) {

        //必须得用else if,因为如果没有else if你每次在右边的界面点击时它都会获取人人对战或者人机对战的                    信息,每次都会重置棋盘数组
        //获取当前被点击按钮的内容,判断是不是"开始新游戏"这个按钮
        if(e.getActionCommand().equals("新游戏")) {
            //重绘棋盘
            for(int i=0;i<gf.isAvail.length;i++)
                for(int j=0;j<gf.isAvail[i].length;j++)
                    gf.isAvail[i][j]=0;
            gf.repaint();
            //如果是开始新游戏的按钮,再为左半部分设置监听方法
            gf.turn=1;
        }
               // forkme github关注
        else if(e.getActionCommand().equals("我的github")){
            if(java.awt.Desktop.isDesktopSupported()){
                try {
                    //创建一个URI实例
                    java.net.URI uri = java.net.URI.create("https://github.com/RoWe98");
                    //获取当前系统桌面扩展
                    java.awt.Desktop dp = java.awt.Desktop.getDesktop();
                    //判断系统桌面是否支持要执行的功能
                    if(dp.isSupported(java.awt.Desktop.Action.BROWSE)){
                    //获取系统默认浏览器打开链接
                        dp.browse(uri);
                    }
                } catch (java.io.IOException error) {
                //此为无法获取系统默认浏览器
                    error.printStackTrace();
                }
            }
        }

        // 按下readme 游戏说明
        else if(e.getActionCommand().equals("说明")){
            String readme = "1.选择一个游戏模式:人人或人机"+"\n" +
                "2.开始新游戏"+"\n"+"3.Enjoy!";
            JOptionPane.showMessageDialog(null,readme);
        }

        else if(e.getActionCommand().equals("放弃")) {
            if(gf.turn==1) {
                JOptionPane.showMessageDialog(null, "白方胜");
                System.out.println("白方胜!");
            }else JOptionPane.showMessageDialog(null, "黑方胜");
            //重新把棋盘设置为不可操作
            gf.turn=0;
        }
        else if(box.getSelectedItem().equals("人机")) {
            gf.ChooseType=1;
            gf.turn=0;
        }
        else if(box.getSelectedItem().equals("人人")){
            gf.ChooseType=0;
            gf.turn=0;
        }
    }

棋盘信息以及棋子信息存储以及设定

棋子坐标信息

首先我们来思考一个问题:如何存储当前棋子在棋盘上的坐标?

答:建立一个Bean来存储当前棋子的坐标信息

我相信大部分人都会这么想,当然我们这里也是可以这么实现这个功能的

如下所示,我们建立一个类来存放我们棋子的坐标

//新建一个棋子类ChessPosition保存每一步棋子所在的位置
public class ChessPosition {
    public int Listi,Listj;

    public ChessPosition() {

    }
    public ChessPosition(int Listi,int Listj) {
        this.Listi=Listi;
        this.Listj=Listj;
    }
}

通过这个类 就可以让我们来保存每一步棋子的位置 信息

棋盘信息设定

同样的问题,我们如何设定棋盘的信息 比如棋盘大小为15*15 ,格子大小,棋盘的起点坐标

这里我们可以使用Java中一个特别好用的东西,那就是接口,我们完全可以定义一个接口保存我们定义的信息,在之后的类中调用我们棋盘信息的时候只需要implement接口即可

接口定义如下所示:

//定义与棋盘数据相关的接口,保存棋盘的起点,格子大小,行数列数等信息
public interface GoBangconfig {
    int x=20,y=20,size=40,row=15,column=15;
}

如图我们已经设置了按键监听所以我们在主方法中为按钮添加监听

//按钮监控类
ButtonListener butListen=new ButtonListener(this,box);
//对每一个按钮都添加状态事件的监听处理机制
for(int i=0;i<butname.length;i++) {
    button[i].addActionListener(butListen);//添加发生操作的监听方法
    }

    //对可选框添加事件监听机制
    box.addActionListener(butListen);

    FrameListener fl=new FrameListener();
    fl.setGraphics(this);//获取画笔对象
    this.addMouseListener(fl);

承上启下

这一步目前是这么想的,我们准备编写具体的方法来判断棋子落子的情况

人机博弈算法来编写五子棋目前市面上主流的算法有

  • 权值法
  • α-β剪枝法
  • 博弈树法

这里我选用了权值法

权值法

权值法就是检测棋盘八个方向

  • 上、下、左、右、左上、右上、左下、右下

权值法设置了一系列权值 就像这样

情况 权值 说明
01 17 眠1连
02 12 眠1连
001 17 眠1连
002 12 眠1连
0001 17 眠1连
0002 12 眠1连
0102 17 眠1连
0201 12 眠1连
0012 15 眠1连
0021 10 眠1连
01002 19 眠1连
02001 14 眠1连
00102 17 眠1连
00201 12 眠1连
00012 15 眠1连
00021 10 眠1连
01000 21 活1连
02000 16 活1连
00100 19 活1连
00200 14 活1连
00010 17 活1连
00020 12 活1连
00001 15 活1连
00002 10 活1连
0101 65 眠2连
0202 60 眠2连
0110 65 眠2连
0220 60 眠2连
011 65 眠2连
022 60 眠2连
0011 65 眠2连
0022 60 眠2连
01012 65 眠2连
02021 60 眠2连
01102 65 眠2连
02201 60 眠2连
00112 65 眠2连
00221 60 眠2连
01010 75 活2连
02020 70 活2连
01100 75 活2连
02200 70 活2连
00110 75 活2连
00220 70 活2连
00011 75 活2连
00022 70 活2连
0111 150 眠3连
0222 140 眠3连
01112 150 眠3连
02221 140 眠3连
01101 1000 活3连
02202 800 活3连
01011 1000 活3连
02022 800 活3连
01110 1000 活3连
02220 800 活3连
01111 3000 4连
02222 3500 4连

说明

  • 0为空位
  • 1为黑棋
  • 2为白棋
  • 类似01022这种什么意思?

如图所示

  • 从左到右分别为白-黑-白
  • 且左右两边都为空
  • 所以用012表示为02120即空-白-黑-白-空

实现权值法

所以为了表示这些情况我们使用HashMap在存储对应的情况和权值

代码如下所示

public static HashMap<String,Integer> map = new HashMap<String,Integer>();//设置不同落子情况和相应权值的数组
    static {
        //被堵住
        map.put("01", 17);//眠1连
        map.put("02", 12);//眠1连
        map.put("001", 17);//眠1连
        map.put("002", 12);//眠1连
        map.put("0001", 17);//眠1连
        map.put("0002", 12);//眠1连

        map.put("0102",17);//眠1连,15
        map.put("0201",12);//眠1连,10
        map.put("0012",15);//眠1连,15
        map.put("0021",10);//眠1连,10
        map.put("01002",19);//眠1连,15
        map.put("02001",14);//眠1连,10
        map.put("00102",17);//眠1连,15
        map.put("00201",12);//眠1连,10
        map.put("00012",15);//眠1连,15
        map.put("00021",10);//眠1连,10

        map.put("01000",21);//活1连,15
        map.put("02000",16);//活1连,10
        map.put("00100",19);//活1连,15
        map.put("00200",14);//活1连,10
        map.put("00010",17);//活1连,15
        map.put("00020",12);//活1连,10
        map.put("00001",15);//活1连,15
        map.put("00002",10);//活1连,10

        //被堵住
        map.put("0101",65);//眠2连,40
        map.put("0202",60);//眠2连,30
        map.put("0110",65);//眠2连,40
        map.put("0220",60);//眠2连,30
        map.put("011",65);//眠2连,40
        map.put("022",60);//眠2连,30
        map.put("0011",65);//眠2连,40
        map.put("0022",60);//眠2连,30

        map.put("01012",65);//眠2连,40
        map.put("02021",60);//眠2连,30
        map.put("01102",65);//眠2连,40
        map.put("02201",60);//眠2连,30
        map.put("00112",65);//眠2连,40
        map.put("00221",60);//眠2连,30

        map.put("01010",75);//活2连,40
        map.put("02020",70);//活2连,30
        map.put("01100",75);//活2连,40
        map.put("02200",70);//活2连,30
        map.put("00110",75);//活2连,40
        map.put("00220",70);//活2连,30
        map.put("00011",75);//活2连,40
        map.put("00022",70);//活2连,30

        //被堵住
        map.put("0111",150);//眠3连,100
        map.put("0222",140);//眠3连,80

        map.put("01112",150);//眠3连,100
        map.put("02221",140);//眠3连,80

        map.put("01101",1000);//活3连,130
        map.put("02202",800);//活3连,110
        map.put("01011",1000);//活3连,130
        map.put("02022",800);//活3连,110
        map.put("01110", 1000);//活3连
        map.put("02220", 800);//活3连

        map.put("01111",3000);//4连,300
        map.put("02222",3500);//4连,280
    }
    public int[][] weightArray=new int[column][row];//定义一个二维数组,保存各个点的权值

如上所示我们设置不同落子情况和相应权值保存到HashMap中,并且定义一个二维数组,保存各个点的权值

其中0表示空位,1表示黑棋子,2表示白棋子。当然上面只是一个示例,实际情况比这个多得多。

权值如何给定?

  • A.随着相连的棋子数增加,它的权值要相应地增加;
  • B.相同的相连棋子数,活连的权值要比眠连要大;
  • C.人执黑,AI 执白。如果相同的相连情况,黑子的权值大于白子,那么AI就偏防守;如果黑子的权值小于白子,那么AI偏进攻。由于黑子先手,一般可以使用黑子的权值大于白子,让AI进行后手防守。(我这里用的、AI用的就是偏防守)。

细节:

  • A.比如当出现某个空位出现了4连,那么这个时候不管其他位置情况如何,我们都必须先下这个位置,因此4连的权值要比3连大得多,保证它一定能够最先被选择。
  • B.如果出现了权值相同的位置怎么办?我们这里默认选择第一个位置。

权值判断

这里我们需要编写一个方法来判断没有棋子的地方的权值,好让棋子可以根据权值来找到合适的位置来落子

当然我们需要分两个情况:

  • 人人
  • 人机
    在人人的情况下我们就不需要判断权值,人机的情况下我们把权值判断交给电脑来判断权值,从而落子

具体算法设计

  • 人下棋后先判断输赢,如果赢了则游戏结束,否则就进入AI算法

  • AI算法要做的事情就是遍历棋盘的每一个空位置,根据当前棋盘的棋子数组,来确定与该空位相关的棋子相连情况。然后和在Haspmap中进行匹配搜索,找到相应的权值,把这个权值加到当前位置。

  • 遍历权值数组,选择最大的权值,找到相应位置落子

  • 判断输赢,如果赢了则游戏结束,否则回到人下棋。

代码实现

public void mouseClicked(java.awt.event.MouseEvent e) {
        int x=e.getX();
        int y=e.getY();
        //计算棋子要落在棋盘的哪个交叉点上
        int countx=(x/40)*40+20;
        int county=(y/40)*40+20;
        Graphics g=gf.getGraphics();
        //计算棋盘上棋子在数组中相应的位置
        int Arrayj=(countx-20)/40;
        int Arrayi=(county-20)/40;

        if(gf.turn!=0)//判断是否可以进行游戏
            if(gf.isAvail[Arrayi][Arrayj]!=0) {
                System.out.println("此处已经有棋子了,请下在其它地方");
            }
            else {
                //选择人人对战
                if(gf.ChooseType==0) {
                    if(gf.turn==1) {
                        //先获取要落的地方
                        g.setColor(Color.black);
                        //落子
                        g.fillOval(countx-size/2, county-size/2, size, size);
                        //设置当前位置已经有棋子了,棋子为黑子
                        gf.isAvail[Arrayi][Arrayj]=1;
                        //把当前所下的棋子位置保存在动态数组中
                        gf.ChessPositonList.add(new ChessPosition(Arrayi,Arrayj));
                        gf.turn++;

                        //判断是否已经出现五科棋子了
                        //列判断
                        //首先界定数组范围,防止越界
                        int imin=Arrayi-4,imax=Arrayi+4;
                        if(imin<0) imin=0;
                        if(imax>14) imax=14;
                        int count1=0;//判断相连的棋子数
                        for(int i=imin;i<=imax;i++) {
                            if(gf.isAvail[i][Arrayj]==1) count1++;
                                //如果出现了其他棋子,或者是没有棋子时,就重新开始计数
                            else count1=0;
                            if(count1==5) {
                                System.out.println("黑方赢");
                                gf.PopUp("黑方赢");
                                gf.turn=0;
                                return;
                            }
                        }
                        //行判断
                        //首先界定数组范围,防止越界
                        int jmin=Arrayj-4,jmax=Arrayj+4;
                        if(jmin<0) jmin=0;
                        if(jmax>14) jmax=14;
                        int count2=0;//判断相连的棋子数
                        for(int j=jmin;j<=jmax;j++) {
                            if(gf.isAvail[Arrayi][j]==1) count2++;
                            else count2=0;
                            if(count2==5) {
                                System.out.println("黑方赢");
                                gf.PopUp("黑方赢");
                                gf.turn=0;
                                return;
                            }
                            //如果出现了其他棋子,或者是没有棋子时,就重新开始计数

                        }
                        //135度判断
                        //首先界定数组范围,防止越界
                        int count3=0;//判断相连的棋子数
                        for(int i=-4;i<=4;i++) {
                            if((Arrayi+i>=0)&&(Arrayj+i>=0)&&(Arrayi+i<=14)&&(Arrayj+i<=14)) {
                                if(gf.isAvail[Arrayi+i][Arrayj+i]==1) count3++;
                                    //如果出现了其他棋子,或者是没有棋子时,就重新开始计数
                                else count3=0;
                                if(count3==5) {
                                    System.out.println("黑方赢");
                                    gf.PopUp("黑方赢");
                                    gf.turn=0;
                                    return;
                                }
                            }
                        }
                        int count4=0;//判断相连的棋子数
                        for(int i=-4;i<=4;i++) {
                            if((Arrayi+i>=0)&&(Arrayj-i>=0)&&(Arrayi+i<=14)&&(Arrayj-i<=14)) {
                                //System.out.print("count4:"+count4);
                                if(gf.isAvail[Arrayi+i][Arrayj-i]==1) count4++;
                                    //如果出现了其他棋子,或者是没有棋子时,就重新开始计数
                                else count4=0;
                                if(count4==5) {
                                    System.out.println("黑方赢");
                                    gf.PopUp("黑方赢");
                                    gf.turn=0;
                                    return;
                                }
                            }
                        }
                    }
                    else if(gf.turn==2){
                        g.setColor(Color.white);
                        g.fillOval(countx-size/2, county-size/2, size, size);
                        //设置当前位置已经有棋子了,棋子为白子
                        gf.ChessPositonList.add(new ChessPosition(Arrayi,Arrayj));
                        gf.isAvail[Arrayi][Arrayj]=2;
                        gf.turn--;

                        //列判断
                        //首先界定数组范围,防止越界
                        int imin=Arrayi-4,imax=Arrayi+4;
                        if(imin<0) imin=0;
                        if(imax>14) imax=14;
                        int count1=0;//判断相连的棋子数
                        for(int i=imin;i<=imax;i++) {
                            if(gf.isAvail[i][Arrayj]==2) count1++;

                                //如果出现了其他棋子,或者是没有棋子时,就重新开始计数
                            else count1=0;
                            if(count1==5) {
                                System.out.println("白方赢");
                                gf.PopUp("白方赢");
                                gf.turn=0;
                                return;
                            }
                        }
                        //行判断
                        //首先界定数组范围,防止越界
                        int jmin=Arrayj-4,jmax=Arrayj+4;
                        if(jmin<0) jmin=0;
                        if(jmax>14) jmax=14;
                        int count2=0;//判断相连的棋子数
                        for(int j=jmin;j<=jmax;j++) {
                            if(gf.isAvail[Arrayi][j]==2) count2++;
                                //如果出现了其他棋子,或者是没有棋子时,就重新开始计数
                            else count2=0;
                            if(count2==5) {
                                System.out.println("白方赢");
                                gf.PopUp("白方赢");
                                gf.turn=0;
                                return;
                            }

                        }
                        //135度判断
                        //首先界定数组范围,防止越界
                        int count3=0;//判断相连的棋子数
                        for(int i=-4;i<=4;i++) {
                            if((Arrayi+i>=0)&&(Arrayj+i>=0)&&(Arrayi+i<=14)&&(Arrayj+i<=14)) {
                                if(gf.isAvail[Arrayi+i][Arrayj+i]==2) count3++;
                                    //如果出现了其他棋子,或者是没有棋子时,就重新开始计数
                                else count3=0;
                                if(count3==5) {
                                    System.out.println("白方赢");
                                    gf.PopUp("白方赢");
                                    gf.turn=0;
                                    return;
                                }
                            }
                        }
                        int count4=0;//判断相连的棋子数
                        for(int i=-4;i<=4;i++) {
                            if((Arrayi+i>=0)&&(Arrayj-i>=0)&&(Arrayi+i<=14)&&(Arrayj-i<=14)) {
                                if(gf.isAvail[Arrayi+i][Arrayj-i]==2) count4++;
                                    //如果出现了其他棋子,或者是没有棋子时,就重新开始计数
                                else count4=0;
                                if(count4==5) {
                                    System.out.println("白方赢");
                                    gf.PopUp("白方赢");
                                    gf.turn=0;
                                    return;
                                }
                            }
                        }
                    }
                }
                //如果选择的是人机对战
                else {
                    if(gf.turn==1) {

                        //人先落子
                        //先获取要落的地方
                        g.setColor(Color.black);
                        //落子
                        g.fillOval(countx-size/2, county-size/2, size, size);
                        //设置当前位置已经有棋子了,棋子为黑子
                        gf.isAvail[Arrayi][Arrayj]=1;
                        //把当前所下的棋子位置保存在动态数组中
                        gf.ChessPositonList.add(new ChessPosition(Arrayi,Arrayj));
                        gf.turn++;

                        //判断是否已经出现五科棋子了
                        //列判断
                        //首先界定数组范围,防止越界
                        int Blackimin=Arrayi-4,Blackimax=Arrayi+4;
                        if(Blackimin<0) Blackimin=0;
                        if(Blackimax>14) Blackimax=14;
                        int count1=0;//判断相连的棋子数
                        for(int i=Blackimin;i<=Blackimax;i++) {
                            if(gf.isAvail[i][Arrayj]==1) count1++;
                                //如果出现了其他棋子,或者是没有棋子时,就重新开始计数
                            else count1=0;
                            if(count1==5) {
                                System.out.println("黑方赢");
                                gf.PopUp("黑方赢");
                                return;
                            }
                        }
                        //行判断
                        //首先界定数组范围,防止越界
                        int Blackjmin=Arrayj-4,Blackjmax=Arrayj+4;
                        if(Blackjmin<0) Blackjmin=0;
                        if(Blackjmax>14) Blackjmax=14;
                        int count2=0;//判断相连的棋子数
                        for(int j=Blackjmin;j<=Blackjmax;j++) {
                            if(gf.isAvail[Arrayi][j]==1) count2++;
                            else count2=0;
                            if(count2==5) {
                                System.out.println("黑方赢");
                                gf.PopUp("黑方赢");
                                return;
                            }
                            //如果出现了其他棋子,或者是没有棋子时,就重新开始计数

                        }
                        //135度判断
                        //首先界定数组范围,防止越界
                        int count3=0;//判断相连的棋子数
                        for(int i=-4;i<=4;i++) {
                            if((Arrayi+i>=0)&&(Arrayj+i>=0)&&(Arrayi+i<=14)&&(Arrayj+i<=14)) {
                                if(gf.isAvail[Arrayi+i][Arrayj+i]==1) count3++;
                                    //如果出现了其他棋子,或者是没有棋子时,就重新开始计数
                                else count3=0;
                                if(count3==5) {
                                    System.out.println("黑方赢");
                                    gf.PopUp("黑方赢");
                                    return;
                                }
                            }
                        }
                        int count4=0;//判断相连的棋子数
                        for(int i=-4;i<=4;i++) {
                            if((Arrayi+i>=0)&&(Arrayj-i>=0)&&(Arrayi+i<=14)&&(Arrayj-i<=14)) {
                                //System.out.print("count4:"+count4);
                                if(gf.isAvail[Arrayi+i][Arrayj-i]==1) count4++;
                                    //如果出现了其他棋子,或者是没有棋子时,就重新开始计数
                                else count4=0;
                                if(count4==5) {
                                    System.out.println("黑方赢");
                                    gf.PopUp("黑方赢");
                                    return;
                                }
                            }
                        }

                        //机器落子
                        //先计算出各个位置的权值
                        for(int i=0;i<gf.isAvail.length;i++) {
                            for(int j=0;j<gf.isAvail[i].length;j++) {
                                //首先判断当前位置是否为空
                                if(gf.isAvail[i][j]==0) {
                                    //往左延伸
                                    String ConnectType="0";
                                    int jmin=Math.max(0, j-4);
                                    for(int positionj=j-1;positionj>=jmin;positionj--) {
                                        //依次加上前面的棋子
                                        ConnectType=ConnectType+gf.isAvail[i][positionj];
                                    }
                                    //从数组中取出相应的权值,加到权值数组的当前位置中
                                    Integer valueleft=gf.map.get(ConnectType);
                                    if(valueleft!=null) gf.weightArray[i][j]+=valueleft;

                                    //往右延伸
                                    ConnectType="0";
                                    int jmax=Math.min(14, j+4);
                                    for(int positionj=j+1;positionj<=jmax;positionj++) {
                                        //依次加上前面的棋子
                                        ConnectType=ConnectType+gf.isAvail[i][positionj];
                                    }
                                    //从数组中取出相应的权值,加到权值数组的当前位置中
                                    Integer valueright=gf.map.get(ConnectType);
                                    if(valueright!=null) gf.weightArray[i][j]+=valueright;

                                    //联合判断,判断行
                                    gf.weightArray[i][j]+=unionWeight(valueleft,valueright);

                                    //往上延伸
                                    ConnectType="0";
                                    int imin=Math.max(0, i-4);
                                    for(int positioni=i-1;positioni>=imin;positioni--) {
                                        //依次加上前面的棋子
                                        ConnectType=ConnectType+gf.isAvail[positioni][j];
                                    }
                                    //从数组中取出相应的权值,加到权值数组的当前位置中
                                    Integer valueup=gf.map.get(ConnectType);
                                    if(valueup!=null) gf.weightArray[i][j]+=valueup;

                                    //往下延伸
                                    ConnectType="0";
                                    int imax=Math.min(14, i+4);
                                    for(int positioni=i+1;positioni<=imax;positioni++) {
                                        //依次加上前面的棋子
                                        ConnectType=ConnectType+gf.isAvail[positioni][j];
                                    }
                                    //从数组中取出相应的权值,加到权值数组的当前位置中
                                    Integer valuedown=gf.map.get(ConnectType);
                                    if(valuedown!=null) gf.weightArray[i][j]+=valuedown;

                                    //联合判断,判断列
                                    gf.weightArray[i][j]+=unionWeight(valueup,valuedown);

                                    //往左上方延伸,i,j,都减去相同的数
                                    ConnectType="0";
                                    for(int position=-1;position>=-4;position--) {
                                        if((i+position>=0)&&(i+position<=14)&&(j+position>=0)&&(j+position<=14))
                                            ConnectType=ConnectType+gf.isAvail[i+position][j+position];
                                    }
                                    //从数组中取出相应的权值,加到权值数组的当前位置
                                    Integer valueLeftUp=gf.map.get(ConnectType);
                                    if(valueLeftUp!=null) gf.weightArray[i][j]+=valueLeftUp;

                                    //往右下方延伸,i,j,都加上相同的数
                                    ConnectType="0";
                                    for(int position=1;position<=4;position++) {
                                        if((i+position>=0)&&(i+position<=14)&&(j+position>=0)&&(j+position<=14))
                                            ConnectType=ConnectType+gf.isAvail[i+position][j+position];
                                    }
                                    //从数组中取出相应的权值,加到权值数组的当前位置
                                    Integer valueRightDown=gf.map.get(ConnectType);
                                    if(valueRightDown!=null) gf.weightArray[i][j]+=valueRightDown;

                                    //联合判断,判断行
                                    gf.weightArray[i][j]+=unionWeight(valueLeftUp,valueRightDown);

                                    //往左下方延伸,i加,j减
                                    ConnectType="0";
                                    for(int position=1;position<=4;position++) {
                                        if((i+position>=0)&&(i+position<=14)&&(j-position>=0)&&(j-position<=14))
                                            ConnectType=ConnectType+gf.isAvail[i+position][j-position];
                                    }
                                    //从数组中取出相应的权值,加到权值数组的当前位置
                                    Integer valueLeftDown=gf.map.get(ConnectType);
                                    if(valueLeftDown!=null) gf.weightArray[i][j]+=valueLeftDown;

                                    //往右上方延伸,i减,j加
                                    ConnectType="0";
                                    for(int position=1;position<=4;position++) {
                                        if((i-position>=0)&&(i-position<=14)&&(j+position>=0)&&(j+position<=14))
                                            ConnectType=ConnectType+gf.isAvail[i-position][j+position];
                                    }
                                    //从数组中取出相应的权值,加到权值数组的当前位置
                                    Integer valueRightUp=gf.map.get(ConnectType);
                                    if(valueRightUp!=null) gf.weightArray[i][j]+=valueRightUp;

                                    //联合判断,判断行
                                    gf.weightArray[i][j]+=unionWeight(valueLeftDown,valueRightUp);
                                }
                            }
                        }

                        //打印出权值
                        for(int i=0;i<go.column;i++) {
                            for(int j=0;j<go.row;j++) {
                                System.out.print(gf.weightArray[i][j]+" ");
                            }
                            System.out.println();
                        }

                        //取出最大的权值
                        int AIi=0,AIj=0;
                        int weightmax=0;
                        for(int i=0;i<go.row;i++) {
                            for(int j=0;j<go.column;j++) {
                                if(weightmax<gf.weightArray[i][j]) {
                                    weightmax=gf.weightArray[i][j];
                                    AIi=i;
                                    AIj=j;
                                    System.out.println(AIi+" "+AIj);
                                }
                            }
                        }

                        //确定位置,落子
                        g.setColor(Color.white);
                        //i对应y,j对应x
                        countx=20+AIj*40;
                        county=20+AIi*40;
                        g.fillOval(countx-size/2, county-size/2, size, size);
                        //设置当前位置已经有棋子了,棋子为白子
                        gf.ChessPositonList.add(new ChessPosition(AIi,AIj));
                        gf.isAvail[AIi][AIj]=2;
                        gf.turn--;

                        //落子以后重置权值数组weightArray
                        for(int i=0;i<go.column;i++)
                            for(int j=0;j<go.row;j++)
                                gf.weightArray[i][j]=0;

                        //列判断
                        //首先界定数组范围,防止越界
                        int imin=AIi-4,imax=AIi+4;
                        if(imin<0) imin=0;
                        if(imax>14) imax=14;
                        count1=0;//判断相连的棋子数
                        for(int i=imin;i<=imax;i++) {
                            if(gf.isAvail[i][AIj]==2) count1++;

                                //如果出现了其他棋子,或者是没有棋子时,就重新开始计数
                            else count1=0;
                            if(count1==5) {
                                System.out.println("白方赢");
                                gf.PopUp("白方赢");
                                gf.turn=0;
                                return;
                            }
                        }
                        //行判断
                        //首先界定数组范围,防止越界
                        int jmin=AIj-4,jmax=AIj+4;
                        if(jmin<0) jmin=0;
                        if(jmax>14) jmax=14;
                        count2=0;//判断相连的棋子数
                        for(int j=jmin;j<=jmax;j++) {
                            if(gf.isAvail[AIi][j]==2) count2++;
                                //如果出现了其他棋子,或者是没有棋子时,就重新开始计数
                            else count2=0;
                            if(count2==5) {
                                System.out.println("白方赢");
                                gf.PopUp("白方赢");
                                gf.turn=0;
                                return;
                            }

                        }
                        //135度判断
                        //首先界定数组范围,防止越界
                        count3=0;//判断相连的棋子数
                        for(int i=-4;i<=4;i++) {
                            if((AIi+i>=0)&&(AIj+i>=0)&&(AIi+i<=14)&&(AIj+i<=14)) {
                                if(gf.isAvail[AIi+i][AIj+i]==2) count3++;
                                    //如果出现了其他棋子,或者是没有棋子时,就重新开始计数
                                else count3=0;
                                if(count3==5) {
                                    System.out.println("白方赢");
                                    gf.PopUp("白方赢");
                                    gf.turn=0;
                                    return;
                                }
                            }
                        }
                        count4=0;//判断相连的棋子数
                        for(int i=-4;i<=4;i++) {
                            if((AIi+i>=0)&&(AIj-i>=0)&&(AIi+i<=14)&&(AIj-i<=14)) {
                                if(gf.isAvail[AIi+i][AIj-i]==2) count4++;
                                    //如果出现了其他棋子,或者是没有棋子时,就重新开始计数
                                else count4=0;
                                if(count4==5) {
                                    System.out.println("白方赢");
                                    gf.PopUp("白方赢");
                                    gf.turn=0;
                                    return;
                                }
                            }
                        }
                    }
                }
            }
    }

这里是权值AI算法的判断代码

    //AI联合算法
    public Integer unionWeight(Integer a,Integer b ) {
        //必须要先判断a,b两个数值是不是null
        if((a==null)||(b==null)) return 0;
            //一一
        else if((a>=10)&&(a<=25)&&(b>=10)&&(b<=25)) return 60;
            //一二、二一
        else if(((a>=10)&&(a<=25)&&(b>=60)&&(b<=80))||((a>=60)&&(a<=80)&&(b>=10)&&(b<=25))) return 800;
            //一三、三一、二二
        else if(((a>=10)&&(a<=25)&&(b>=140)&&(b<=1000))||((a>=140)&&(a<=1000)&&(b>=10)&&(b<=25))||((a>=60)&&(a<=80)&&(b>=60)&&(b<=80)))
            return 3000;
            //二三、三二
        else if(((a>=60)&&(a<=80)&&(b>=140)&&(b<=1000))||((a>=140)&&(a<=1000)&&(b>=60)&&(b<=80))) return 3000;
        else return 0;
    }

演示

具体演示如图所示

下载

依赖环境

  • jdk1.8

运行环境

源码

GitHub连接

转载请注明出处和作者

End