Java单机版五子棋

这几天做了一个小应用,单机版的五子棋开发。分享一下源代码。

总共有三个类文件,分别为:StartChessJFrame.java, Point.java, ChessBoard.java

//StartChessJFrame.java
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
/**
 * This is main window.
 * @author Logan
 * 主函数文件,包括顶部菜单和底部菜单,包括主面板。
 */

public class StartChessJFrame extends JFrame{
    //对战面板
    private ChessBoard chessBoard;

    //工具条面板
    private JPanel toolbar;

    //“重新开始”按钮,“悔棋”按钮,“退出”按钮
    private JButton startButton;
    private JButton backButton;
    private JButton exitButton;

    //菜单栏
    private JMenuBar menuBar;

    //系统菜单
    private JMenu sysMenu;

    //“重新开始”,“退出”和“悔棋”菜单项
    private JMenuItem startMenuItem;
    private JMenuItem exitMenuItem;
    private JMenuItem backMenuItem;

    public StartChessJFrame(){

        //设置标题
        setTitle("单机版五子棋");

        //初始化面板对象
        //创建和添加菜单
        chessBoard = new ChessBoard();

        //初始化菜单栏
        menuBar = new JMenuBar();

        //初始化菜单
        sysMenu = new JMenu("系统");

        //初始化菜单项
        startMenuItem = new JMenuItem("重新开始");
        exitMenuItem = new JMenuItem("退出");
        backMenuItem = new JMenuItem("悔棋");

        //将三个菜单项添加到菜单上
        sysMenu.add(startMenuItem);
        sysMenu.add(exitMenuItem);
        sysMenu.add(backMenuItem);

        //初始化按钮事件监听器内部类
        MyItemListener lis = new MyItemListener();

        //将三个菜单项注册到事件监听器上
        this.startMenuItem.addActionListener(lis);
        //不知道为什么这两个没有this
        backMenuItem.addActionListener(lis);
        exitMenuItem.addActionListener(lis);

        //将“系统”菜单添加到菜单栏上
        menuBar.add(sysMenu);

        //将menuBar设置为菜单栏
        setJMenuBar(menuBar);

        //工具面板栏实例化
        toolbar = new JPanel();

        //三个按钮初始化
        startButton = new JButton("重新开始");
        backButton = new JButton("悔棋");
        exitButton = new JButton("退出");

        //将工具面板按钮用FlowLayout布局
        toolbar.setLayout(new FlowLayout(FlowLayout.LEFT));

        //将三个按钮添加到工具面板上
        toolbar.add(startButton);
        toolbar.add(backButton);
        toolbar.add(exitButton);

        //将三个按钮注册监听事件
        startButton.addActionListener(lis);
        backButton.addActionListener(lis);
        exitButton.addActionListener(lis);

        //将工具面板布局到界面“南”方也就是下面
        add(toolbar,BorderLayout.SOUTH);

        //将面板对象添加到窗体上
        add(chessBoard);

        //设置界面关闭事件
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //自适应大小
        pack();
    }

    //事件监听器内部类
    private class MyItemListener implements ActionListener{
        public void actionPerformed(ActionEvent e){
            //取得事件源
            Object obj = e.getSource();

            //重新开始
            //JFiveFrame.this内部类引用外部类
            if(obj == StartChessJFrame.this.startMenuItem||obj == startButton){
                System.out.println("重新开始...");
                chessBoard.restartGame();
            }
            else if(obj == exitMenuItem || obj == exitButton){
                //结束应用程序
                System.exit(0);
            }
            else if(obj == backMenuItem || obj == backButton){
                //悔棋
                System.out.println("悔棋...");
                chessBoard.goback();
            }
        }
    }
    public static void main(String [] args){
        //创建主框架
        StartChessJFrame f = new StartChessJFrame();
        //显示主框架
        f.setVisible(true);
    }
}
//Point.java
//点类,
import java.awt.Color;
public class Point {
    //棋盘中的x索引
    private int x;

    //期盼中的y索引
    private int y;

    //颜色
    private Color color;

    //直径
    public static final int DIAMETER = 30;

    public Point(int x, int y, Color color){
        this.x = x;
        this.y = y;
        this.color = color;
    }

    //拿到棋盘中的x索引
    public int getX(){
        return x;
    }

    //拿到棋盘中的y索引
    public int getY(){
        return y;
    }

    //拿到颜色
    public Color getColor(){
        return color;
    }
}
//ChessBoard.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseEvent;

/**
 * 五子棋-棋盘类
 * @author Logan
 * 棋盘主函数。
 */
public class ChessBoard extends JPanel implements MouseListener{
    //边距
    public static final int MARGIN = 30;

    //网格间距
    public static final int GRID_SPAN = 30;

    //棋盘行数
    public static final int ROWS = 10;

    //棋盘列数
    public static final int COLS = 10;

    //初始每个数组元素为null
    Point[] chessList = new Point[(ROWS+1)*(COLS+1)];

    //默认开始是黑旗先下
    boolean isBlack = true;

    //游戏是否结束
    boolean gameover = false;

    //当前棋盘的旗子个数
    int chessCount;

    //当前刚下的旗子的索引
    int xIndex, yIndex;

    //绘制
    public ChessBoard(){
        //设置背景颜色为橘黄色
        setBackground(Color.ORANGE);

        //添加监听器
        addMouseListener(this);

        //匿名内部类
        addMouseMotionListener(new MouseMotionListener(){
            public void mouseDragged(MouseEvent e){
                //没有函数体
            }
            public void mouseMoved(MouseEvent e){
                //将鼠标单击的坐标位置转换成网格索引
                int x1 = (e.getX()-MARGIN+GRID_SPAN/2)/GRID_SPAN;
                int y1 = (e.getY()-MARGIN+GRID_SPAN/2)/GRID_SPAN;

                //游戏已经结束,不能下
                //落在棋盘外,不能下
                //x,y位置已经有旗子存在,不能下
                if(x1<0||x1>ROWS||y1<0||y1>COLS||gameover||findChess(x1,y1))
                    setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
                else setCursor(new Cursor(Cursor.HAND_CURSOR));
            }
        });
    }


    public void paintComponent(Graphics g){
        //画棋盘
        super.paintComponent(g);

        //画横线
        for(int i = 0;i<=ROWS;i++){
            g.drawLine(MARGIN, MARGIN+i*GRID_SPAN, MARGIN+COLS*GRID_SPAN, MARGIN+i*GRID_SPAN);
        }

        //画竖线
        for(int i = 0;i<=COLS;i++){
            g.drawLine(MARGIN+i*GRID_SPAN, MARGIN, MARGIN+i*GRID_SPAN, MARGIN+ROWS*GRID_SPAN);
        }

        //画旗子
        for(int i = 0;i//网格交叉点x的坐标
            int xPos = chessList[i].getX()*GRID_SPAN+MARGIN;

            //网格交叉点y的坐标
            int yPos = chessList[i].getY()*GRID_SPAN+MARGIN;

            //设置颜色
            g.setColor(chessList[i].getColor());

            //***这个函数不知道干什么的***
            g.fillOval(xPos-Point.DIAMETER/2, yPos-Point.DIAMETER/2, Point.DIAMETER, Point.DIAMETER);

            //标记最后一个旗子的红色矩形框
            //最后一个旗子
            if(i == chessCount - 1){
                g.setColor(Color.red);
                g.drawRect(xPos-Point.DIAMETER/2, yPos-Point.DIAMETER/2, Point.DIAMETER, Point.DIAMETER);
            }
        }
    }
    //鼠标在组件上按下时调用
    public void mousePressed(MouseEvent e){
        //游戏已经结束,不能下
        if(gameover)
            return;

        //
        String colorName = isBlack?"黑旗":"白旗";

        //将鼠标单击的位置转换成网格索引
        xIndex = (e.getX()-MARGIN+GRID_SPAN/2)/GRID_SPAN;
        yIndex = (e.getY()-MARGIN+GRID_SPAN/2)/GRID_SPAN;

        //落在棋盘外,不能下
        if(xIndex<0||xIndex>ROWS||yIndex<0||yIndex>COLS)
            return;

        //x,y位置已经有旗子存在,不能下
        if(findChess(xIndex,yIndex))
            return;

        Point ch = new Point(xIndex,yIndex,isBlack?Color.black:Color.white);
        chessList[chessCount++] = ch;

        //通知系统重新绘制
        repaint();

        //给出胜利信息,不能再继续下棋
        if(isWin()){
            String msg = String.format("恭喜,%s赢了!", colorName);
            JOptionPane.showMessageDialog(this, msg);
            gameover = true;
        }
        isBlack = !isBlack;
    }

    //覆盖MouseListener的方法
    //鼠标按键在组件上单击(按下并释放)时调用
    public void mouseClicked(MouseEvent e){

    }

    //鼠标进入到组件上时调用
    public void mouseEntered(MouseEvent e){

    }

    //鼠标离开组件时调用
    public void mouseExited(MouseEvent e){

    }

    //鼠标按钮在组件上释放时调用
    public void mouseReleased(MouseEvent e){

    }

    //在旗子数组中查找是否有索引为x,y的旗子存在
    private boolean findChess(int x,int y){
        for(Point c:chessList){
            if(c != null && c.getX() == x && c.getY() == y)
                return true;
        }
        return false;
    }

    //判断哪方赢
    private boolean isWin(){

        //连续旗子的个数
        int continueCount = 1;

        //横向向西查找
        for(int x = xIndex - 1;x >= 0; x--){
            Color c = isBlack?Color.black:Color.white;
            if(getChess(x,yIndex,c)!=null){
                continueCount++;
            }
            else{
                break;
            }
        }

        //横向向东查找
        for(int x = xIndex + 1;x <= ROWS;x++){
            Color c = isBlack?Color.black:Color.white;
            if(getChess(x,yIndex,c)!=null){
                continueCount++;
            }
            else{
                break;
            }
        }

        //判断记录数大于等于5,即表示此方获胜
        if(continueCount >= 5){
            return true;
        }
        else{
            continueCount = 1;
        }

        //继续另一种情况的搜索
        //纵向向上寻找
        for(int y = yIndex-1;y>=0;y--){
            Color c = isBlack?Color.black:Color.white;
            if(getChess(xIndex,y,c)!=null){
                continueCount++;
            }
            else{
                break;
            }
        }

        //纵向向下寻找
        for(int y = yIndex+1;y <= ROWS;y++){
            Color c = isBlack?Color.black:Color.white;
            if(getChess(xIndex,y,c)!=null){
                continueCount++;
            }
            else{
                break;
            }
        }

        if(continueCount >= 5){
            return true;
        }
        else{
            continueCount = 1;
        }

        //继续另一种情况的搜索:斜向
        //东北寻找
        for(int x = xIndex + 1,y = yIndex-1;y>=0&&x<=COLS;x++,y--){
            Color c = isBlack?Color.black:Color.white;
            if(getChess(x,y,c)!=null){
                continueCount++;
            }
            else{
                break;
            }
        }

        //西南寻找
        for(int x = xIndex -1,y = yIndex+1;y<=ROWS&&x>=0;x--,y++){
            Color c = isBlack?Color.black:Color.white;
            if(getChess(x,y,c)!=null){
                continueCount++;
            }
            else{
                break;
            }
        }

        //
        if(continueCount>=5){
            return true;
        }
        else{
            continueCount = 1;
        }

        //继续另一种情况的搜索:斜向
        //西北寻找
        for(int x = xIndex - 1, y= yIndex-1;y>=0&&x>=0;x--,y--){
            Color c = isBlack?Color.black:Color.white;
            if(getChess(x,y,c)!=null){
                continueCount++;
            }
            else{
                break;
            }
        }

        //东南寻找
        for(int x = xIndex + 1,y = yIndex+1;y<=ROWS&&x<=COLS;x++,y++){
            Color c = isBlack?Color.black:Color.white;
            if(getChess(x,y,c)!=null){
                continueCount++;
            }
            else{
                break;
            }
        }

        if(continueCount>=5){
            return true;
        }
        else{
            continueCount = 1;
        }
        return false;
    }

    //定义getChess
    private Point getChess(int xIndex,int yIndex,Color color){
        for(Point c:chessList){
            if(c != null && c.getX() == xIndex && c.getY() == yIndex && c.getColor() == color){
                return c;
            }
        }
        return null;
    }

    //清除旗子
    public void restartGame(){
        //清除旗子
        for(int i = 0;inull;
        }

        //恢复游戏相关的变量值
        isBlack = true;
        gameover = false;//游戏是否结束
        chessCount = 0;//当前棋盘的旗子个数
        repaint();
    }

    //悔棋
    public void goback(){
        if(chessCount == 0){
            return;
        }

        chessList[chessCount - 1] = null;
        chessCount--;
        if(chessCount >0){
            xIndex = chessList[chessCount - 1].getX();
            yIndex = chessList[chessCount - 1].getY();
        }
        isBlack = !isBlack;
        repaint();
    }

    //矩形
    public Dimension getPreferredSize(){
        return new Dimension(MARGIN*2+GRID_SPAN*COLS,MARGIN*2+GRID_SPAN*ROWS);
    }
}

Java单机版五子棋_第1张图片

总结:这是一个比较简单的小设计,但是很值得初学者,代码量不多,大概只有500行左右的代码,而且能加深对面向对象编程的了解。

你可能感兴趣的:(Java项目)