五子棋———完美注释版,免费分享!!!

这是一个基于穷举算法的五子棋。人机大战时,计算机的算法是扫描穷举法。下面是核心类的代码。

import javax.swing.JOptionPane;
import javax.swing.JPanel;

//五子棋游戏的核心类
public class GoGame {
    // 棋盘的高度,宽度。chessModel代表棋盘的种类1为20*15,2为30*20,3为40*30
    private int height, width, chessModel;
    // 棋盘的横纵坐标,用于获取点击坐标的,初始化的值为零。
    private int x = 0, y = 0;
    // 棋盘对应的颜色,取1,2,3,-5。
    // 1代表棋盘格上为黑子,2代表棋盘格上位白子,3代表棋盘格上没有棋子,-5代表棋盘格上不能下子//包括了边
    private int[][] chessMapShow;
    // isOdd交换棋手的标志,true是黑子(玩家)下,false是白子下,但是下完子之后,isodd马上会变成对方的标志。
    // isExist某棋盘格子上是否有棋子的标识true代表有棋子。
    private boolean isOdd, isExist;

    // 无参数的构造方法
    public GoGame() {
    }

    // 有参数的构造方法,初始化棋盘的数组,调用初始化棋盘的方法。
    public GoGame(int chessModel) {
        this.isOdd = true;
        if (chessModel == 1) {
            PanelInit(20, 15, chessModel);
        }
        if (chessModel == 2) {
            PanelInit(30, 20, chessModel);
        }
        if (chessModel == 3) {
            PanelInit(40, 30, chessModel);
        }
    }

    // 构造好棋盘的布局,只有本类能够调用,因为只有在构造初始化的时候调用,外部类不需要调用
    private void PanelInit(int width, int height, int chessModel) {
        this.width = width;
        this.height = height;
        this.chessModel = chessModel;
        this.chessMapShow = new int[width + 1][height + 1];
        // 行数代表高度,列数代表宽度
        for (int i = 0; i <= width; i++) {
            for (int j = 0; j <= height; j++) {
                chessMapShow[i][j] = -5;// 首先是不能下棋的
            }
        }
    }

    // 获取是否交换棋手的标识
    public boolean getIsOdd() {
        return this.isOdd;
    }

    // 设置交换棋手的标志。
    public void setIsOdd(boolean isOdd) {
        if (isOdd) {
            this.isOdd = true;
        }else {
            this.isOdd =false;      }

    }

    // 获取该棋盘某一格子上是否有棋子的标识
    public boolean getIsExist() {
        return this.isExist;
    }

    // 获取棋盘高度
    public int getHeight() {
        return this.height;

    }

    // 获取棋盘宽度
    public int getWidth() {
        return this.width;
    }

    // 获取棋盘的种类
    public int getChessModel() {
        return this.chessModel;
    }

    // 获取棋盘的地图上的棋格子的信息。
    public int[][] getChessMapShow() {
        return this.chessMapShow;
    }

    // 判断是下子是否横向越界,或纵向越界。
    public boolean overMap(int y, int x) {
        // 横向越界
        if (x >= width + 20 || x < 0)
            return true;
        // 纵向越界
        return y >= height + 20 || y < 0;
    }

    // 判断是格子上是否有棋子了
    public boolean chessExist(int i, int j) {
        // 如果数组上已经有黑子和白子,就返回true
        if (chessMapShow[i][j] == 1 || chessMapShow[i][j] == 2) {
            return true;
        }
        return false;
    }

    // 准备下棋,把坐标xy的棋格上变成可以下棋的数字标志。
    public void readyUp(int x, int y) {
        // 如果坐标xy越界了棋盘数组,就退出方法。
        if (overMap(x, y)) {
            return;
        }
        // 如果坐标xy上已经有棋子了,就退出方法。
        if (chessExist(x, y)) {
            this.isExist = true;
            return;
        }
        // 如果不存在棋子要没有越界,就把这个坐标的棋格上改为可以下棋
        chessMapShow[x][y] = 3;
    }

    // 在某一位置上下棋
    public void upChess(int x, int y) {
        // 如果越界了,退出方法。
        if (overMap(x, y)) {
            return;
        }
        // 如果存在棋子了,设置isExist标志成为true
        if (chessExist(x, y)) {
            this.isExist = true;
            return;
        } else {
            this.isExist = false;
            if (getIsOdd()) {
                // isOdd如果是true就下的是黑子,是false就下的是白子。
                // 总是要把交换标识isOdd变成对方执手,让对方下棋。
                setIsOdd(false);
                this.chessMapShow[x][y] = 1;
            } else {
                setIsOdd(true);
                this.chessMapShow[x][y] = 2;
            }
        }
    }

    // 记录电脑下子横向坐标
    public void setX(int x) {
        this.x = x;
    }

    // 记录电脑下子的纵向坐标
    public void setY(int y) {
        this.y = y;
    }

    // 获取电脑下子的横向坐标
    public int getX() {
        return this.x;
    }

    // 获取电脑下子的纵向坐标
    public int getY() {
        return this.y;
    }

    // 计算某一格子上的四个直线方向的棋子的最大值
    // 左,右直线方向。
    // 上下直线方向。
    // 左上,右下直线方向。
    // 右上,左下直线方向。
    // black_or_write是传进的数值,1位黑,2为白。
    public int checkMax(int x, int y, int black_or_write) {
        // num是计棋子数。max_num是自大棋子数,最终的返回值。max_temp是临时的用来 记录临时的最大的棋子数。
        int num = 0, max_num, max_temp = 0;
        // 为了不破坏传进来的xy值,用来存储此刻棋子格子的坐标
        int x_temp = x, y_temp = y;
        // 指针,二维指向坐标xy为中心的八个方向,四条直线。
        int x_temp1 = x_temp, y_temp1 = y_temp;
        // 判断右边,接着就是判断右边。每次相对传入xy坐标循环四次。
        for (int i = 1; i < 5; i++) {
            x_temp1 += 1;
            if (x_temp1 > this.width) {
                break;
            }
            if (chessMapShow[x_temp1][y_temp1] == black_or_write) {
                num++;
            } else {
                break;
            }
        }
        // 判断左边,指针退指向原来的xy坐标位置
        x_temp1 = x_temp;
        for (int i = 1; i < 5; i++) {
            x_temp1 -= 1;
            if (x_temp1 < 0) {
                break;
            }
            if (chessMapShow[x_temp1][y_temp1] == black_or_write) {
                num++;
            } else {
                break;
            }
        }
        if (num < 5) {
            max_temp = num;
        }
        // 判断上边,同样要先复原指针恢复为xy的坐标位置
        x_temp1 = x_temp;
        y_temp1 = y_temp;
        num = 0;
        for (int i = 1; i < 5; i++) {
            y_temp1 -= 1;
            if (y_temp1 < 0) {
                break;
            }
            if (chessMapShow[x_temp1][y_temp1] == black_or_write) {
                num++;
            } else {
                break;
            }
        }
        // 判断下边
        y_temp1 = y_temp;
        num = 0;
        for (int i = 1; i < 5; i++) {
            y_temp1 += 1;
            if (y_temp1 > this.height) {
                break;
            }
            if (chessMapShow[x_temp1][y_temp1] == black_or_write) {
                num++;
            } else {
                break;
            }
        }
        // 如果num大于上一次记录最大量。就把num的值传入max_num.
        if (num > max_temp && num < 5) {
            max_temp = num;
        }
        // 判断左上
        x_temp1 = x_temp;
        y_temp1 = y_temp;
        num = 0;
        for (int i = 1; i < 5; i++) {
            x_temp1 -= 1;
            y_temp1 -= 1;
            if (y_temp1 < 0 || x_temp1 < 0) {
                break;
            }
            if (chessMapShow[x_temp1][y_temp1] == black_or_write) {
                num++;
            } else {
                break;
            }
        }
        // 判断右下
        x_temp1 = x_temp;
        y_temp1 = y_temp;
        for (int i = 1; i < 5; i++) {
            x_temp1 += 1;
            y_temp1 += 1;
            if (y_temp1 > this.height || x_temp1 > this.width) {
                break;
            }
            if (chessMapShow[x_temp1][y_temp1] == black_or_write) {
                num++;
            } else {
                break;
            }
        }
        if (num > max_temp && num < 5) {
            max_temp = num;
        }
        // 判断右上
        x_temp1 = x_temp;
        y_temp1 = y_temp;
        num = 0;
        for (int i = 1; i < 5; i++) {
            x_temp1 += 1;
            y_temp1 -= 1;
            if (y_temp1 < 0 || x_temp1 > this.width) {
                break;
            }
            if (chessMapShow[x_temp1][y_temp1] == black_or_write) {
                num++;
            } else {
                break;
            }
        }
        // 判断左下
        x_temp1 = x_temp;
        y_temp1 = y_temp;
        num = 0;
        for (int i = 1; i < 5; i++) {
            x_temp1 -= 1;
            y_temp1 += 1;
            if (y_temp1 > this.height || x_temp1 < 0) {
                break;
            }
            if (chessMapShow[x_temp1][y_temp1] == black_or_write) {
                num++;
            } else {
                break;
            }
        }
        if (num > max_temp && num < 5) {
            max_temp = num;
        }
        max_num = max_temp;
        return max_num;
    }

    // 判断输赢,计算机和玩家下完棋之后都要调用的方法。
    public boolean judgeSuccess(int x, int y, boolean isOdd) {
        // 表示棋子在xy上有一颗棋子。
        int num = 1;
        int arrvalue;//是谁下的子。1为黑子,2为白子。
        int x_temp = x, y_temp = y;
        if (isOdd) {
            arrvalue = 2;
        } else {
            arrvalue = 1;
        }
        //设置横纵的两个指针。
        int x_temp1 = x_temp, y_temp1 = y_temp;
        // 判断右边
        for (int i = 1; i < 6; i++) {
            x_temp1 += 1;
            if (x_temp1 > width) {
                break;
            }
            if (this.chessMapShow[x_temp1][y_temp1] == arrvalue) {
                num++;
            } else {
                break;
            }
        }
        // 判断左边
        x_temp1 = x_temp;
        for (int i = 1; i < 6; i++) {
            x_temp1 -= 1;
            if (x_temp1 < 0) {
                break;
            }
            if (this.chessMapShow[x_temp1][y_temp1] == arrvalue) {
                num++;
            } else {
                break;
            }
        }
        if (num == 5) {
            return true;
        }
        // 判断上面
        x_temp1 = x_temp;
        y_temp1 = y_temp;
        num = 1;
        for (int i = 1; i < 6; i++) {
            y_temp1 -= 1;
            if (y_temp1 < 0) {
                break;
            }
            if (this.chessMapShow[x_temp1][y_temp1] == arrvalue) {
                num++;
            } else {
                break;
            }
        }
        // 判断下面
        y_temp1 = y_temp;
        for (int i = 1; i < 6; i++) {
            y_temp1 += 1;
            if (y_temp1 > this.height) {
                break;
            }
            if (this.chessMapShow[x_temp1][y_temp1] == arrvalue) {
                num++;
            } else {
                break;
            }
        }
        if (num == 5) {
            return true;
        }
        // 判断左上
        x_temp1 = x_temp;
        y_temp1 = y_temp;
        num = 1;
        for (int i = 1; i < 6; i++) {
            x_temp1 -= 1;
            y_temp1 -= 1;

            if (y_temp1 < 0 || x_temp1 < 0) {
                break;
            }
            if (this.chessMapShow[x_temp1][y_temp1] == arrvalue) {
                num++;
            } else {
                break;
            }
        }
        // 判断右下
        x_temp1 = x_temp;
        y_temp1 = y_temp;
        for (int i = 1; i < 6; i++) {
            y_temp1 += 1;
            x_temp1 += 1;
            if (y_temp1 > this.height || x_temp1 > this.width) {
                break;
            }
            if (this.chessMapShow[x_temp1][y_temp1] == arrvalue) {
                num++;
            } else {
                break;
            }
        }
        if (num == 5) {
            return true;
        }
        // 判断右上
        x_temp1 = x_temp;
        y_temp1 = y_temp;
        num = 1;
        for (int i = 1; i < 6; i++) {
            x_temp1 += 1;
            y_temp1 -= 1;

            if (y_temp1 < 0 || x_temp1 > this.width) {
                break;
            }
            if (this.chessMapShow[x_temp1][y_temp1] == arrvalue) {
                num++;
            } else {
                break;
            }
        }
        // 判断左下
        x_temp1 = x_temp;
        y_temp1 = y_temp;
        for (int i = 1; i < 6; i++) {
            y_temp1 += 1;
            x_temp1 -= 1;
            if (y_temp1 > this.height || x_temp1 < 0) {
                break;
            }
            if (this.chessMapShow[x_temp1][y_temp1] == arrvalue) {
                num++;
            } else {
                break;
            }
        }
        if (num == 5) {
            return true;
        }
        return false;
    }

    // 显示赢了之后的界面
    public void showSuccess(JPanel jp) {
        JOptionPane.showMessageDialog(jp, "你赢了,你好厉害", "win", JOptionPane.INFORMATION_MESSAGE);
    }

    // 显示输了之后的界面
    public void showDefeat(JPanel jp) {
        JOptionPane.showMessageDialog(jp, "你输了,好遗憾", "you lose", JOptionPane.INFORMATION_MESSAGE);
    }

    // 计算机走棋,使用穷举法计算每一个做标点的上下左右四个方向的最大棋子数,最后得出棋子数最大值的坐标,下子
    public void computerUpchess(int width, int height) {
        int max_black, max_write, max_temp, max = 0;
        setIsOdd(true);// 先交换棋手,不然永远都是计算机下棋了,永远都是白子。true黑子才是黑子,是玩家下棋。
        System.out.println("计算机走棋。。。。");
        for (int i = 0; i <= this.width; i++) {
            for (int j = 0; j <= this.height; j++) {
                // 双重循环的中,如这一点上子多,就堵住
                if (!chessExist(i, j)&&!overMap(i, j)) {// 判断是否下棋
                    max_write = checkMax(i, j, 2);// 判断白子的最大值
                    max_black = checkMax(i, j, 1);
                    //把白子和黑子的最大值付给max_temp变量。
                    max_temp = Math.max(max_write, max_black);
                    if (max_temp > max) {
                        //把最佳下子位置记录下来。
                        max = max_temp;
                        this.x = i;
                        this.y = j;
                    }
                }
            }
        }
        //下完棋一定要设置自己下棋的位置,为了计算机下棋之后判断输赢用。
        //计算机下完棋之后,调用getX和getY来判断计算机输赢。
        setX(this.x);
        setY(this.y);
        //下白子。
        chessMapShow[this.x][this.y] = 2;
    }

}

下面是为了界面化面板类的代码:实现了点击下棋和画出棋盘和棋子。

import java.awt.Color;
import java.awt.Graphics;
import java.awt.color.CMMException;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

import javax.swing.JOptionPane;
import javax.swing.JPanel;

/**
 * @author 王爷 此类主要是完成如下的功能 1.构建一个面板,并在面板上画棋盘。 2.处理该面板上的事件
 */
public class ChessPanel extends JPanel implements MouseListener, MouseMotionListener {

    // 棋盘的高度和宽度
    private int width, height;
    // 为了从核心类获取棋盘的信息来画数组,这里设置一个引用。在构造方法里传入对象。
    private GoGame goGame;

    // 构造方法,传入核心对象,并从核心对象获取高度和宽度的属性。
    public ChessPanel(GoGame goGame) {
        this.goGame = goGame;
        this.width = goGame.getWidth();
        this.height = goGame.getHeight();
        addMouseListener(this);// 为整个花瓣添加点击事件。
    }

    // 设置gogame的高度和宽度
    public void setGoGame(GoGame goGame) {
        this.goGame = goGame;
        width = goGame.getWidth();
        height = goGame.getHeight();
    }

    // 根据坐标计算出棋盘每一个棋格的信息(如是黑子还是白子)
    // 然后调用draw方法上画出棋子。draw之后自己定义。
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        // 画出出边界之外 的棋盘。遍历数组时一定要从0开始便利,
        //不然计算机下棋不会显示,自己下棋也不能下在第一列和第一行!!!我调试过很久才调出来。
        //忘要参考的读者莫要饭错误
        for (int i = 0; i <= this.width; i++) {
            for (int j = 0; j <= this.height; j++) {
                int v = goGame.getChessMapShow()[i][j];
                // i是横坐标,j是纵坐标。
                draw(g, i, j, v);
            }
        }
    }

    // 根据提供的xy坐标画出棋子和棋盘。
    private void draw(Graphics g, int i, int j, int v) {
        //背景随便什么颜色都行,如果用常量值不爽,可以自己实例化一个Color对象出来,然后传入rgb数值。
        setBackground(Color.CYAN);
        // 这样画的棋盘就不会从面板边缘开始。
        int x = 20 * i + 20;
        int y = 20 * j + 20;
        // 先把画布都画成白色的矩形框。
        if (i != width && j != height) {
            g.setColor(Color.white);
            g.fillRect(x, y, 20, 20);
            g.setColor(Color.BLACK);
            g.drawRect(x, y, 20, 20);
        }
        // 画黑子
        if (v == 1) {
            g.setColor(Color.black);
            g.fillOval(x - 8, y - 8, 16, 16);
            g.setColor(Color.gray);
            // 绘制椭圆,分别根据左上角的横纵坐标,椭圆的高度和宽度椭圆
            g.drawOval(x - 8, y - 8, 16, 16);
        }
        // 画白子
        if (v == 2) {
            g.setColor(Color.white);
            g.fillOval(x - 8, y - 8, 16, 16);
            g.setColor(Color.gray);
            g.drawOval(x - 8, y - 8, 16, 16);
        }
        if (v == 3) {
            // 设置为青色
            g.setColor(Color.cyan);
            g.drawOval(x - 8, y - 8, 16, 16);
        }
    }

    // 棋盘画布的点击事件
    @Override
    public void mousePressed(MouseEvent e) {
        // 获取鼠标点击的坐标xy
        // 因为在ChessBoard类中的MapSize()方法中,高度和宽度是width*20+50和height*20+100,所以坐标要除以20
        // 而在画棋子的时候,我们为了让边缘不是在窗口的界面边缘,我们加上了一个矩形的宽度,所以下棋时要减去半个矩形的宽度。
        int x = (e.getX() - 10) / 20;
        int y = (e.getY() - 10) / 20;
        System.out.println("横坐标:" + x + "纵坐标:" + y);
        // 如果获取的是鼠标的事件的掩码。则下棋
        if (e.getModifiers() == MouseEvent.BUTTON1_MASK) {
            goGame.upChess(x, y);
        }
        System.out.println(goGame.getIsOdd() + "" + goGame.getChessMapShow()[x][y]);
        repaint();
        // 下完棋之后我,我们根据这个坐标来判断玩家的输赢
        // 用户判断输赢时是根据鼠标获取的位置对映的数组坐标来判断的。
        if (goGame.judgeSuccess(x, y, goGame.getIsOdd())) {
            goGame.showSuccess(this);
            // 不能让鼠标继续下棋了。鼠标点击面板没有用了。所以销毁传入的鼠标对象
            e.consume();
            // 把状态量改为false,表示不是计算机下棋。
            ChessBoard.isComputer = false;
        }
        // 判断是否为人机对弈,如果是人机对弈而且棋子不存在。,就计算机下棋
        if (ChessBoard.isComputer && !goGame.getIsExist()) {
            goGame.computerUpchess(goGame.getWidth(), goGame.getHeight());
            repaint();
            // 计算机下棋,他会记录自己下的坐标,所以在判断输赢时,要用getX和getY方法判断。
            System.out.println(goGame.getIsOdd());
            System.out.println(goGame.getX()+" "+goGame.getY());
            if (goGame.judgeSuccess(goGame.getX(), goGame.getY(), goGame.getIsOdd())) {
                goGame.showDefeat(this);
                // 计算机赢了也不能下棋了。所以销毁传入的鼠标对象
                e.consume();
            }
        }
    }

    // 鼠标拖动事件
    @Override
    public void mouseMoved(MouseEvent e) {
        int x = (e.getX() - 10) / 20;
        int y = (e.getY() - 10) / 20;
        // 鼠标移动到哪一点,数组就会响应的变为可以下棋状态。
        goGame.readyUp(x, y);
        repaint();
    }

    // 显示赢了之后的界面
    public void showSuccess(JPanel jp) {
        JOptionPane.showMessageDialog(jp, "你赢了,你好厉害", "win", JOptionPane.INFORMATION_MESSAGE);
    }

    // 显示输了之后的界面
    public void showDefeat(JPanel jp) {
        JOptionPane.showMessageDialog(jp, "你输了,好遗憾", "you lose", JOptionPane.INFORMATION_MESSAGE);
    }

    @Override
    public void mouseDragged(MouseEvent e) {
    }

    @Override
    public void mouseClicked(MouseEvent e) {
    }

    @Override
    public void mouseEntered(MouseEvent e) {
    }

    @Override
    public void mouseExited(MouseEvent e) {
    }

    @Override
    public void mouseReleased(MouseEvent e) {
    }

}

下面是窗口类。用于实现窗口话和点击菜单会激发不同的事件。如:关闭窗口时系统也退出。游戏棋盘的选择,游戏模式的选择。游戏窗口视图的选择。

import java.awt.Container;
import java.awt.Graphics;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JRadioButton;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

//这个类主要是加载五子棋的整个窗口以及菜单
public class ChessBoard extends JFrame implements ActionListener {

    // 可选的棋盘大小
    private String[] strSize = { "20*15", "30*20", "40*30" };
    // 可选的对战模式
    private String[] strModel = { "人机对战", "人人对战" };
    // 用连个boolean 来判断是人机还是人人,isComputer和checkcomputer为true是为了默认开局方式为人机。
    public static boolean isComputer = true, checkComputer = true;
    // 窗口的宽和高
    private int height, width;
    // 核心类对象
    private GoGame goGame;
    // 棋盘对象
    private ChessPanel chessPanel;

    // 构造五子棋的窗体
    public ChessBoard() {
        this.setTitle("五子棋---个人制作");
        // 初始化核心类的对对象。
        goGame = new GoGame(1);
        // 使用核心类,初始化面板对象。
        chessPanel = new ChessPanel(goGame);
        // 获取本窗口的容器。
        Container con = this.getContentPane();
        // 容器里加入面板,并设置布局为中心。
        con.add(chessPanel, "Center");
        //把窗口设置为大小不可调整。
        this.setResizable(false);
        //添加一个窗口监听事件,主要是实现按关闭按钮能够关闭系统,退出虚拟机。为了精简代码,这里使用了匿名内部类。
        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        // 先使用类内部的设置窗口的方法来初始化窗口大小
        this.MapSize(20, 15);
        // 创建窗口的菜单条,一方便
        JMenuBar mbar = new JMenuBar();
        this.setJMenuBar(mbar);
        // 创建游戏菜单
        JMenu gameMenu = new JMenu("游戏");
        // 将菜单加入到菜单条,自己创建一个方法反回一个已经构造好的菜单。加在菜单条上。
        mbar.add(makeMenu(gameMenu, new Object[] {
                "开局", "棋盘", "模式", null, "退出" }, this));
        // 创建视图菜单
        JMenu lookMenu = new JMenu("视图");
        // 将菜单添加到菜单条
        mbar.add(makeMenu(lookMenu, new Object[] {
                "Metal", "Motif", "Windows" }, this));
        // 创建帮助菜单
        JMenu helpMenu = new JMenu("帮助");
        // 将菜单添加到菜单条
        mbar.add(makeMenu(helpMenu, new Object[] {
                "关于" }, this));

    }

    // 获取人机iscompputer
    public boolean getIsComputer() {
        return this.isComputer;
    }

    // 构造五子棋的主菜单,第一步是要创建一个菜单的引用,以便之后创建菜单实例返回。
    public JMenu makeMenu(Object parent, Object items[], Object target) {
        //创建一个菜单引用。
        JMenu m = null;
        //如果传入的本来就是菜单,则直接强制转换。如果是字符串,则使用字符创建菜单。
        if (parent instanceof JMenu) {
            m = (JMenu) parent;
        } else if (parent instanceof String) {
            m = new JMenu((String) parent);
        } else {
            return null;
        }
        //下面是为菜单构建菜单项。还是使用方法返回。
        for (int i = 0; i < items.length; i++) {
            if (items[i] == null) {
                m.addSeparator();
            } else if (items[i] == "棋盘") {
                JMenu jm = new JMenu("棋盘");
                ButtonGroup group = new ButtonGroup();
                JRadioButtonMenuItem rmenu;
                for (int j = 0; j < strSize.length; j++) {
                    rmenu = makeRadioButtonMenuItem(strSize[j], target);
                    if (j == 0) {
                        rmenu.setSelected(true);
                    }
                    //先把多按钮加入到菜单中,再把多按钮加入到按钮组里,这样才能实现单选。
                    jm.add(rmenu);
                    group.add(rmenu);
                }
                m.add(jm);
            } else if (items[i] == "模式") {
                JMenu jm = new JMenu("模式");
                ButtonGroup group = new ButtonGroup();
                JRadioButtonMenuItem rmenu;
                for (int h = 0; h < strModel.length; h++) {
                    rmenu = makeRadioButtonMenuItem(strModel[h], target);
                    if (h == 0) {
                        rmenu.setSelected(true);
                    }
                    jm.add(rmenu);
                    group.add(rmenu);
                }
                //记住,一定要是加入菜单条里的菜单
                m.add(jm);
            } else {
                //如果菜单项没有在包含多选项,则用方法直接构造一个菜单项返回并添加到菜单里。
                m.add(makeMenuItem(items[i], target));
            }
        }
        return m;
    }

    // 构造五子棋的菜单项,构造方法和上面构造菜单的不部分类似。不过 得添加监听事件
    private JMenuItem makeMenuItem(Object item, Object target) {
        JMenuItem menuItem = null;
        if (item instanceof String) {
            menuItem = new JMenuItem((String) item);
        } else if (item instanceof JMenuItem) {
            menuItem = (JMenuItem) item;
        } else {
            return null;
        }
        if (target instanceof ActionListener) {
            menuItem.addActionListener((ActionListener) target);
        }
        return menuItem;
    }

    // 构造五子棋的单选按钮式菜单项,和上面的方法非常类似。不再赘述。
    private JRadioButtonMenuItem makeRadioButtonMenuItem(Object item, Object target) {
        JRadioButtonMenuItem jRadioButtonMenuItem = null;
        if (item instanceof String) {
            jRadioButtonMenuItem = new JRadioButtonMenuItem((String) item);
        } else if (item instanceof JRadioButtonMenuItem) {
            jRadioButtonMenuItem = (JRadioButtonMenuItem) item;
        } else {
            return null;
        }
        if (target instanceof ActionListener) {
            jRadioButtonMenuItem.addActionListener((ActionListener) target);
        }
        return jRadioButtonMenuItem;
    }

    // 设置界面大小
    public void MapSize(int w, int h) {
        //这里设置的宽度和高度,和鼠标点击时获取坐标值有很大的关联。
        setSize(w * 20 + 50, h * 20 + 100);
        if (this.checkComputer) {
            this.isComputer = true;
        } else {
            this.isComputer = false;
        }
        chessPanel.setGoGame(goGame);
        chessPanel.repaint();
    }

    // 重新开始
    public void restart() {
        int modelChess = goGame.getChessModel();
        if (modelChess <= 3 && modelChess >= 1) {
            goGame = new GoGame(modelChess);
            MapSize(goGame.getWidth(), goGame.getHeight());
        } else {
            System.out.println("\u81EA\u5B9A\u4E49");
        }
    }

    @Override
    // 实现ActionListenner的主要方法。
    public void actionPerformed(ActionEvent e) {
        String arg = e.getActionCommand();
        try {
            if (arg.equals("Windows")) {
                UIManager.setLookAndFeel(
                        "com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
            } else if (arg.equals("Motif")) {
                UIManager.setLookAndFeel(
                        "com.sun.java.swing.plaf.motif.MotifLookAndFeel");
            } else {
                UIManager.setLookAndFeel(
                        "javax.swing.plaf.metal.MetalLookAndFeel");
            }
            SwingUtilities.updateComponentTreeUI(this);
        } catch (Exception e2) {
        }
        if (arg.equals("20*15")) {
            this.width = 20;
            this.height = 15;
            goGame = new GoGame(1);
            MapSize(this.width, this.height);
            SwingUtilities.updateComponentTreeUI(this);

        }
        if (arg.equals("30*20")) {
            this.width = 30;
            this.height = 20;
            goGame = new GoGame(2);
            MapSize(this.width, this.height);
            SwingUtilities.updateComponentTreeUI(this);

        }
        if (arg.equals("40*30")) {
            this.width = 40;
            this.height = 30;
            goGame = new GoGame(3);
            MapSize(this.width, this.height);
            SwingUtilities.updateComponentTreeUI(this);

        }
        if (arg.equals("人机对弈")) {
            this.checkComputer = true;
            this.isComputer = true;
            goGame = new GoGame(goGame.getChessModel());
            MapSize(goGame.getWidth(),goGame.getHeight());
            SwingUtilities.updateComponentTreeUI(this);
        }
        if (arg.equals("人人对弈")) {
            this.checkComputer = true;
            this.isComputer = true;
            goGame = new GoGame(goGame.getChessModel());
            MapSize(goGame.getWidth(),goGame.getHeight());
            SwingUtilities.updateComponentTreeUI(this);
        }
        if (arg.equals("开局")) {
            restart();
        }
        if (arg.equals("关于")){

            JOptionPane.showMessageDialog(this, "五子棋游戏测试版本", "关于", 0);
        }
        if (arg.equals("退出")) {
            System.exit(0);
        }
    }

}

这里是为了练习项目。为大家提供的代码和注释,应该是一看就能看懂的,非常适合初学者。

时间: 2024-10-13 16:20:45

五子棋———完美注释版,免费分享!!!的相关文章

windows7旗舰版激活密钥永久版免费分享

windows7之家不仅提供精品Win7教程 给大家,加上这个windows7激活密匙还帮大家解决windows7系统激活问题,包括win7旗舰版 windows7安装版这些. 用的是Windows7 RTM旗舰版官方原版cn_windows_7_ultimate_x86_dvd_x15-65907,win7旗舰版原版系统下载:Windows7旗舰版官方原版下载 强烈推荐 安装好系统后右击计算机--属性--更改产品密匙 输入以下密匙; HT6VR-XMPDJ-2VBFV-R9PFY-3VP7R

2016最新马哥Linux就业班+架构师班视频教程全套含随堂笔记PPT 全套资料免费分享

有朋友咨询问我是不是做营销的? 不是,不是,不是!!! 这么认为的话,干嘛还来咨询呢? 直接发我个邮件,附上你手里的最新教程分享链接,我一定回复. 不相信,解释再多也没用... 本人是一名运维工程师,主要做Linux和数据库运维工作.非常喜欢收集.整理.分享一些质量优质的IT技术教程.马哥Linux在业界可谓是名气响当当的,很多做系统运维的朋友或是刚入行的菜鸟视之为Linux教育界的教父,都趋之若鹜. 本人也不例外,我就是在2013.2014年平靠学习马哥那个套经典的运维教程走上linux运维之

Java甘特图控件swing版免费下载地址 &nbsp; &nbsp; &nbsp;

FlexGantt 控件是现在Java 平台下最先进的甘特图解决方案,使用一个很高的抽象层次,能适用于多种不同的域,例如 ERP 系统.生产计划和日程安排.制造流程系统或项目公文管理程序等.这些使得 FlexGantt 能从其他有局限性的项目计划(资源.人.任务)甘特图库中脱颖而出. 具体功能: 原文来自http://www.51diaodu.com/pdt/2966 模型视图控制器:FlexGantt 遵从与 Swing 相同 MVC 方法.许多不同的模型用于各种各样的用途.一个日历模型跟踪假

超级邮件群发机12.32完美破解版---日轻松发万封邮件,方法对了每天发不了万封你骂我

前几天发了一个邮件群发工具,很多人回复,被推荐和置顶,感觉很开心,上回第二次发贴就有这么多的朋友支持我,有你们的支持是我奋斗的动力,今后将提供更多更优质的绝对给力小工具给大家,上回发了贴后很多人加我QQ问我怎么用,说真的那个软件非常简单,一看就会用,但有些朋友问我怎么发几封就发的出收不到了,这里我不再多讲,关键是你发的内容是否合法,再好的软件你拼命发重复的内容,肯定容易被和谐,软件显示发送成功,可能你收不到,这也正常,这需要你有更多的发件箱了.还有些人说软件不太强大,邮件内容只能写文字,没有高级

《pigcms v6.2最新完美至尊版无任何限制,小猪微信源码多用户微信营销服务平台系统》

<pigcms v6.2最新完美至尊版无任何限制,小猪微信源码多用户微信营销服务平台系统> 前两天分享了套小猪CMS(PigCms)多用户微信营销服务平台系统V6.1完美破解至尊版带微用户管理CRM+微信支付,还是不少童鞋反应出不少问题.今天再分享套小猪pigcms v6.2最新完美至尊版无任何限制,pigcms多用户微信营销服务平台系统,非常感谢我们网站一位童鞋提供了这套源码,现在源码我们正在检测中,主要检测源码的安全性或有没有木马后门什么的. 暂时放我们测试时候的几张截图出来 102套模板

考研数学基础教材免费分享

考研数学基础教材免费分享 整理了<概率论与数理统计(浙大四版)><同济高等数学(第七版)><同济线性代数(第六版)>三本书的教材和配套习题全解!资源链接:https://pan.baidu.com/s/1nicM7Pq9QguszuuMJCCOxA 原文地址:http://blog.51cto.com/14063572/2316052

Python Flask高级编程之RESTFul API前后端分离精讲 (网盘免费分享)

Python Flask高级编程之RESTFul API前后端分离精讲 (免费分享)  点击链接或搜索QQ号直接加群获取其它资料: 链接:https://pan.baidu.com/s/12eKrJKN-MzscalsJKRoL5w 提取码:88hj 免费分享,如若链接失效请加群 其它资源在群里,私聊管理员即可免费领取:群——517432778,点击加群,或扫描二维码 免费课程资料领取目录:  Python Flask构建微信小程序订餐系统 Python分布式爬虫必学框架Scrapy打造搜索引擎

微软发布Win10:技术预览版免费下载

微软今日如约放出了Windows 10技术预览版的下载,大家现在就可以免费下载Windows 10技术预览版ISO文件,安装并开启体验. Windows 10技术预览版首批提供了英语.简体中文.葡萄牙语,含32位.64位. Windows 10技术预览版简体中文版64位大小为3.96GB,32位大小为3.05GB. 产品密钥:NKJFK-GPHP7-G8C3J-P6JXR-HQRJR Windows 10技术预览版简体中文版官方下载: 64位:http://go.microsoft.com/fw

美国数学教父拒绝10亿美元 免费分享教学视频

美国39岁“数学教父” 拒绝10亿美元 免费分享教学视频 美国39岁的“数学教父”萨尔曼·汗放弃了1万亿美元的商业机会,拒绝风投机构的10亿美元投资,他唯一坚持的就是免费分享教学视频.他讲解数学通俗易懂,颠覆了美国教育,全美国有2万多所学校不需要数学老师讲课,只要看他的视频就行了. 帮侄女辅导无意中成为“数学教父” 萨尔曼是来自孟加拉国的移民,从小家里很穷,但他在数学方面颇有天赋,考上了美国麻省理工学院,四年读完了数学和计算机科学两个专业的课程. 萨尔曼有个小侄女叫纳迪亚,2004年时上七年级,