五子棋制作(具备基础功能:下棋与悔棋)

代码全览
图1:Interface     图2:GoListener     图3:Chess
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;

public class Interface extends JFrame{
    GoListener gol=new GoListener();
    double Xd=gol.Xd,Yd=gol.Yd,SIZEd=gol.SIZEd,Rowd=gol.Rowd,Cold=gol.Cold,xbtnPaneld =gol.xbtnPaneld;
    int X=(int)Xd,Y=(int)Yd,SIZE=(int)SIZEd,ROW=(int)Rowd,COL=(int)Cold,xbtnPanel=(int)xbtnPaneld;

    double JFwidthd=900,JFheightd=730;
    int JFwidth=(int)JFwidthd,JFheight=(int)JFheightd;

    public void showUI() {
        setTitle("AI五子棋");
        setSize(JFwidth, JFheight);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        setLayout(null);

        JButton startOverBT = new JButton("开始游戏");
        startOverBT.setBounds ( xbtnPanel/4+SIZE*(COL-1)+SIZE,xbtnPanel/4,xbtnPanel/2,xbtnPanel/4);
        JButton Undo = new JButton("悔      棋");
        Undo.setBounds (xbtnPanel/4+SIZE*(COL-1)+SIZE,xbtnPanel/4+xbtnPanel/2,xbtnPanel/2,xbtnPanel/4);

        add(startOverBT);
        add(Undo);

        setVisible(true);

// 添加鼠标监听器
        addMouseListener(gol);
//按钮添加动作监听器
        startOverBT.addActionListener (gol);
        Undo.addActionListener (gol);
        Graphics g = getGraphics ();
// 初始化Graphics - 画笔
// 将面板上的画笔对象 的地址复制一份给 监听器对象中的画笔对象变量名
        gol.g = g;
    }

    public void paint(Graphics g){
        super.paint(g);
        gol.repaint1(g);
    }

    public static void main(String[] args) {
        Interface goUI = new Interface();
        goUI.showUI();
    }
}
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseListener;
import java.awt.*;
import java.awt.event.MouseEvent;

public class GoListener implements MouseListener, ActionListener{

    // 棋盘参数:
    double Xd=50,Yd=70,SIZEd=40,Rowd=16,Cold=Rowd,xbtnPaneld =200;
    int X=(int)Xd,Y=(int)Yd,SIZE=(int)SIZEd,ROW=(int)Rowd,COL=(int)Cold,xbtnPanel=(int)xbtnPaneld;
    int halfSize=SIZE/2;
    Color bgcolor = new Color(0, 255, 216);
    Graphics g;
    int boolChessFlag=0,chessFlag=1,chessFlagInMouseEntered=0;// 0不能下棋 1黑棋 2白棋
    int[][] chessPiecesLocat=new int[COL][ROW];//chessPiecesLocat[列][有几列]
    Chess[] Chess1=new Chess[ROW*COL];
    int Chess1Index=0;

    public void paint(Graphics g,int chessflag,int x,int y){ //画棋子
        if(chessflag==1){
            int blackChange=200;//调黑棋渐变程度0(全黑)-blackChange
            for(int i = 0; i < blackChange; i++){
                Color colo5 = new Color (i,i,i);
                g.setColor (colo5);
                double di3=SIZEd/blackChange*i/2;
                double di2=SIZEd-SIZEd/blackChange*i;
                int i3=(int)di3;
                int i2=(int)di2;
                g.fillOval (x+i3, y+i3, i2, i2);
            }
        }else if (chessflag==2){
            int whiteChange=160;//调白棋渐变程度whiteChange-255(全白)
            int whiteRange=256-whiteChange;
            for(int i =0; i < whiteRange; i++){
                int colorSet=whiteChange+i;
                Color colo5 = new Color (colorSet,colorSet,colorSet);
                g.setColor (colo5);
                double di3=SIZEd/whiteRange*i/2;
                double di2=SIZEd-SIZEd/whiteRange*i;
                int i3=(int)di3;
                int i2=(int)di2;
                g.fillOval (x+i3, y+i3, i2, i2);
            }
        }
    }

    public int judgeHorizontal(int[][]a,int x,int y){
        int count = 0;// 连子数记录变量
// 向右边查找
        int c1 = a[x][y];
        for(int i = x + 1; i < a.length; i++){
// 右边取出的棋子
            int cn = a[i][y];
// 与c1进行比较
            if(c1 == cn){
                count++;
            } else{
//如果找到一颗棋子 不同于c1 要么是 0
                break;// 跳出循环
            }
        }
        //System.out.println ("向右边查找连子数为:" + count);
// 向左边查找 行不变 列减
// 包含当前棋子本身
        count++;
        for(int i = x - 1; i>=0; i--){
// 右边取出的棋子
            int cn = a[i][y];
// 与c1进行比较
            if(c1 == cn){
                count++;
            } else{
//如果找到一颗棋子 不同于c1 要么是 0
                break;// 跳出循环
            }
        }
        //System.out.println ("横向查找的连子数:" + count);
        return count;
    }
    public int judgeVertical(int[][]a,int x,int y){
        int count = 0;// 连子数记录变量
// 向上边查找
        int c1 = a[x][y];
        for(int i = y - 1; i >=0; i--){
            int cn = a[x][i];
            if(c1 == cn){
                count++;
            } else{
                break;
            }
        }
        //System.out.println ("向上边查找连子数为:" + count);
        count++;
// 向下边查找
        for(int i = y + 1; i<a[x].length; i++){
            int cn = a[x][i];
            if(c1 == cn){
                count++;
            } else{
                break;
            }
        }
        //System.out.println ("纵向查找的连子数:" + count);
        return count;
    }
    public int judgeIncline1(int[][]a,int x,int y){ //左上-右下
        int count = 0;// 连子数记录变量
// 向左上边查找
        int c1 = a[x][y];
        int j=y;
        for(int i = x - 1; i >=0; i--){
            if(j>0){
                j--;
            }else{break;}
            int cn = a[i][j];
            if(c1 == cn){
                count++;
            } else{
                break;
            }
        }
        //System.out.println ("向左上边查找连子数为:" + count);
        count++;
// 向右下边查找
        j=y;
        for(int i = x + 1; i<a.length; i++){
            if(j<a[x].length-1){
                j++;
            }else{break;}
            int cn = a[i][j];
            if(c1 == cn){
                count++;
            } else{
                break;
            }
        }
        //System.out.println ("左上-右下查找的连子数:" + count);
        return count;
    }
    public int judgeIncline2(int[][]a,int x,int y){ //右上-左下
        int count = 0;// 连子数记录变量
// 向右上边查找
        int c1 = a[x][y];
        int j=y;
        for(int i = x + 1; i<a.length; i++){
            if(j>0){
                j--;
            }else{break;}
            int cn = a[i][j];
            if(c1 == cn){
                count++;
            } else{
                break;
            }
        }
        //System.out.println ("向右上边查找连子数为:" + count);
        count++;
// 向左下边查找
        j=y;
        for(int i = x - 1; i>=0; i--){
            if(j<a[x].length-1){
                j++;
            }else{break;}
            int cn = a[i][j];
            if(c1 == cn){
                count++;
            } else{
                break;
            }
        }
        //System.out.println ("右上-左下查找的连子数:" + count);
        return count;
    }
    public boolean judge(int[][]a,int x,int y){
        int a1,b,c,d;
        a1=judgeHorizontal(a,x,y);
        b=judgeVertical(a,x,y);
        c=judgeIncline1(a,x,y);
        d=judgeIncline2(a,x,y);
        if(a1>=5 || b>=5 || c>=5 || d>=5){
            return true;
        }else{return false;}
    }

    public void actionPerformed(ActionEvent e){
        System.out.println ("按钮被点击了");
// 获取按钮的文本
        String btnStr = e.getActionCommand ();
// 获取按钮的对象
        JButton btn = (JButton) e.getSource ();
        if(btnStr.equals ("开始游戏")){
            boolChessFlag=1;// 设置标识 为 黑棋先下
// 点击开始游戏按钮之后 将文本替换成 结束游戏
            btn.setText ("结束游戏");
            //System.out.println("chessFlag"+chessFlag);
        }else if(btnStr.equals ("结束游戏")){
            boolChessFlag=0;// 设置标识 不能下棋
// 点击结束游戏按钮 替换成开始游戏
            btn.setText ("开始游戏");
            //System.out.println("chessFlag"+chessFlag);
        } else if (btnStr.equals ("悔      棋")) {
            if(Chess1Index<=0){
                JOptionPane.showMessageDialog (null,"没有棋子可悔了");
            }else if(Chess1Index>0){
                Chess Chess2=Chess1[Chess1Index-1];
                chessPiecesLocat[Chess2.x][Chess2.y]=0;
                Chess1[Chess1Index-1]=null;
                Chess1Index--;
                if(chessFlag == 1){
                    chessFlag = 2;
                } else if(chessFlag == 2){
                    chessFlag = 1;
                }
                repaint1(g);
            }
        }
    }

        public void repaint1(Graphics g){ //在Interface中需调整棋盘位置重新写repaint为repaint1重画棋盘
            System.out.println("repaint1绘制");
    //在Interface中需调整棋盘的位置,加上 上方边框 左边按钮面板的宽
            int Xboard=X;
            int Yboard=Y;
            g.setColor (bgcolor);
            g.fillRect(Xboard-SIZE/2, Yboard-SIZE/2, SIZE*(ROW-1)+SIZE,SIZE*(COL-1)+SIZE);
    // 绘制棋盘
            g.setColor (Color.black);
            for(int i = 0; i <ROW; i++){
                g.drawLine (Xboard, Yboard+i*SIZE, Xboard + (COL-1)* SIZE, Yboard+i*SIZE);
                g.drawLine (Xboard+i*SIZE,Yboard,Xboard+i*SIZE,Yboard+(ROW-1)*SIZE);
            }
            g.setColor (Color.red);
            g.drawRect (Xboard-halfSize,Yboard-halfSize,SIZE*(COL-1)+SIZE,SIZE*(ROW-1)+SIZE);
    //画棋子
            for(int i=0;i<chessPiecesLocat.length;i++){
                for(int j=0;j<chessPiecesLocat[i].length;j++){
                    if(chessPiecesLocat[i][j]==0){
                        continue;
                    } else if (chessPiecesLocat[i][j]==1) {
                        chessFlagInMouseEntered=1;
                    } else if (chessPiecesLocat[i][j]==2) {
                        chessFlagInMouseEntered=2;
                    }
                    double x1=i*SIZEd+Xd-SIZEd/2;
                    double y1=j*SIZEd+Yd-SIZEd/2;
                    int xshow=(int)x1;
                    int yshow=(int)y1;
                    paint(g,chessFlagInMouseEntered,xshow,yshow);
                }
            }
        }

    @Override
    public void mousePressed(MouseEvent e){
        if(boolChessFlag==0){
// 弹窗
            JOptionPane.showMessageDialog (null,"游戏未开始");
            return;// 结束方法
        }
        System.out.println ("鼠标按下事件");
// 获取坐标
        int x = e.getX ();
        int y = e.getY ();
        //System.out.println("获取坐标--x:"+x+",y:"+y);
        double xd=x,yd=y;
        double x2=(xd-Xd+SIZEd/2)/SIZEd;
        double y2=(yd-Yd+SIZEd/2)/SIZEd;
        int x3=(int)x2;
        int y3=(int)y2;
        System.out.println("x3:"+x3+",y3:"+y3);
        if(x2<0 || x3>COL-1 || y2<0 || y3>ROW-1){
            return;
        }
        double x1=x3*SIZEd+Xd-SIZEd/2;
        double y1=y3*SIZEd+Yd-SIZEd/2;
        int xshow=(int)x1;
        int yshow=(int)y1;

        if(chessPiecesLocat[x3][y3]!=0){
            //JOptionPane.showMessageDialog (null,"该位置已有棋子");
            System.out.println("该位置已有棋子");
            return;
        }
        chessPiecesLocat[x3][y3]=chessFlag;
        Chess chess=new Chess();
        chess.x=x3;
        chess.y=y3;
        chess.chessFlag=chessFlag;
        Chess1[Chess1Index]=chess;
        Chess1Index++;


//绘制 外切矩形的左上角坐标 宽度 高度
        paint(g,chessFlag,xshow,yshow);
        if(judge(chessPiecesLocat,x3,y3)){
            if(chessFlag==1){JOptionPane.showMessageDialog (null,"游戏结束,黑方胜利!");}
            if(chessFlag==2){JOptionPane.showMessageDialog (null,"游戏结束,白方胜利!");}
            int[][]newChessPiecesArray=new int[COL][ROW];
            chessPiecesLocat=newChessPiecesArray;
            chessFlag=1;
            Chess1Index=0;
            repaint1(g);
            return;
        }
// 将散坐标 转成 标准坐标
// 将58 转成 0 转成 50
        if(chessFlag == 1){
            chessFlag = 2;
        } else if(chessFlag == 2){
            chessFlag = 1;
        }
    }
    @Override
    public void mouseClicked(MouseEvent e){}
    @Override
    public void mouseReleased(MouseEvent e){}
    @Override
    public void mouseEntered(MouseEvent e){}
    @Override
    public void mouseExited(MouseEvent e){}
}
public class Chess {
    int x;
    int y;
    int chessFlag;
}

讲解

首先创建一个界面类Interface作为五子棋界面类(图1)
public class Interface extends JFrame继承JFrame使Interface拥有JFrame的方法,方便之后重写绘制底板的方法

在Interface中设置基本参数,边距X ,Y; 棋子大小/棋盘格子大小SIZE; 绘制棋盘纵向线数COL,横向线数ROW;以及按钮面板宽度xbtnPanel。这里为了方便修改数据直接在Golistener中设置,而界面类中调用数据即可,在后面会看到具体数据为

Xd=50,Yd=70,SIZEd=40,Rowd=16,Cold=Rowd,xbtnPaneld =200;

转换int和double为后期计算需要,可按自己的需要进行转换。

创建变量JFwidth=900,JFheight=730用来设置整个JFrame界面大小。

    GoListener gol=new GoListener();
    double Xd=gol.Xd,Yd=gol.Yd,SIZEd=gol.SIZEd,Rowd=gol.Rowd,Cold=gol.Cold,xbtnPaneld =gol.xbtnPaneld;
    int X=(int)Xd,Y=(int)Yd,SIZE=(int)SIZEd,ROW=(int)Rowd,COL=(int)Cold,xbtnPanel=(int)xbtnPaneld;

    double JFwidthd=900,JFheightd=730;
    int JFwidth=(int)JFwidthd,JFheight=(int)JFheightd;

创建showUI方法,设置界面标题,大小,关闭选项,位置和排列布局(showUI中的前5行)

接下去的4行设置了游戏开始和悔棋按钮位置和大小

之后添加鼠标监听器,按钮添加动作监听器,将面板上的画笔对象 的地址复制一份给监听器对象中的画笔对象变量名

其中GoListener为我们另外创建的监听器类(图2)

    public void showUI() {
        setTitle("AI五子棋");
        setSize(JFwidth, JFheight);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        setLayout(null);

        JButton startOverBT = new JButton("开始游戏");
        startOverBT.setBounds ( xbtnPanel/4+SIZE*(COL-1)+SIZE,xbtnPanel/4,xbtnPanel/2,xbtnPanel/4);
        JButton Undo = new JButton("悔      棋");
        Undo.setBounds (xbtnPanel/4+SIZE*(COL-1)+SIZE,xbtnPanel/4+xbtnPanel/2,xbtnPanel/2,xbtnPanel/4);

        add(startOverBT);
        add(Undo);

        setVisible(true);

// 添加鼠标监听器
        addMouseListener(gol);
//按钮添加动作监听器
        startOverBT.addActionListener (gol);
        Undo.addActionListener (gol);
        Graphics g = getGraphics ();
// 初始化Graphics - 画笔
// 将面板上的画笔对象 的地址复制一份给 监听器对象中的画笔对象变量名
        gol.g = g;
    }

再创建main方法显示窗口界面

    public static void main(String[] args) {
        Interface goUI = new Interface();
        goUI.showUI();
    }

重写JFrame中paint方法,这样改变窗体大小时棋盘和棋子就不会消失,其中用到了GoListener中的方法在下面会讲到

    public void paint(Graphics g){
        super.paint(g);
        gol.repaint1(g);
    }

创建GoListener类调用接口MouseListener来检测按钮点击情况,ActionListener用来检测棋盘点击情况。设置基本变量的值。bgcolor是棋盘的背景颜色,创建Graphics g实现画笔功能boolChessFlag=0,chessFlag=1,chessFlagInMouseEntered=0; 二维数组int[][]用来存储棋子位置以达到还原棋子目的,Chess为我们之后建的棋子类,用来存储下棋时每颗棋的位置和顺序:

public class Chess {
    int x;
    int y;
    int chessFlag;
}

ChessIndex

public class GoListener implements MouseListener, ActionListener{
    // 棋盘参数:
    double Xd=50,Yd=70,SIZEd=40,Rowd=16,Cold=Rowd,xbtnPaneld =200;
    int X=(int)Xd,Y=(int)Yd,SIZE=(int)SIZEd,ROW=(int)Rowd,COL=(int)Cold,xbtnPanel=(int)xbtnPaneld;
    int halfSize=SIZE/2;
    Color bgcolor = new Color(0, 255, 216);
    Graphics g;
    int boolChessFlag=0,chessFlag=1,chessFlagInMouseEntered=0;// 0不能下棋 1黑棋 2白棋
    int[][] chessPiecesLocat=new int[COL][ROW];//chessPiecesLocat[列][有几列]
    Chess[] Chess1=new Chess[ROW*COL];
    int Chess1Index=0;
}

因为我们调用了两个接口,必须重写其中所有方法

    public void actionPerformed(ActionEvent e){};
    public void mouseClicked(MouseEvent e){};
    public void mousePressed(MouseEvent e){};
    public void mouseReleased(MouseEvent e){};
    public void mouseEntered(MouseEvent e){};
    public void mouseExited(MouseEvent e){};

而我们只想改变actionPerformed和mousePressed(下面会讲)方法,所以其他方法保留原样即可

actionPerformed方法可检测按钮的点击,写入点击 开始游戏 按键后按键上字符改为 结束游戏 并开始游戏(boolChessFlag=1),反之同理。

    public void actionPerformed(ActionEvent e){
        System.out.println ("按钮被点击了");
// 获取按钮的文本
        String btnStr = e.getActionCommand ();
// 获取按钮的对象
        JButton btn = (JButton) e.getSource ();
        if(btnStr.equals ("开始游戏")){
            boolChessFlag=1;// 设置标识 为 黑棋先下
// 点击开始游戏按钮之后 将文本替换成 结束游戏
            btn.setText ("结束游戏");
        }else if(btnStr.equals ("结束游戏")){
            boolChessFlag=0;// 设置标识 不能下棋
// 点击结束游戏按钮 替换成开始游戏
            btn.setText ("开始游戏");
            }
        }
    }

在GoListener中创建方法repaint1,用于绘制棋盘,此方法就是上面看到的Interface类paint方法中调用的方法(保证棋盘画在JFrame下面,拖动窗口就不会消失了)

        public void repaint1(Graphics g){ //在Interface中需调整棋盘位置重新写repaint为repaint1重画棋盘
            System.out.println("repaint1绘制");
    //在Interface中需调整棋盘的位置,加上 上方边框 左边按钮面板的宽
            int Xboard=X;
            int Yboard=Y;
            g.setColor (bgcolor);
            g.fillRect(Xboard-SIZE/2, Yboard-SIZE/2, SIZE*(ROW-1)+SIZE,SIZE*(COL-1)+SIZE);
    // 绘制棋盘
            g.setColor (Color.black);
            for(int i = 0; i <ROW; i++){
                g.drawLine (Xboard, Yboard+i*SIZE, Xboard + (COL-1)* SIZE, Yboard+i*SIZE);
                g.drawLine (Xboard+i*SIZE,Yboard,Xboard+i*SIZE,Yboard+(ROW-1)*SIZE);
            }
            g.setColor (Color.red);
            g.drawRect (Xboard-halfSize,Yboard-halfSize,SIZE*(COL-1)+SIZE,SIZE*(ROW-1)+SIZE);
        }

之后,为了实现鼠标点击棋盘画出棋子,在GoListener中重写MousePressed方法,当开始游戏按钮没被点击时我们希望他不画棋子而是弹出一个游戏未开始的提示,反之画棋子

先获取每次点击的位置坐标,这时用坐标画棋子并不会对其棋盘规定落棋点,所以要把该坐标转化为棋盘坐标

x2=(xd-Xd+SIZEd/2)/SIZEd;
y2=(yd-Yd+SIZEd/2)/SIZEd;

再计算该棋盘坐标在界面上的坐标

x1=x3*SIZEd+Xd-SIZEd/2;
y1=y3*SIZEd+Yd-SIZEd/2;

在算出棋盘坐标后可判断点击位置是否超出棋盘,若超出就不画棋子;读取存储棋子位置的二维数组,若该位置有棋子,则不画,确保棋子在该点能画后画上棋子,再将坐标存入二维数组中,更换chessflag保证下一颗棋子为不同颜色的棋。

    public void mousePressed(MouseEvent e){
        if(boolChessFlag==0){
// 弹窗
            JOptionPane.showMessageDialog (null,"游戏未开始");
            return;// 结束方法
        }
        System.out.println ("鼠标按下事件");
// 获取坐标
        int x = e.getX ();
        int y = e.getY ();
        //System.out.println("获取坐标--x:"+x+",y:"+y);
        double xd=x,yd=y;
        double x2=(xd-Xd+SIZEd/2)/SIZEd;
        double y2=(yd-Yd+SIZEd/2)/SIZEd;
        int x3=(int)x2;
        int y3=(int)y2;
        System.out.println("x3:"+x3+",y3:"+y3);
        if(x2<0 || x3>COL-1 || y2<0 || y3>ROW-1){
            return;
        }
        double x1=x3*SIZEd+Xd-SIZEd/2;
        double y1=y3*SIZEd+Yd-SIZEd/2;
        int xshow=(int)x1;
        int yshow=(int)y1;

        if(chessPiecesLocat[x3][y3]!=0){
            //JOptionPane.showMessageDialog (null,"该位置已有棋子");
            System.out.println("该位置已有棋子");
            return;
        }
        chessPiecesLocat[x3][y3]=chessFlag;
        Chess chess=new Chess();
        chess.x=x3;
        chess.y=y3;
        chess.chessFlag=chessFlag;
        Chess1[Chess1Index]=chess;
        Chess1Index++;

        paint(g,chessFlag,xshow,yshow);

        if(chessFlag == 1){
            chessFlag = 2;
        } else if(chessFlag == 2){
            chessFlag = 1;
        }
    }

上面所用到的paint方法为我们另外创建的方法,用于绘制立体棋子

    public void paint(Graphics g,int chessflag,int x,int y){ //画棋子
        if(chessflag==1){
            int blackChange=200;//调黑棋渐变程度0(全黑)-blackChange
            for(int i = 0; i < blackChange; i++){
                Color colo5 = new Color (i,i,i);
                g.setColor (colo5);
                double di3=SIZEd/blackChange*i/2;
                double di2=SIZEd-SIZEd/blackChange*i;
                int i3=(int)di3;
                int i2=(int)di2;
                g.fillOval (x+i3, y+i3, i2, i2);
            }
        }else if (chessflag==2){
            int whiteChange=160;//调白棋渐变程度whiteChange-255(全白)
            int whiteRange=256-whiteChange;
            for(int i =0; i < whiteRange; i++){
                int colorSet=whiteChange+i;
                Color colo5 = new Color (colorSet,colorSet,colorSet);
                g.setColor (colo5);
                double di3=SIZEd/whiteRange*i/2;
                double di2=SIZEd-SIZEd/whiteRange*i;
                int i3=(int)di3;
                int i2=(int)di2;
                g.fillOval (x+i3, y+i3, i2, i2);
            }
        }
    }

因为我们有二维数组存储已下棋子的坐标和颜色,我们可以还原棋子,而我们拖动界面时棋子会消失,这时我们需要这个功能;重画棋盘时棋子也会消失,这时我们也需要这个功能。所以我们在repaint1方法末端加上重画棋子的代码,棋子就会一直留在界面上

        public void repaint1(Graphics g){ //在Interface中需调整棋盘位置重新写repaint为repaint1重画棋盘
            System.out.println("repaint1绘制");
    //在Interface中需调整棋盘的位置,加上 上方边框 左边按钮面板的宽
            int Xboard=X;
            int Yboard=Y;
            g.setColor (bgcolor);
            g.fillRect(Xboard-SIZE/2, Yboard-SIZE/2, SIZE*(ROW-1)+SIZE,SIZE*(COL-1)+SIZE);
    // 绘制棋盘
            g.setColor (Color.black);
            for(int i = 0; i <ROW; i++){
                g.drawLine (Xboard, Yboard+i*SIZE, Xboard + (COL-1)* SIZE, Yboard+i*SIZE);
                g.drawLine (Xboard+i*SIZE,Yboard,Xboard+i*SIZE,Yboard+(ROW-1)*SIZE);
            }
            g.setColor (Color.red);
            g.drawRect (Xboard-halfSize,Yboard-halfSize,SIZE*(COL-1)+SIZE,SIZE*(ROW-1)+SIZE);
    //画棋子
            for(int i=0;i<chessPiecesLocat.length;i++){
                for(int j=0;j<chessPiecesLocat[i].length;j++){
                    if(chessPiecesLocat[i][j]==0){
                        continue;
                    } else if (chessPiecesLocat[i][j]==1) {
                        chessFlagInMouseEntered=1;
                    } else if (chessPiecesLocat[i][j]==2) {
                        chessFlagInMouseEntered=2;
                    }
                    double x1=i*SIZEd+Xd-SIZEd/2;
                    double y1=j*SIZEd+Yd-SIZEd/2;
                    int xshow=(int)x1;
                    int yshow=(int)y1;
                    paint(g,chessFlagInMouseEntered,xshow,yshow);
                }
            }
        }

接下去实现悔棋功能。

在mousePressed方法的下半部分有写

Chess chess=new Chess();
chess.x=x3;
chess.y=y3;
chess.chessFlag=chessFlag;
Chess1[Chess1Index]=chess;
Chess1Index++;

这一段将棋子的位置和颜色编号,按下棋的顺序存入数组Chess1中,注意此数组为Chess类的数组,而Chess类中有三个变量为x,y和chessFlag,创建new Cjess()再把对应的值付给chess,再把当前的chess存到Chess1数组中,最后把ChessIndex也就是记录数组中对象总数的变量+1,要悔棋时从后往前删除对象。

所以我们在按钮被按下的方法中加入按下悔棋时的操作:先判断棋盘上有几个棋子,如果没有棋子那就不能悔棋,若有,将最后存入的棋取出,在二维数组chessPiecesLocat中删除对应位置的棋子chessPiecesLocat[Chess2.x][Chess2.y]=0,同时删除Chess1中的最后一个对象Chess1[Chess1Index-1]=null,之后重画棋盘和棋子就能达到悔棋的效果。

    public void actionPerformed(ActionEvent e){
        System.out.println ("按钮被点击了");
// 获取按钮的文本
        String btnStr = e.getActionCommand ();
// 获取按钮的对象
        JButton btn = (JButton) e.getSource ();
        if(btnStr.equals ("开始游戏")){
            boolChessFlag=1;// 设置标识 为 黑棋先下
// 点击开始游戏按钮之后 将文本替换成 结束游戏
            btn.setText ("结束游戏");
            //System.out.println("chessFlag"+chessFlag);
        }else if(btnStr.equals ("结束游戏")){
            boolChessFlag=0;// 设置标识 不能下棋
// 点击结束游戏按钮 替换成开始游戏
            btn.setText ("开始游戏");
            //System.out.println("chessFlag"+chessFlag);
        } else if (btnStr.equals ("悔      棋")) {
            if(Chess1Index<=0){
                JOptionPane.showMessageDialog (null,"没有棋子可悔了");
            }else if(Chess1Index>0){
                Chess Chess2=Chess1[Chess1Index-1];
                chessPiecesLocat[Chess2.x][Chess2.y]=0;
                Chess1[Chess1Index-1]=null;
                Chess1Index--;
                if(chessFlag == 1){
                    chessFlag = 2;
                } else if(chessFlag == 2){
                    chessFlag = 1;
                }
                repaint1(g);
            }
        }
    }

接下来实现判断输赢的功能

判断输赢需从4个方向判断,为了代码整齐,在GoListener中写4个方法判断+1个方法整合

    public int judgeHorizontal(int[][]a,int x,int y){
        int count = 0;// 连子数记录变量
// 向右边查找
        int c1 = a[x][y];
        for(int i = x + 1; i < a.length; i++){
// 右边取出的棋子
            int cn = a[i][y];
// 与c1进行比较
            if(c1 == cn){
                count++;
            } else{
//如果找到一颗棋子 不同于c1 要么是 0
                break;// 跳出循环
            }
        }
        //System.out.println ("向右边查找连子数为:" + count);
// 向左边查找 行不变 列减
// 包含当前棋子本身
        count++;
        for(int i = x - 1; i>=0; i--){
// 右边取出的棋子
            int cn = a[i][y];
// 与c1进行比较
            if(c1 == cn){
                count++;
            } else{
//如果找到一颗棋子 不同于c1 要么是 0
                break;// 跳出循环
            }
        }
        //System.out.println ("横向查找的连子数:" + count);
        return count;
    }
    public int judgeVertical(int[][]a,int x,int y){
        int count = 0;// 连子数记录变量
// 向上边查找
        int c1 = a[x][y];
        for(int i = y - 1; i >=0; i--){
            int cn = a[x][i];
            if(c1 == cn){
                count++;
            } else{
                break;
            }
        }
        //System.out.println ("向上边查找连子数为:" + count);
        count++;
// 向下边查找
        for(int i = y + 1; i<a[x].length; i++){
            int cn = a[x][i];
            if(c1 == cn){
                count++;
            } else{
                break;
            }
        }
        //System.out.println ("纵向查找的连子数:" + count);
        return count;
    }
    public int judgeIncline1(int[][]a,int x,int y){ //左上-右下
        int count = 0;// 连子数记录变量
// 向左上边查找
        int c1 = a[x][y];
        int j=y;
        for(int i = x - 1; i >=0; i--){
            if(j>0){
                j--;
            }else{break;}
            int cn = a[i][j];
            if(c1 == cn){
                count++;
            } else{
                break;
            }
        }
        //System.out.println ("向左上边查找连子数为:" + count);
        count++;
// 向右下边查找
        j=y;
        for(int i = x + 1; i<a.length; i++){
            if(j<a[x].length-1){
                j++;
            }else{break;}
            int cn = a[i][j];
            if(c1 == cn){
                count++;
            } else{
                break;
            }
        }
        //System.out.println ("左上-右下查找的连子数:" + count);
        return count;
    }
    public int judgeIncline2(int[][]a,int x,int y){ //右上-左下
        int count = 0;// 连子数记录变量
// 向右上边查找
        int c1 = a[x][y];
        int j=y;
        for(int i = x + 1; i<a.length; i++){
            if(j>0){
                j--;
            }else{break;}
            int cn = a[i][j];
            if(c1 == cn){
                count++;
            } else{
                break;
            }
        }
        //System.out.println ("向右上边查找连子数为:" + count);
        count++;
// 向左下边查找
        j=y;
        for(int i = x - 1; i>=0; i--){
            if(j<a[x].length-1){
                j++;
            }else{break;}
            int cn = a[i][j];
            if(c1 == cn){
                count++;
            } else{
                break;
            }
        }
        //System.out.println ("右上-左下查找的连子数:" + count);
        return count;
    }

整合上面四个方法

    public boolean judge(int[][]a,int x,int y){
        int a1,b,c,d;
        a1=judgeHorizontal(a,x,y);
        b=judgeVertical(a,x,y);
        c=judgeIncline1(a,x,y);
        d=judgeIncline2(a,x,y);
        if(a1>=5 || b>=5 || c>=5 || d>=5){
            return true;
        }else{return false;}
    }

判断输赢的最好时机就是鼠标点击下完棋子的时候,所以在mousePressed方法中,在将棋子存入二维数组之后加上判断输赢语句

if(judge(chessPiecesLocat,x3,y3)){
    if(chessFlag==1){JOptionPane.showMessageDialog (null,"游戏结束,黑方胜利!");}
    if(chessFlag==2){JOptionPane.showMessageDialog (null,"游戏结束,白方胜利!");}
    int[][]newChessPiecesArray=new int[COL][ROW];
    chessPiecesLocat=newChessPiecesArray;
    chessFlag=1;
    Chess1Index=0;
    repaint1(g);
    return;
}
    public void mousePressed(MouseEvent e){
        if(boolChessFlag==0){
// 弹窗
            JOptionPane.showMessageDialog (null,"游戏未开始");
            return;// 结束方法
        }
        System.out.println ("鼠标按下事件");
// 获取坐标
        int x = e.getX ();
        int y = e.getY ();
        //System.out.println("获取坐标--x:"+x+",y:"+y);
        double xd=x,yd=y;
        double x2=(xd-Xd+SIZEd/2)/SIZEd;
        double y2=(yd-Yd+SIZEd/2)/SIZEd;
        int x3=(int)x2;
        int y3=(int)y2;
        System.out.println("x3:"+x3+",y3:"+y3);
        if(x2<0 || x3>COL-1 || y2<0 || y3>ROW-1){
            return;
        }
        double x1=x3*SIZEd+Xd-SIZEd/2;
        double y1=y3*SIZEd+Yd-SIZEd/2;
        int xshow=(int)x1;
        int yshow=(int)y1;

        if(chessPiecesLocat[x3][y3]!=0){
            //JOptionPane.showMessageDialog (null,"该位置已有棋子");
            System.out.println("该位置已有棋子");
            return;
        }
        chessPiecesLocat[x3][y3]=chessFlag;
        Chess chess=new Chess();
        chess.x=x3;
        chess.y=y3;
        chess.chessFlag=chessFlag;
        Chess1[Chess1Index]=chess;
        Chess1Index++;


//绘制 外切矩形的左上角坐标 宽度 高度
        paint(g,chessFlag,xshow,yshow);
        if(judge(chessPiecesLocat,x3,y3)){
            if(chessFlag==1){JOptionPane.showMessageDialog (null,"游戏结束,黑方胜利!");}
            if(chessFlag==2){JOptionPane.showMessageDialog (null,"游戏结束,白方胜利!");}
            int[][]newChessPiecesArray=new int[COL][ROW];
            chessPiecesLocat=newChessPiecesArray;
            chessFlag=1;
            Chess1Index=0;
            repaint1(g);
            return;
        }

        if(chessFlag == 1){
            chessFlag = 2;
        } else if(chessFlag == 2){
            chessFlag = 1;
        }
    }

到此,一个基础的五子棋程序就完成了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值