一个简单的五子棋程序,实现了人机对战、人人对战、悔棋、认输功能。
一、首先是制作界面,也就是下棋界面。要画一个棋盘,添加按钮实现各种功能。
(1)创建一个ChessTable类来存放棋盘的基础数据,比如横向线的条数、纵向线的条数、单元格的大小、棋子的直径等。定义一个类是为了更改棋盘基础数据的时候更加方便。
public interface ChessTable {
public int x0 = 50; //表格左上角起点的x值
public int y0 = 70; //表格左上角起点的y值
public int rows = 11; //横向线的条数
public int columns = 11; //纵向线的条数
public int chess_size = 30; //棋子的直径
public int size = 40; //单元格的大小
}
(2)接下来是下棋界面的设计,考虑到后面要实现悔棋和改变界面大小,就要用到重绘。所以在创建类的时候直接继承JFrame,然后在类里面重写paint()方法来实现重绘。
JPanel是一个容器组件,可以把按钮添加到JPanel中。然后指定JPanel存放的位置。
通过ImageIcon可以在界面中添加背景图片,增加观赏性。
public class Gobang extends JFrame {
public static void main(String[] args) {
Gobang gb = new Gobang();
gb.showJFrame();
}
//初始化窗体的方法
public void showJFrame() {
this.setTitle("五子棋");
this.setSize(650, 550);
this.setDefaultCloseOperation(3);
this.setLocationRelativeTo(null);
this.setResizable(false);//界面不可改变大小
this.setLayout(new BorderLayout());
//添加容器组件
JPanel jl = new JPanel();
jl.setPreferredSize(new Dimension(150,0));
jl.setBackground(Color.LIGHT_GRAY);
JButton start = new JButton("开始新游戏");
start.setPreferredSize(new Dimension(100,30));
jl.add(start);
JButton back = new JButton("悔棋");
back.setPreferredSize(new Dimension(80,30));
jl.add(back);
JButton giveup = new JButton("认输");
giveup.setPreferredSize(new Dimension(80,30));
jl.add(giveup);
String[] type = {
"人人对战","人机对战"};
JComboBox<String> box = new JComboBox<>(type);
box.setPreferredSize(new Dimension(90,30));
jl.add(box);
this.add(jl,BorderLayout.EAST);
this.setVisible(true);
}
//重写绘制界面的方法
public void paint(Graphics g) {
//在界面加上图片
ImageIcon image = new ImageIcon("C:\\Users\\某某某\\Desktop\\文档\\五子棋背景图\\1.jpg");
g.drawImage(image.getImage(),50,70,400,400,null);
}
//画棋盘
public void drawChessTable(Graphics g) {
//画横线
for(int i = 0;i < ChessTable.rows;i++) {
g.drawLine(ChessTable.x0, ChessTable.y0+i*ChessTable.size,
ChessTable.x0+(ChessTable.columns - 1)*ChessTable.size, ChessTable.y0+i*ChessTable.size);
}
//画竖线
for(int j = 0;j < ChessTable.rows;j++) {
g.drawLine(ChessTable.x0+j*ChessTable.size, ChessTable.y0,
ChessTable.x0+j*ChessTable.size, ChessTable.y0+(ChessTable.rows - 1)*ChessTable.size);
}
}
}
效果图如下:
(3)添加监听器,收集按钮上的信息。
收集按钮上的信息通过addActionListener()监听方法。
要实现下棋,就要获取点击位置的坐标,需要addMouseListener()监听方法。
添加监听方法就要有事件处理类,创建GobangListener类作为事件处理类。
继承MouseAdapter鼠标适配类,MouseAdapter类里继承了MouseListener, MouseWheelListener, MouseMotionListener。继承MouseAdapter是因为MouseAdapter只需要重写用到的方法,不需要重写所有的抽象方法。
同时,还要继承ActionListener。
//实例化事件处理类的对象,并把画笔、数组传递过去
GobangListener gl = new GobangListener(this,chesses);
//添加动作监听方法
start.addActionListener(gl);
back.addActionListener(gl);
giveup.addActionListener(gl);
box.addActionListener(gl);
public class GobangListener extends MouseAdapter implements ActionListener {
//重写抽象方法
}
(4)定义一个数组来存放棋子信息,当你在该位置下棋后,就不能再下棋了。
将窗体传递到GobangListener类,可以在窗体中获取画笔,也可以添加MouseListener监听方法。
public class Gobang extends JFrame {
//定义一个二维数组,用来标记棋盘上的位置
private int[][] chesses = new int[ChessTable.rows][ChessTable.columns];
}
public class GobangListener extends MouseAdapter implements ActionListener {
private Gobang ct;
private Graphics2D g;
private int[][] chesses;
// 构造方法
public GobangListener(Gobang G, int[][] chesses) {
this.ct = G;
this.chesses = chesses;
// 获取窗体上的画笔对象
g = (Graphics2D) this.ct.getGraphics();
//画笔防锯齿
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);// 设置画笔抗锯齿
}
}
(5)实现下棋、悔棋、和重绘。
用count来计数,判断轮到谁下棋。
通过chesses[i][j]来判断该位置是否能下棋。
悔棋要通过数组队列来实现,定义一个数组队列ArrayList。Point是一个类,可以直接用,可以获取x,y坐标值。
重绘则根据chesses数组中的信息再画一次。
调用判断输赢方法judge(),决出胜利后,移除MouseListener()不能再下棋。
//重写绘制窗体的方法
public void paint(Graphics g) {
super.paint(g);
ImageIcon image = new ImageIcon("C:\\Users\\庞志贤\\Desktop\\文档\\五子棋背景图\\1.jpg");
g.drawImage(image.getImage(),50,70,400,400,null);
drawChessTable(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);// 设置画笔抗锯齿
//按照数组中的信息进行重绘
for(int j = 0;j < ChessTable.rows;j++) {
for(int i = 0;i < ChessTable.columns;i++) {
int x = ChessTable.x0 + i*ChessTable.size;
int y = ChessTable.y0 + j*ChessTable.size;
if(chesses[i][j] == 1) {
g.setColor(Color.black);
g.fillOval(x - ChessTable.chess_size / 2, y - ChessTable.chess_size / 2,
ChessTable.chess_size, ChessTable.chess_size);
}else if(chesses[i][j] == -1) {
g.setColor(Color.WHITE);
g.fillOval(x - ChessTable.chess_size / 2, y - ChessTable.chess_size / 2,
ChessTable.chess_size, ChessTable.chess_size);
}
}
}
}
public class GobangListener extends MouseAdapter implements ActionListener {
private Gobang ct;
private Graphics2D g;
private int[][] chesses;
private int count;
private ArrayList<Point> list = new ArrayList<Point>();
public void mouseReleased(MouseEvent e) {
// 获取鼠标事件发生时光标的位置
int x1 = e.getX();
int y1 = e.getY();
for (int j = 0; j < ChessTable.rows; j++) {
for (int i = 0; i < ChessTable.columns; i++) {
int x = ChessTable.x0 + i * ChessTable.size;
int y = ChessTable.y0 + j * ChessTable.size;
if (x1 > x - ChessTable.size / 3 && x1 < x + ChessTable.size / 3 && y1 > y - ChessTable.size / 3
&& y1 < y + ChessTable.size / 3) {
// 如果选择的位置没有棋子
if (chesses[i][j] == 0) {
if (count == 0) {
// 如果是黑子就为1
chesses[i][j] = 1;
g.setColor(Color.black);
count++;
// 调用判断输赢的方法
if (judge(i, j)) {
System.out.println("执黑子胜利");
// 判断输赢后移除鼠标监听方法,不能再下棋子