【JAVA】实现一个五子棋游戏——悔棋、复盘、双人对战、人机对战


前言

这是一篇使用JAVA实现制作一个简易五子棋的教程。我会尽力写的详细、清晰,帮助大家理解整个制作过程。

这个五子棋能实现的基本功能有:人机对战,双人对战,复盘,悔棋。
(不过我没有添加选择先后手的功能,人机对战部分默认人先手执黑子,AI执白子,这个功能大家了解后可以自己去尝试实现)

其中,人机对战部分我借鉴了其他博主使用的五元组算法,下面使用的这个五元组算法应该是比较简易的一个五元组实现方式了,当然也还有很多其他的实现方式,大家可以自行去学习了解。


一、游戏面板的制作

我们要实现的第一个任务就是:建立一个游戏面板。
大家可以思考一下,面板上我们都需要放些什么呢?棋盘区域、按钮功能区
在我们的游戏面板上,我们最先需要实现的就是建立两个区块,分别用于下棋、功能选择。
那么我们应该使用什么来划分区域?答案就是JPanel

JPanel是Java Swing中的一个类,它表示一个可以容纳其他Swing组件的容器。它类似于窗口或框架,但通常用作较大GUI中的子组件。使用JPanel,您可以将相关组件分组在一起,并将它们排列在特定的布局中,例如网格或流布局。JPanel还可以自定义颜色、边框和其他视觉属性,以匹配应用程序的整体外观。

以下是区域建立的实现代码:
这里我们使用JPanel 划分区域,然后使用JButton 建立按钮
详细过程大家可以直接看代码,我注释写的比较详细

 public  void initUI(){
        //当然,在划分区域前要先建立一个Frame哈
        JFrame jf = new JFrame();
        jf.setSize(1100,900);//设置大小
        jf.setLocationRelativeTo(null);//位置显示居中处理
        jf.setTitle("五子棋游戏");//设置TITLE
        jf.setDefaultCloseOperation(3);//停止运行

        //创建一个侧边栏
        //侧边栏用于放置按钮
        JPanel cebian_panel = new JPanel();
    
        //设置尺寸
        cebian_panel.setPreferredSize(new Dimension(200,0));
        //利用BorderLayout来设置在框体中的对应方位,并将其加入框架中
        jf.add(cebian_panel,BorderLayout.EAST);
        cebian_panel.setBackground(Color.yellow);

        //添加功能按钮
        //使用setfont设置字体
        JButton start = new JButton("开始");
        start.setFont(new Font("宋体",Font.BOLD,20));

        JButton huiqi = new JButton("悔棋");
        //英语不好,这个命名比较随意了,见谅见谅
        huiqi.setFont(new Font("宋体",Font.BOLD,20));

        JButton fupan = new JButton("复盘");
        fupan.setFont(new Font("宋体",Font.BOLD,20));

        JButton manmachine = new JButton("人机对战");
        manmachine.setFont(new Font("黑体",Font.BOLD,20));

        JButton manman = new JButton("双人对战");
        manman.setFont(new Font("黑体",Font.BOLD,20));

    
        cebian_panel.add(start);
        cebian_panel.add(huiqi);
        cebian_panel.add(fupan);
        cebian_panel.add(manmachine);
        cebian_panel.add(manman);
        cebian_panel.setLayout(null);
        start.setBounds(50,200,90,50);//设置在侧边栏里的位置,这里是手动设置的,比较麻烦,大家可以再优化优化
        huiqi.setBounds(50,300,90,50);
        fupan.setBounds(50,400,90,50);
        manmachine.setBounds(40,600,120,40);
        manman.setBounds(40,700,120,40);

        //设置棋盘面板
        MPanel mpanel = new MPanel();
        jf.add(mpanel,BorderLayout.CENTER);//放在中间
        mpanel.setBackground(Color.gray);

        jf.setVisible(true);
    }

这是一张图片儿

二、绘制棋盘,棋子以及实现重绘功能

面板有了,按钮加了,那么下一步就是绘制棋盘和棋子了!
这里我们使用画笔工具来绘画。

1.绘制棋盘

在绘制棋盘的时候,我们使用的是画线工具,利用循环将将间隔均匀的棋盘线绘制出来

代码如下(示例):
首先是paint方法中的绘制部分代码


public int x0=50,y0=50,size=50,line=16,chesssize=50;
    //这里给出的只是部分代码,不完全
    //可以看出来,我们绘制的是16x16的棋盘,选定的棋子大小是直径50
    //x0,y0的设置是为了留出棋盘周围的一圈位置,更美观一点
    public void paint(Graphics g)
    {
        //绘制棋盘
        for(int i=0;i<line;i++)
        {
            g.setColor(Color.black);
            g.drawLine(x0,size*i+y0,(line-1)*size+x0,i*size+y0);
            g.drawLine(size*i+x0,y0,size*i+x0,(line-1)*size+y0);
        }
    }

记得要在UI类中添加画笔工具

        //画笔绘画
        //绘画画笔需要从应用的组件中获取
        Graphics g = mpanel.getGraphics();
        //我们要在棋盘区域绘制,将画笔直接添加到mpanel

2.棋子的绘制

绘制棋子前,我们要思考,整个五子棋游戏实现的过程中,我们需要棋子做些什么?需要获取到哪些棋子相关的数据?棋子位置、棋子的颜色
这两个是最重要的!
其次,看到棋盘后,我们应该很容易想到,对于下棋的位置,我们可以使用一个二维数组来存储每一个棋盘格子上对应的棋子状态,例如:
0 代表为空,无棋子;
1 代表有黑子
2 代表有白子
以下是棋子类的代码示例:
(不明白 this 的使用的可以参见我前面发的文章)

public class chess {
    public int x,y,flag;
    public chess(int x,int y,int flag)
    {
        this.x=x;//位置
        this.y=y;
        this.flag=flag;//颜色标记
    }
}

还有就是,在绘制过程中,我们使用画笔的画圆功能来绘制棋子

想明白上面这些后,还有一个很重要的点我们需要考虑:怎么将棋子下载我们鼠标点击的位置上呢?以及怎么才能将棋子落下的位置自动校正至棋盘格子交点?
1)使用鼠标监听器来下棋
使用鼠标监听器我们需要在UI类中添加监听器,创建gamemouse类并将画笔传入类中
以下是UI类中添加鼠标监听器的代码示例:

//第二步:添加鼠标监听器
gamemouse gm = new gamemouse(g,mpanel);
//添加按钮监听器
mpanel.addMouseListener(gm);

2)矫正落棋位置、交替落棋功能

代码如下(示例):
以下是gamemouse 类,绘制棋子需要将画笔 g 也传递到gamemouse 类中
注意:因为这个代码我反复修改了很多次,中间用过很多种方法,并且也还没有优化过,其中一些变量的定义不规范,重在理解思路,大家可以自行修正改进,还有就是在讲述实现方法的过程中给出的代码也并不是全部的,我在复制过来的时候可能会有遗漏,最好不要直接从这里复制过去使用,完整的代码我会放在后面

//使用inplements继承接口
//继承接口后需要将接口中所有方法复制粘贴过来
public class gamemouse implements MouseListener {
        public int x0=50,y0=50,size=50,line=16,chesssize=50;
        public int count=0;
        //存储棋子数据
        public int[][] Q = new int[line][line];
        public int JX=0,JY=0;
        public int flag=0,num=0,AI_flag=0;
        //定义一个二维数组存储棋盘与下棋数据
        //这里与上面重复了,因为我一开始没打算单独创建棋子类Chess的
        //这个与Q记录的东西差不多,只是使用两种不同类型数组来存储
        //大家在后面就会发现,Q1数组用于实现悔棋和重绘功能会比较方便
        //而Q数组用于实现绘制棋子比较方便
        public chess[] Q1= new chess[line*line];
        private MPanel mp;
        //引用传递画笔
        private Graphics g;
        public int max=0,max_x=0,max_y=0;
        //构造方法初始化私有修饰符修饰的画笔方法
        public gamemouse(Graphics g, MPanel mp)
        {
            this.g=g;
            this.mp=mp;
        }
        public void mouseClicked(MouseEvent e) {
            //鼠标点击后由鼠标监听器获取坐标
            int x = e.getX();
            int y = e.getY();

            //实现落在交点
            //依据鼠标监听器,对获取的坐标位置进行判断,并矫正位置
            //x0是设计棋盘是留下的用于矫正相对位置的
            //JX,JY用于实现真正落棋位置,
            //但这里他们代表的是在二维棋盘数组中的位置,所以后面需要处理成坐标
            if ((x-x0) % size > size / 2)
                JX = (x-x0) / size + 1;
            else
                JX = (x - x0) / size;
            if ((y - y0) % size > size / 2)
                JY = (y -y0) / size + 1;
            else
                JY = (y - y0) / size;

            //实现棋子变色功能
            //使用一个计数器就可以改变颜色了
            if ((Q[JX][JY]==1 || Q[JX][JY]==2)) {
            //已有棋子的位置不能重复落棋
                System.out.println("无法下在这里!");
            }
            else if(flag==0)//这个flag指的是是否点击开始按钮,与落棋算法无关
                return ;
            else {
                if (count % 2 == 0) {
                    g.setColor(Color.black);
                    g.fillOval(JX*size + x0-chesssize/2,JY*size+y0-chesssize/2,chesssize,chesssize);
                    chess Chess = new chess(JX,JY,1);//可以使用Chess类存储相关数据
                    Q1[num]=Chess;
                    Q[JX][JY]=1;
                }
                if (count % 2 == 1) {
                    g.setColor(Color.white);
                    g.fillOval(JX * size + x0 - chesssize/2, JY * size + y0 - chesssize / 2, chesssize, chesssize);
                    chess Chess = new chess(JX,JY,2);
                    Q1[num]=Chess;
                    Q[JX][JY]=2;
                }
                num++;
                count++;
            }
            if(AI_flag==1)//跳转AI下棋
            {
                AI();
            }
            //判断输赢
            if(AI_flag==0)//普通下棋
            {
                if(iswin()>=4)
                {
                    if(Q[JX][JY]==1)
                    {
                        System.out.println("Black win!");
                        flag=0;
                        drawStr("黑棋赢!");//绘画出这个字,后面我会给出完整代码
                    }
                    else if(Q[JX][JY]==2)
                    {
                        System.out.println("White win!");
                        flag=0;
                        drawStr("白棋赢!");
                    }
                }
            }
        }
        //判断输赢函数
        public int iswin(){
            //横向5个
            int c = 0;
            for (int i = JX + 1; i <=line; i++) {
                if (Q[i][JY] == Q[JX][JY]) {
                    c++;
                } else break;
            }
            for (int i = JX - 1; i >= 0; i--) {
                if (Q[i][JY] == Q[JX][JY]) {
                    c++;
                } else break;
            }
            if(c==4)
                return c;
            c=0;
            //纵向五个
            for (int i = JY + 1; i <= line; i++) {
                if (Q[JX][i] == Q[JX][JY]) {
                    c++;
                } else break;
            }
            for (int i = JY - 1; i >= 0; i--) {
                if (Q[JX][i] == Q[JX][JY]) {
                    c++;
                } else break;
            }
            if(c==4)
                return c;
            c=0;
            //斜下
            int i,j;
            for (i = JX + 1,j=JY+1; i <= line&&j<=line; i++,j++) {
                if (Q[i][j] == Q[JX][JY]) {
                    c++;
                } else break;
            }
            for (i = JX - 1,j=JY-1; i >= 0&&j>=0; i--,j--) {
                if (Q[i][j] == Q[JX][JY]) {
                    c++;
                } else break;
            }
            if(c==4)
                return c;
            c=0;
            //斜上
            for (i = JX - 1,j=JY+1; i >=0&&j<=line; i--,j++) {
                if (Q[i][j] == Q[JX][JY]) {
                    c++;
                } else break;
            }
            for (i = JX + 1,j=JY-1; i <=line&&j>=0; i++,j--) {
                if (Q[i][j] ==Q[JX][JY]) {
                    c++;
                } else break;
            }
            if(c==4)
                return c;
            return 0;
        }
        public void mousePressed(MouseEvent e){}
        public void mouseReleased(MouseEvent e){}
        public void mouseEntered(MouseEvent e){}
        public void mouseExited(MouseEvent e){}
}

3)重绘问题
当你已经完成了上面的代码后,你会发现,如果你拉伸框体,上面原本绘制好的棋盘与棋子都会消失,因此我们要添加一个重绘功能。
为了实现重绘功能,我们建立了一个名为MPanel的类,这个类继承了JPanel类,但是我们通过重写里面的paint 方法,实现了对棋盘与棋子的重绘。
在重绘棋子的过程中,我们需要将存储棋盘棋子位置数据的Q数组传入。
可以理解为,我们要将在gamemouse类中创建并记录了落棋数据的二维数组传入现在这个Mpanel类中,具体的实现要依靠UI类来传输,代码就不单独附上了。

public class MPanel extends JPanel{
    public int[][] Q;
    public int x0=50,y0=50,size=50,line=16,chesssize=50;
    //继承JPanel内的方法
    //重写paint方法
    public void paint(Graphics g)
    {
        //重绘窗体
        super.paint(g);
        //绘制棋盘
        for(int i=0;i<line;i++)
        {
            g.setColor(Color.black);
            g.drawLine(x0,size*i+y0,(line-1)*size+x0,i*size+y0);
            g.drawLine(size*i+x0,y0,size*i+x0,(line-1)*size+y0);
        }

        //绘制棋子
        for(int i=0;i<line;i++)
        {
            for(int j=0;j<line;j++)
            {
                if(Q[i][j]==1)//重绘黑棋
                {
                    g.setColor(Color.black);
                    g.fillOval(i*size+x0-chesssize/2,j*size+y0-chesssize/2,chesssize,chesssize);
                }
                else if(Q[i][j]==2)//重绘白棋
                {
                    g.setColor(Color.white);
                    g.fillOval(i*size+x0-chesssize/2,j*size+y0-chesssize/2,chesssize,chesssize);
                }
                else if(Q[i][j]==0)
                {

                }
            }
        }

    }
}

芝士一个画画工具吧
这是博主的爱

三、按钮功能——开始、悔棋、复盘、人人对战

1)添加按钮监听器

        //将gamemouse类改写成这个样子
        public class gamemouse implements MouseListener, ActionListener
        //在UI类中加上
        //添加按钮监听器
        start.addActionListener(gm);
        huiqi.addActionListener(gm);
        fupan.addActionListener(gm);
        manmachine.addActionListener(gm);
        manman.addActionListener(gm);

2)清空与绘画输赢提示
先讲一个清除棋盘上所有棋子的方法
思路很简单

public void clean(){
            for(int i=0;i< line;i++)
            {
                for(int j=0;j<line;j++)
                {
                    Q[i][j]=0;
                }
            }
            mp.repaint();
        }

然后是绘画输赢提示的方法

        //绘画字符串的方法
        public void drawStr(String m){
            g.setColor(Color.RED);
            g.setFont(new Font("楷体",Font.BOLD,90));
            g.drawString(m,mp.getWidth()/2-200,mp.getHeight()/2-40);
        }

3)按钮功能实现
开始:设置一个flag就行,点击后flag变为1才能开始下棋
人人对战:这个学会上面将的下棋了以后就能实现了
悔棋:可以使用哪个Q1数组,按顺序后退,如果是人人对战一次退一子,人机则一次退两子(因为人机是人下后机器立马跟着下),但是我这里设计的是如果已经有结局了就无法退棋,棋盘上只剩一个棋子也无法退棋,这个大家可以自行修改
复盘:也是根据Q1数组,因为这个是按下棋顺序存储的数据,Q数组就没办法这么简单的视线这个功能。清空棋盘后,从前往后一个一个按顺序绘制就可以了。

//按钮监听器
        public void actionPerformed(ActionEvent e)
        {
            //获取按钮内容
            String anniu = e.getActionCommand();
            switch(anniu)
            {
                case "开始" :
                    flag=1;
                    clean();
                    count=0;
                    num=0;
                    AI_flag=0;
                    for(int i=0;i< Q1.length;i++)
                    {
                        Q1[i]=null;
                    }
                    break;
                case "悔棋" :
                    if(num>1&&flag==1)
                    {
                        if(AI_flag==1)
                        {
                            //从一维数组里获取
                            chess Chess = Q1[num-1];
                            Q[Chess.x][Chess.y]=0;
                            Chess.flag=0;
                            Chess = Q1[num-2];
                            Q[Chess.x][Chess.y]=0;
                            Chess.flag=0;
                            count-=2;
                            num-=2;
                            mp.repaint();
                        }
                        else
                        {
                            //从一维数组里获取
                            chess Chess = Q1[num-1];
                            Q[Chess.x][Chess.y]=0;
                            Chess.flag=0;
                            count--;
                            num--;
                            mp.repaint();
                        }
                    }
                    break;
                case "复盘" :
                    clean();
                    mp.paint(g);
                    for(int i=0;i< Q1.length;i++)
                    {
                        if(Q1[i]!=null)
                        {
                            chess Chess = Q1[i];
                            //这个重绘加了延时操作,这样会好看一点
                            try {
                                Thread.sleep(500);
                            } catch (InterruptedException ex) {
                                throw new RuntimeException(ex);
                            }
                            if(Chess.flag==1)//重绘黑棋
                            {
                                g.setColor(Color.black);
                                g.fillOval(Chess.x*size+x0-chesssize/2, Chess.y*size+y0-chesssize/2,chesssize,chesssize);
                                Q[Chess.x][Chess.y]=1;
                            }
                            else if(Chess.flag==2)//重绘白棋
                            {
                                g.setColor(Color.white);
                                g.fillOval(Chess.x*size+x0-chesssize/2, Chess.y*size+y0-chesssize/2,chesssize,chesssize);
                                Q[Chess.x][Chess.y]=2;
                            }
                        }
                    }//完成重绘过程
                    break;
                case "双人对战" :
                    mp.repaint();
                    drawStr("双人对战模式");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException ex) {
                        throw new RuntimeException(ex);
                    }
                    mp.repaint();
                    break;
                case "人机对战" :
                    mp.repaint();
                    drawStr("人机对战模式");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException ex) {
                        throw new RuntimeException(ex);
                    }
                    mp.repaint();
                    AI_flag=1;
                    break;
            }
        }

四、AI功能

先放代码:

//AI算法
        public void AI()
        {
            System.out.println("Ai开始执行");
            int blackcolor=0;
            int whitecolor=0;
            max=0;
            max_x=0;
            max_y=0;

            if(iswin()>=4)
            {
                System.out.println("Black win!");
                flag=0;
                drawStr("恭喜获得胜利!");
            }
            int[][] chessvale = new int[line][line];
            //横向
            for(int i=0;i<line;i++)
            {
                for(int j=0;j<line-4;j++)
                {
                    int k=j;
                    while(k<j+5)
                    {
                        if(Q[i][k]==1)
                            blackcolor++;
                        if(Q[i][k]==2)
                            whitecolor++;
                        k++;
                    }
                    for(k=j;k<j+5;k++)
                    {
                        if(Q[i][k]==0)
                            chessvale[i][k]+=score(blackcolor,whitecolor);
                    }
                    blackcolor=0;
                    whitecolor=0;
                }
            }
            //纵向
            for(int i=0;i<line-4;i++)
            {
                for(int j=0;j<line;j++)
                {
                    int k=i;
                    while(k<i+5)
                    {
                        if(Q[k][j]==1)
                            blackcolor++;
                        if(Q[k][j]==2)
                            whitecolor++;
                        k++;
                    }
                    for(k=i;k<i+5;k++)
                    {
                        if(Q[k][j]==0)
                            chessvale[k][j]+=score(blackcolor,whitecolor);
                    }
                    blackcolor=0;
                    whitecolor=0;
                }
            }
            //斜上1
            for(int i=line-1;i>=4;i--)
            {
                for(int j=0,k=i;j<line&&k>=0;j++,k--)
                {
                    int m=k;
                    int l=j;
                    while(m>k-5&&k-5>=-1)
                    {
                        if(Q[m][l]==1)
                            blackcolor++;
                        if(Q[m][l]==2)
                            whitecolor++;
                        m--;
                        l++;
                    }
                    if(m==k-5)
                    {
                        for(m=k,l=j;m>k-5;m--,l++)
                        {
                            if(Q[m][l]==0)
                            {
                                chessvale[m][l]+=score(blackcolor,whitecolor);
                            }
                        }
                    }
                    blackcolor=0;
                    whitecolor=0;
                }
            }
            //斜上2
            for(int i=0;i<line;i++)
            {
                for(int j=line-1,k=i;j>=0&&k<line;j--,k++)
                {
                    int m=k;
                    int l=j;
                    while(m<k+5&&k+5<=line)
                    {
                        if(Q[m][l]==1)
                            blackcolor++;
                        if(Q[m][l]==2)
                            whitecolor++;
                        m++;
                        l--;
                    }
                    if(m==k+5)
                    {
                        for(m=k,l=j;m<k+5;m++,l--)
                        {
                            if(Q[m][l]==0)
                                chessvale[m][l]+=score(blackcolor,whitecolor);
                        }
                    }
                    blackcolor=0;
                    whitecolor=0;
                }
            }
            //斜下
            for(int i=0;i<line-4;i++)
            {
                for(int j=0,k=i;j<line&&k<line;j++,k++)
                {
                    int m=k;
                    int l=j;
                    while(m<k+5&&k+5<=15)
                    {
                        if(Q[m][l]==1)
                            blackcolor++;
                        if(Q[m][l]==2)
                            whitecolor++;
                        m++;
                        l++;
                    }
                    if(m==k+5)
                    {
                        for(m=k,l=j;m<k+5;m++,l++)
                        {
                            if(Q[m][l]==0)
                                chessvale[m][l]+=score(blackcolor,whitecolor);
                        }
                    }
                    blackcolor=0;
                    whitecolor=0;
                }
            }
            //斜下2
            for(int i=0;i<line-4;i++)
            {
                for(int j=0,k=i;j<line&&k<line;j++,k++)
                {
                    int m=k;
                    int l=j;
                    while(m<k+5&&k+5<=15)
                    {
                        if(Q[l][m]==1)
                            blackcolor++;
                        if(Q[l][m]==2)
                            whitecolor++;
                        m++;
                        l++;
                    }
                    if(m==k+5)
                    {
                        for(m=k,l=j;m<k+5;m++,l++)
                        {
                            if(Q[l][m]==0)
                                chessvale[l][m]+=score(blackcolor,whitecolor);
                        }
                    }
                    blackcolor=0;
                    whitecolor=0;
                }
            }
            //找出最大交点处
            for(int i=0;i<line;i++)
            {
                for(int j=0;j<line;j++)
                {
                    if(chessvale[i][j]>max)
                    {
                        max=chessvale[i][j];
                        max_x=i;
                        max_y=j;
                        System.out.println(max);
                    }
                }
            }

            System.out.println("num="+num);
            System.out.println("max_x"+max_x);
            System.out.println("max_y"+max_y);
            //在最大位置下棋,并判断输赢
            g.setColor(Color.white);
            g.fillOval(max_x * size + x0 - chesssize/2, max_y * size + y0 - chesssize / 2, chesssize, chesssize);
            chess Chess = new chess(max_x,max_y,2);
            Q1[num]=Chess;
            Q[max_x][max_y]=2;
            count++;
            num++;
            System.out.println("判断输赢");
            JX=max_x;
            JY=max_y;
            if(iswin()>=4)
            {
                System.out.println("判断输赢2");
                System.out.println("White win!");
                flag=0;
                drawStr("失败!");
            }
            //清空chessvalue
            for(int i=0;i<line;i++)
            {
                for(int j=0;j<line;j++)
                {
                    chessvale[i][j]=0;
                }
            }
        }

主要实现思路就是:添加一个分值表 --> 遍历空位置,计算权值,放入权值数组 --> 找出最大权值位置 --> AI下棋 -->判断输赢
这个分值表的建立参照的是五子棋AI的五元组实现方法,这个大家可以去参考一下其他的文章,还是比较容易理解的,因为都是现成的权值表拿来可以使用。

总结

终于到总结了,我写不动了。希望我的这个教程能帮到大家,如果大家发现文章内有什么问题的话也欢迎联系我说明。

下面是详细的代码。

gameUI类

public class gameUI {
    //第一步:显示游戏界面
    public  void initUI(){
        //重修修改为JFrame类型的
        JFrame jf = new JFrame();
        jf.setSize(1100,900);
        jf.setLocationRelativeTo(null);
        jf.setTitle("五子棋游戏");
        jf.setDefaultCloseOperation(3);

        JPanel cebian_panel = new JPanel();
        //设置尺寸
        cebian_panel.setPreferredSize(new Dimension(200,0));
        //利用BorderLayout来设置对应方位
        jf.add(cebian_panel,BorderLayout.EAST);
        cebian_panel.setBackground(Color.yellow);

        //添加功能按钮
        JButton start = new JButton("开始");
        start.setFont(new Font("宋体",Font.BOLD,20));

        JButton huiqi = new JButton("悔棋");
        huiqi.setFont(new Font("宋体",Font.BOLD,20));

        JButton fupan = new JButton("复盘");
        fupan.setFont(new Font("宋体",Font.BOLD,20));

        JButton manmachine = new JButton("人机对战");
        manmachine.setFont(new Font("黑体",Font.BOLD,20));

        JButton manman = new JButton("双人对战");
        manman.setFont(new Font("黑体",Font.BOLD,20));


        cebian_panel.add(start);
        cebian_panel.add(huiqi);
        cebian_panel.add(fupan);
        cebian_panel.add(manmachine);
        cebian_panel.add(manman);
        cebian_panel.setLayout(null);
        start.setBounds(50,200,90,50);
        huiqi.setBounds(50,300,90,50);
        fupan.setBounds(50,400,90,50);
        manmachine.setBounds(40,600,120,40);
        manman.setBounds(40,700,120,40);

        //设置棋盘面板
        MPanel mpanel = new MPanel();
        jf.add(mpanel,BorderLayout.CENTER);
        mpanel.setBackground(Color.gray);

        jf.setVisible(true);

        //第三步:画笔绘画
        //绘画画笔需要从应用的组件中获取
        Graphics g = mpanel.getGraphics();



        //第二步:添加鼠标监听器
        gamemouse gm = new gamemouse(g,mpanel);
        //传递Q
        mpanel.Q= gm.Q;
        //创建对象时将构造方法初始化
        //将这里从窗口中获取得到的画笔用来给监听器中私有属性定义的画笔初始化
        mpanel.addMouseListener(gm);
        //添加按钮监听器
        start.addActionListener(gm);
        huiqi.addActionListener(gm);
        fupan.addActionListener(gm);
        manmachine.addActionListener(gm);
        manman.addActionListener(gm);
    }
    public void Win()
    {
        JFrame WIN= new JFrame("胜利");
        WIN.setSize(300,300);
        WIN.setLocationRelativeTo(null);
        WIN.setDefaultCloseOperation(3);

        WIN.setVisible(true);
    }
    //主函数
    public static void main (String[] args)
    {
        gameUI gUI = new gameUI();
        gUI.initUI();
    }
}

gamemouse类

public class gamemouse implements MouseListener, ActionListener {
        public int x0=50,y0=50,size=50,line=16,chesssize=50;
        public int count=0;
        public int[][] Q = new int[line][line];
        public int JX=0,JY=0;
        public int flag=0,num=0,AI_flag=0;
        public chess[] Q1= new chess[line*line];
        //二维数组
        private MPanel mp;
        //引用传递画笔
        private Graphics g;
        public int max=0,max_x=0,max_y=0;
        //构造方法初始化私有修饰符修饰的画笔方法
        public gamemouse(Graphics g, MPanel mp)
        {
            this.g=g;
            this.mp=mp;
        }
        public void clean(){
            for(int i=0;i< line;i++)
            {
                for(int j=0;j<line;j++)
                {
                    Q[i][j]=0;
                }
            }
            mp.repaint();
        }
        //绘画字符串的方法
        public void drawStr(String m){
            g.setColor(Color.RED);
            g.setFont(new Font("楷体",Font.BOLD,90));
            g.drawString(m,mp.getWidth()/2-200,mp.getHeight()/2-40);
        }
        //按钮监听器
        public void actionPerformed(ActionEvent e)
        {
            //获取按钮内容
            String anniu = e.getActionCommand();
            switch(anniu)
            {
                case "开始" :
                    flag=1;
                    clean();
                    count=0;
                    num=0;
                    AI_flag=0;
                    for(int i=0;i< Q1.length;i++)
                    {
                        Q1[i]=null;
                    }
                    break;
                case "悔棋" :
                    if(num>1&&flag==1)
                    {
                        if(AI_flag==1)
                        {
                            //从一维数组里获取
                            chess Chess = Q1[num-1];
                            Q[Chess.x][Chess.y]=0;
                            Chess.flag=0;
                            Chess = Q1[num-2];
                            Q[Chess.x][Chess.y]=0;
                            Chess.flag=0;
                            count-=2;
                            num-=2;
                            mp.repaint();
                        }
                        else
                        {
                            //从一维数组里获取
                            chess Chess = Q1[num-1];
                            Q[Chess.x][Chess.y]=0;
                            Chess.flag=0;
                            count--;
                            num--;
                            mp.repaint();
                        }
                    }
                    break;
                case "复盘" :
                    clean();
                    mp.paint(g);
                    for(int i=0;i< Q1.length;i++)
                    {
                        if(Q1[i]!=null)
                        {
                            chess Chess = Q1[i];
                            try {
                                Thread.sleep(500);
                            } catch (InterruptedException ex) {
                                throw new RuntimeException(ex);
                            }
                            if(Chess.flag==1)//重绘黑棋
                            {
                                g.setColor(Color.black);
                                g.fillOval(Chess.x*size+x0-chesssize/2, Chess.y*size+y0-chesssize/2,chesssize,chesssize);
                                Q[Chess.x][Chess.y]=1;
                            }
                            else if(Chess.flag==2)//重绘白棋
                            {
                                g.setColor(Color.white);
                                g.fillOval(Chess.x*size+x0-chesssize/2, Chess.y*size+y0-chesssize/2,chesssize,chesssize);
                                Q[Chess.x][Chess.y]=2;
                            }
                        }
                    }//完成重绘过程
                    break;
                case "双人对战" :
                    mp.repaint();
                    drawStr("双人对战模式");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException ex) {
                        throw new RuntimeException(ex);
                    }
                    mp.repaint();
                    break;
                case "人机对战" :
                    mp.repaint();
                    drawStr("人机对战模式");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException ex) {
                        throw new RuntimeException(ex);
                    }
                    mp.repaint();
                    AI_flag=1;
                    break;
            }
        }

        public void mouseClicked(MouseEvent e) {
            //鼠标点击后由鼠标监听器获取坐标
            int x = e.getX();
            int y = e.getY();

            //实现落在交点
            if ((x-x0) % size > size / 2)
                JX = (x-x0) / size + 1;
            else
                JX = (x - x0) / size;
            if ((y - y0) % size > size / 2)
                JY = (y -y0) / size + 1;
            else
                JY = (y - y0) / size;

            //实现棋子变色功能
            if ((Q[JX][JY]==1 || Q[JX][JY]==2)) {
                System.out.println("无法下在这里!");
            }
            else if(flag==0)
                return ;
            else {
                if (count % 2 == 0) {
                    g.setColor(Color.black);
                    g.fillOval(JX*size + x0-chesssize/2,JY*size+y0-chesssize/2,chesssize,chesssize);
                    chess Chess = new chess(JX,JY,1);
                    Q1[num]=Chess;
                    Q[JX][JY]=1;
                }
                if (count % 2 == 1) {
                    g.setColor(Color.white);
                    g.fillOval(JX * size + x0 - chesssize/2, JY * size + y0 - chesssize / 2, chesssize, chesssize);
                    chess Chess = new chess(JX,JY,2);
                    Q1[num]=Chess;
                    Q[JX][JY]=2;
                }
                num++;
                count++;
            }
            if(AI_flag==1)
            {
                AI();
            }
            //判断输赢
            if(AI_flag==0)
            {
                if(iswin()>=4)
                {
                    if(Q[JX][JY]==1)
                    {
                        System.out.println("Black win!");
                        flag=0;
                        drawStr("黑棋赢!");
                    }
                    else if(Q[JX][JY]==2)
                    {
                        System.out.println("White win!");
                        flag=0;
                        drawStr("白棋赢!");
                    }
                }
            }
        }
        //判断输赢函数
        public int iswin(){
            //横向5个
            int c = 0;
            for (int i = JX + 1; i <=line; i++) {
                if (Q[i][JY] == Q[JX][JY]) {
                    c++;
                } else break;
            }
            for (int i = JX - 1; i >= 0; i--) {
                if (Q[i][JY] == Q[JX][JY]) {
                    c++;
                } else break;
            }
            if(c==4)
                return c;
            c=0;
            //纵向五个
            for (int i = JY + 1; i <= line; i++) {
                if (Q[JX][i] == Q[JX][JY]) {
                    c++;
                } else break;
            }
            for (int i = JY - 1; i >= 0; i--) {
                if (Q[JX][i] == Q[JX][JY]) {
                    c++;
                } else break;
            }
            if(c==4)
                return c;
            c=0;
            //斜下
            int i,j;
            for (i = JX + 1,j=JY+1; i <= line&&j<=line; i++,j++) {
                if (Q[i][j] == Q[JX][JY]) {
                    c++;
                } else break;
            }
            for (i = JX - 1,j=JY-1; i >= 0&&j>=0; i--,j--) {
                if (Q[i][j] == Q[JX][JY]) {
                    c++;
                } else break;
            }
            if(c==4)
                return c;
            c=0;
            //斜上
            for (i = JX - 1,j=JY+1; i >=0&&j<=line; i--,j++) {
                if (Q[i][j] == Q[JX][JY]) {
                    c++;
                } else break;
            }
            for (i = JX + 1,j=JY-1; i <=line&&j>=0; i++,j--) {
                if (Q[i][j] ==Q[JX][JY]) {
                    c++;
                } else break;
            }
            if(c==4)
                return c;
            return 0;
        }
        public int score(int blackcoler ,int whitecolor){
            if(blackcoler>0&&whitecolor<0)
                return 0;
            if(blackcoler==0&&whitecolor==0)
                return 7;
            if(blackcoler==1)
                return 15;
            if(blackcoler==2)
                return 400;
            if(blackcoler==3)
                return 1800;
            if(blackcoler==4)
                return 100000;
            if(whitecolor==1)
                return 35;
            if(whitecolor==2)
                return 800;
            if(whitecolor==3)
                return 1500;
            if(whitecolor==4)
                return 800000;
            return -1;
        }
        //AI算法
        public void AI()
        {
            System.out.println("Ai开始执行");
            int blackcolor=0;
            int whitecolor=0;
            max=0;
            max_x=0;
            max_y=0;

            if(iswin()>=4)
            {
                System.out.println("Black win!");
                flag=0;
                drawStr("恭喜获得胜利!");
            }
            int[][] chessvale = new int[line][line];
            //横向
            for(int i=0;i<line;i++)
            {
                for(int j=0;j<line-4;j++)
                {
                    int k=j;
                    while(k<j+5)
                    {
                        if(Q[i][k]==1)
                            blackcolor++;
                        if(Q[i][k]==2)
                            whitecolor++;
                        k++;
                    }
                    for(k=j;k<j+5;k++)
                    {
                        if(Q[i][k]==0)
                            chessvale[i][k]+=score(blackcolor,whitecolor);
                    }
                    blackcolor=0;
                    whitecolor=0;
                }
            }
            //纵向
            for(int i=0;i<line-4;i++)
            {
                for(int j=0;j<line;j++)
                {
                    int k=i;
                    while(k<i+5)
                    {
                        if(Q[k][j]==1)
                            blackcolor++;
                        if(Q[k][j]==2)
                            whitecolor++;
                        k++;
                    }
                    for(k=i;k<i+5;k++)
                    {
                        if(Q[k][j]==0)
                            chessvale[k][j]+=score(blackcolor,whitecolor);
                    }
                    blackcolor=0;
                    whitecolor=0;
                }
            }
            //斜上1
            for(int i=line-1;i>=4;i--)
            {
                for(int j=0,k=i;j<line&&k>=0;j++,k--)
                {
                    int m=k;
                    int l=j;
                    while(m>k-5&&k-5>=-1)
                    {
                        if(Q[m][l]==1)
                            blackcolor++;
                        if(Q[m][l]==2)
                            whitecolor++;
                        m--;
                        l++;
                    }
                    if(m==k-5)
                    {
                        for(m=k,l=j;m>k-5;m--,l++)
                        {
                            if(Q[m][l]==0)
                            {
                                chessvale[m][l]+=score(blackcolor,whitecolor);
                            }
                        }
                    }
                    blackcolor=0;
                    whitecolor=0;
                }
            }
            //斜上2
            for(int i=0;i<line;i++)
            {
                for(int j=line-1,k=i;j>=0&&k<line;j--,k++)
                {
                    int m=k;
                    int l=j;
                    while(m<k+5&&k+5<=line)
                    {
                        if(Q[m][l]==1)
                            blackcolor++;
                        if(Q[m][l]==2)
                            whitecolor++;
                        m++;
                        l--;
                    }
                    if(m==k+5)
                    {
                        for(m=k,l=j;m<k+5;m++,l--)
                        {
                            if(Q[m][l]==0)
                                chessvale[m][l]+=score(blackcolor,whitecolor);
                        }
                    }
                    blackcolor=0;
                    whitecolor=0;
                }
            }
            //斜下
            for(int i=0;i<line-4;i++)
            {
                for(int j=0,k=i;j<line&&k<line;j++,k++)
                {
                    int m=k;
                    int l=j;
                    while(m<k+5&&k+5<=15)
                    {
                        if(Q[m][l]==1)
                            blackcolor++;
                        if(Q[m][l]==2)
                            whitecolor++;
                        m++;
                        l++;
                    }
                    if(m==k+5)
                    {
                        for(m=k,l=j;m<k+5;m++,l++)
                        {
                            if(Q[m][l]==0)
                                chessvale[m][l]+=score(blackcolor,whitecolor);
                        }
                    }
                    blackcolor=0;
                    whitecolor=0;
                }
            }
            //斜下2
            for(int i=0;i<line-4;i++)
            {
                for(int j=0,k=i;j<line&&k<line;j++,k++)
                {
                    int m=k;
                    int l=j;
                    while(m<k+5&&k+5<=15)
                    {
                        if(Q[l][m]==1)
                            blackcolor++;
                        if(Q[l][m]==2)
                            whitecolor++;
                        m++;
                        l++;
                    }
                    if(m==k+5)
                    {
                        for(m=k,l=j;m<k+5;m++,l++)
                        {
                            if(Q[l][m]==0)
                                chessvale[l][m]+=score(blackcolor,whitecolor);
                        }
                    }
                    blackcolor=0;
                    whitecolor=0;
                }
            }
            //找出最大交点处
            for(int i=0;i<line;i++)
            {
                for(int j=0;j<line;j++)
                {
                    if(chessvale[i][j]>max)
                    {
                        max=chessvale[i][j];
                        max_x=i;
                        max_y=j;
                        System.out.println(max);
                    }
                }
            }

            System.out.println("num="+num);
            System.out.println("max_x"+max_x);
            System.out.println("max_y"+max_y);
            //在最大位置下棋,并判断输赢
            g.setColor(Color.white);
            g.fillOval(max_x * size + x0 - chesssize/2, max_y * size + y0 - chesssize / 2, chesssize, chesssize);
            chess Chess = new chess(max_x,max_y,2);
            Q1[num]=Chess;
            Q[max_x][max_y]=2;
            count++;
            num++;
            System.out.println("判断输赢");
            JX=max_x;
            JY=max_y;
            if(iswin()>=4)
            {
                System.out.println("判断输赢2");
                System.out.println("White win!");
                flag=0;
                drawStr("失败!");
            }
            //清空chessvalue
            for(int i=0;i<line;i++)
            {
                for(int j=0;j<line;j++)
                {
                    chessvale[i][j]=0;
                }
            }
        }

        public void mousePressed(MouseEvent e){}
        public void mouseReleased(MouseEvent e){}
        public void mouseEntered(MouseEvent e){}
        public void mouseExited(MouseEvent e){}

    }        

chess类

public class chess {
    public int x,y,flag;
    public chess(int x,int y,int flag)
    {
        this.x=x;
        this.y=y;
        this.flag=flag;
    }
}

MPanel类

public class MPanel extends JPanel{
    public int[][] Q;
    public int x0=50,y0=50,size=50,line=16,chesssize=50;
    //继承JPanel内的方法
    //重写paint方法
    public void paint(Graphics g)
    {
        //重绘窗体
        super.paint(g);
        //绘制棋盘
        for(int i=0;i<line;i++)
        {
            g.setColor(Color.black);
            g.drawLine(x0,size*i+y0,(line-1)*size+x0,i*size+y0);
            g.drawLine(size*i+x0,y0,size*i+x0,(line-1)*size+y0);
        }

        //绘制棋子
        for(int i=0;i<line;i++)
        {
            for(int j=0;j<line;j++)
            {

                if(Q[i][j]==1)//重绘黑棋
                {
                    g.setColor(Color.black);
                    g.fillOval(i*size+x0-chesssize/2,j*size+y0-chesssize/2,chesssize,chesssize);
                }
                else if(Q[i][j]==2)//重绘白棋
                {
                    g.setColor(Color.white);
                    g.fillOval(i*size+x0-chesssize/2,j*size+y0-chesssize/2,chesssize,chesssize);
                }
                else if(Q[i][j]==0)
                {

                }
            }
        }

    }
}

在这里插入图片描述

结束啦!!!!!
下期再见!

  • 18
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值