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

时间:2022-01-13 15:48:34

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

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);
}
}

}

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