五子棋(java)

设计一个五子棋游戏
游戏采用15×15棋盘,通过二维数组记录棋子位置,支持黑白交替落子,并实现水平/垂直/斜向五连珠判定。特色功能包括:立体棋子渲染、步数统计、胜负提示以及完整的棋局回放系统。

------------------------------------------------------------------------------------------

一、设计游戏面板

先创建自定义面板类public class GameUI {}

显示游戏界面
    public void initUI(){}
        JFrame jf = new JFrame();
        jf.setSize(900,900);
        jf.setTitle("五子棋游戏");
居中显示        jf.setLocationRelativeTo(null);
退出进程        jf.setDefaultCloseOperation(3);

用一个独立的面板对象绘制棋盘
因为自定面板类才有绘制棋盘,棋子功能
~写一个MPanel类负责棋盘绘制和棋子显示~
public class MPanel extends JPanel implements Config {}

引用传递
    public Chess[] chessArr;

重写paint方法
    public void paint(Graphics g){
***1.保留绘制组件的功能
super 表示当前类的父类对象
this  表示本类对象
        super.paint(g);

        System.out.println("paint....");

***2.绘制棋盘,棋子
硬编码
        for(int i=0;i<LINE;i++) {
            g.drawLine(X0, Y0+i*SIZE, (LINE-1)*SIZE+X0, Y0+i*SIZE);
            g.drawLine(X0+i*SIZE, Y0, X0+i*SIZE, (LINE-1)*SIZE+Y0);
        }

重绘所有棋子数据
        for(int i=0;i<chessArr.length;i++){
            Chess c = chessArr[i];
            if(c != null) {
                c.drawChess(g);
            }
        }
    }


        MPanel chessPanel = new MPanel();
        chessPanel.setBackground(Color.GREEN);
        jf.add(chessPanel);

        JPanel eastPanel = new JPanel();
        eastPanel.setPreferredSize(new Dimension(80,0));
        eastPanel.setLayout(new FlowLayout(FlowLayout.CENTER,0,30));
        jf.add(eastPanel,BorderLayout.EAST);

功能按钮
        String[] name = {"开始","悔棋","复盘"};
        for(int i=0;i<name.length;i++){
            JButton jbu = new JButton(name[i]);
            eastPanel.add(jbu);
            jbu.addActionListener(listener);
        }

标签:显示步数
        JLabel label = new JLabel("步数:0");
        label.setFont(new Font("宋体",Font.BOLD,18));
        eastPanel.add(label);


        jf.setVisible(true);

从窗体上获取画笔
        Graphics g = chessPanel.getGraphics();

传递画笔对象
        listener.gr = g;
        listener.chessPanel = chessPanel;
        listener.label=label;

把chessArr数组从GameListener中传递给MPanel类
        chessPanel.chessArr = listener.chessArr;

应用需要一个主函数

public static void main(String[] args) {
        GameUI ui = new GameUI();
        ui.initUI();
}

------------------------------------------------------------------------------------------

二、通过Config接口定义棋盘常量来方便修改与应用数值

实现接口:implements          继承类:extends
实现接口一定要重写接口中所有的抽象方法

自定义接口public interface Config {}

常量
public int X0=50,Y0=50,SIZE=50,LINE=15,CHESS=50;

-----------------------------------------------------------------------------------------

三、创建GameListener类来处理鼠标/按钮事件,实现落子、悔棋、复盘功能并为页面添加监听器

创建监听器类public class GameListener extends MouseAdapter implements Config, ActionListener {}

引用传递
保存传递过来的画笔对象    public Graphics gr;

棋子计数器    public int count = 0;

保存当前棋子的交点值    public int chessX, chessY;

保存当前棋子颜色    public Color color;

保存棋子对象
    public Chess[] chessArr = new Chess[200];

定义二维数组保存棋子颜色
二维数组:一维-行数  二维-列数  =>  int[行][列];
    public int[][] winArr = new int[LINE][LINE];
控制开始游戏的标记位    public boolean start = false;
绘制棋盘面板对象    public MPanel chessPanel;
    public JLabel label;

在自定义面板类中添加监听器

GameListener listener = new GameListener();

给窗体添加鼠标监听器方法
chessPanel.addMouseListener(listener);

~重写监听器处理方法~

1、重写动作监听器处理方法
    public void actionPerformed(ActionEvent e){
        String name = e.getActionCommand();
        switch (name){
            case "开始":
                start = true;
                break;
            case "悔棋":
                retreat();
                break;
            case "复盘":
                replay();
                break;
        }
    }

***悔棋
    public void retreat(){
        //取出最后一颗棋子
        count--;
        Chess c = chessArr[count];
        //清空二维数组数据
        winArr[c.chessY][c.chessX] = 0;
        chessArr[count] = null;

        //刷新棋盘:
        chessPanel.repaint();
    }

***复盘
    public void replay(){
按顺序备份所有的棋子数据
        Chess[] copyArr = new Chess[count];
        for(int i=0;i<count;i++){
            copyArr[i] = chessArr[i];
        }
先清空棋盘上数据
        for(int i=0;i<chessArr.length;i++){
            chessArr[i] = null;
        }
        chessPanel.paint(gr);
按顺序重新把所有棋子再画一遍
        for(int i=0;i<copyArr.length;i++){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            Chess c = copyArr[i];
            c.drawChess(gr);
        }
    }

2、重写鼠标监听器处理方法
    public void mouseClicked(MouseEvent e) {
        int x = e.getX();
        int y = e.getY();
        System.out.println("点击!");

计算棋子交点值
        if ((x - X0) % SIZE > SIZE / 2) {
            chessX = (x - X0) / SIZE + 1;
        } else {
            chessX = (x - X0) / SIZE;
        }
        if ((y - Y0) % SIZE > SIZE / 2) {
            chessY = (y - Y0) / SIZE + 1;
        } else {
            chessY = (y - Y0) / SIZE;
        }

开始游戏
 ! 非  对象结果取反
        if(!start){
            return;
        }

覆盖问题
        if(winArr[chessY][chessX] != 0){
            System.out.println("....");
当前方法的返回值类型是void 表示不需要返回数据
            return;   //结束当前方法的调用
        }

取余  %
        if (count % 2 == 0) {
            color = Color.BLACK;
保存棋子颜色
把棋子的交点值看作是二维数组的下标
            winArr[chessY][chessX] = 1;
        } else {
            color = Color.WHITE;
            winArr[chessY][chessX] = 2;
        }

~创建Chess 对象,保存其数据,并绘制出来~

Chess类实现棋子绘制与数据存储

根据棋子对象设计对应的类public class Chess implements Config {}

属性
交点值    public int chessX, chessY;
当前棋子颜色    public Color color = Color.BLACK;

方法
构造方法:public 类名(参数类型 参数名,,){  方法体...}
作用:1.创建对象  2.同时给多个属性初始化
    public Chess(int chessX, int chessY, Color color) {
        this.chessX = chessX;
        this.chessY = chessY;
        this.color = color;
    }

根据保存数据的还原图形
1.绘制立体棋子(颜色渐变)  2.绘制图片
    public void drawChess(Graphics g) {
        if (color == Color.BLACK) {
            for (int i = 0; i < CHESS; i++) {
                g.setColor(new Color(i*2,i*2,i*2));
                g.fillOval(chessX * SIZE + X0 - CHESS / 2+i/2, chessY * SIZE + Y0 - CHESS / 2+i/2,
                        CHESS - i, CHESS - i);
            }
        } else if (color == Color.WHITE) {
            for (int i = 0; i < CHESS; i++) {
                    g.setColor(new Color((127-i)*2,(127-i)*2,(127-i)*2));
                    g.fillOval(chessX * SIZE + X0 - CHESS / 2+i/2, chessY * SIZE + Y0 - CHESS / 2+i/2,
                            CHESS - i, CHESS - i);
                }
        }
    }


对象的数据类型就是前面的类名
        Chess chess = new Chess(chessX, chessY, color);
        chess.drawChess(gr);

按顺序保存棋子对象
        chessArr[count++] = chess;
        label.setText("步数:"+count);

判断输赢
        if (isWin() >= 5 || isLeftRight()>=5) {
            if (winArr[chessY][chessX] == 1) {
                drawWin("黑棋赢!");
            } else if (winArr[chessY][chessX] == 2) {
                drawWin("白棋赢!");
            }
        }

        System.out.println("isWin() = " + isWin());
//        printArr();
    }

绘制字符串
    public void drawWin(String msg){
        //设置字体大小
        gr.setFont(new Font("宋体",Font.BOLD,40));
        gr.setColor(Color.RED);
        gr.drawString(msg,400,400);
    }

--------------------------------------------------------------------------------

四、在GameListener中编写判断输赢的方法

判断输赢:以最后一颗棋子为中心,搜索该棋子水平,垂直,左斜,右斜四个方向上的相连个数
    public int isWin() {
记录棋子相连个数        int number = 0;
向左
        for (int i = chessX; i >= 0; i--) {
            if (winArr[chessY][i] == winArr[chessY][chessX]) {
                number++;
            } else {
终止当前循环        break;
            }
        }
向右
        for (int i = chessX + 1; i < winArr.length; i++) {
            if (winArr[chessY][i] == winArr[chessY][chessX]) {
                number++;
            } else {
                break;
            }
        }
        return number;
    }
    public int isLeftRight() {
记录棋子相连个数        int number = 0;

左上
        for (int i = chessX,j=chessY; i >= 0 && j>=0; i--,j--) {
            if (winArr[j][i] == winArr[chessY][chessX]) {
                number++;
            } else {
                break;
            }
        }
右下
        for(int i=chessX+1,j=chessY+1;i<winArr.length&&j<winArr.length;i++,j++){
            if (winArr[j][i] == winArr[chessY][chessX]) {
                number++;
            } else {
                break;
            }
        }
        return number;
    }


***打印二维数组
    public void printArr() {
遍历二维数组的数据
        for (int i = 0; i < winArr.length; i++) {
            for (int j = 0; j < winArr[0].length; j++) {
                System.out.print(winArr[i][j] + " ");
            }
            System.out.println();
        }
        System.out.println();
    }

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值