第一部分:
第一个类:
package gobang227;//这是包名,copy的同学记得修改!!!!
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
//定义棋盘类让其继承面板类,原因为之后要重写棋盘面板类的paint方法,将棋盘面板重置
public class GoBangMain extends JPanel implements GoBangDate {
// 定义初始化界面函数
public void initUI() {
// 实例化界面对象jr,设置界面标题,大小,关闭,居中,改变大小选项不可选
JFrame jf = new JFrame();
jf.setTitle("五子棋对战");
jf.setSize(760, 630);
jf.setDefaultCloseOperation(3);
jf.setLocationRelativeTo(null);
jf.setResizable(false);
// 整体布局为边框布局,JFrame默认布局为边框布局
jf.setLayout(new BorderLayout());
// 添加棋盘面板,添加到边框布局的中部
jf.add(this, BorderLayout.CENTER);
this.setBackground(Color.gray);
// 功能面板,默认为流式布局
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(150, 0));
// 添加空白区域(美观的要求)
JLabel label = new JLabel();
label.setPreferredSize(new Dimension(140, 120));
panel.add(label);
// 添加功能面板
jf.add(panel, BorderLayout.EAST);
// 添加功能按钮
JButton bu1 = new JButton("开始新游戏");
JButton bu2 = new JButton("悔棋");
JButton bu3 = new JButton("认输");
bu1.setPreferredSize(new Dimension(140, 60));
bu2.setPreferredSize(new Dimension(140, 60));
bu3.setPreferredSize(new Dimension(140, 60));
panel.add(bu1);
panel.add(bu2);
panel.add(bu3);
JRadioButton jr1 = new JRadioButton("人人对战");
JRadioButton jr2 = new JRadioButton("人机对战");
jr1.setPreferredSize(new Dimension(80, 40));
jr2.setPreferredSize(new Dimension(80, 40));
// 将jr1和jr2分组,保证每次只能选中一个按钮
ButtonGroup bg = new ButtonGroup();
bg.add(jr1);
bg.add(jr2);
// 默认选中为jr1按钮,即人人对战
jr1.setSelected(true);
// 把两个按钮添加到功能面板上
panel.add(jr1);
panel.add(jr2);
// 复选框
JCheckBox jc = new JCheckBox("AI先手");
jc.setPreferredSize(new Dimension(80, 40));
panel.add(jc);
// 可见
jf.setVisible(true);
// 实例化画笔对象
Graphics g = this.getGraphics();
// 实例化监听接口,并传参,参数为画笔对象
GoBangListener gl = new GoBangListener(g);
// 给棋盘面板添加监听方法,监听处理类的对象为gl
this.addMouseListener(gl);
}
@Override
public void paint(Graphics g) {
super.paint(g);
// 调用棋盘面板初始化的方法,使棋盘面板初始化
drawChessBorder(g);
}
// 定义棋盘面板初始化的方法
private void drawChessBorder(Graphics g) {
for (int i = 0; i < ROW; i++)
g.drawLine(X, Y + i * SIZE, X + (COLUMN - 1) * SIZE, Y + i * SIZE);
for (int i = 0; i < COLUMN; i++)
g.drawLine(X + i * SIZE, Y, X + i * SIZE, Y + (ROW - 1) * SIZE);
}
public static void main(String[] args) {
// 实例化棋盘类对象,调用初始化函数
GoBangMain go = new GoBangMain();
go.initUI();
}
}
第二个类:
package gobang227;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class GoBangListener implements MouseListener, GoBangDate {
private Graphics g;
// x,y为坐标值,row,col为棋子的行和列(例如:左上角行列数为1,1)
private int x, y, row, col;
// 棋子颜色的标志位,1为黑棋,2为白棋
private int flag = 1;
// 构造方法
public GoBangListener(Graphics g) {
this.g = g;
}
@Override
public void mouseClicked(MouseEvent e) {
// 获取点击位置的横纵坐标
x = e.getX();
y = e.getY();
// 计算点击位置的行和列,确认棋子把棋子放在相应交叉点
//在这里注意为什么要减去CHESSSIZE / 2,因为画棋子的时候或者说画椭圆的时候调用 fillOval(x, y, CHESSSIZE, CHESSSIZE)方法,但是在这里参数x,y是以椭圆大小为边框的矩形的左上角,不是大家想象中的圆心!!!!!!
row = Math.round(y / SIZE);
System.out.println("这个棋子在第" + row + "行!");
y = Y - CHESSSIZE / 2 + (row - 1) * SIZE;
col = Math.round(x / SIZE);
System.out.println("这个棋子在第" + col + "列!");
x = X - CHESSSIZE / 2 + (col - 1) * SIZE;
// 确保点击位置在棋盘上
if (row <= ROW && col <= COLUMN) {
// flag=1说明下个棋子是黑棋
if (flag == 1) {
g.setColor(Color.black);
g.fillOval(x, y, CHESSSIZE, CHESSSIZE);
// 把下个棋子的颜色置为白棋
flag = 2;
} else {
g.setColor(Color.white);
g.fillOval(x, y, CHESSSIZE, CHESSSIZE);
flag = 1;
}
} else {
System.out.println("这个位置不在棋盘上");
System.out.println("这个位置的横坐标为:" + x);
System.out.println("这个位置的纵坐标为:" + y);
}
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
}
第三个类(这是个接口):
package gobang227;
public interface GoBangDate {
// 设置棋盘面板的起始坐标
public int X = 50;
public int Y = 50;
// 设置棋盘面板的横线竖线个数
public int ROW = 15;
public int COLUMN = 15;
// 设置棋盘面板的格子大小,SIZE为正方形方格的长宽,CHESSSIZE为棋子的长宽
public int SIZE = 35;
public int CHESSSIZE = 25;
运行结果:OK我们现在可以画出来一个棋盘啦,也可以进行相应的点击,而且出现棋子的位置都在交叉点上。
那我们还存在什么问题呢?
1.右边的功能按钮功能还没做
2.点击两次同一个位置会造成棋子覆盖(定义一个二维数组来确认交叉点是否已经下过棋子了)
3.重绘的问题(界面最小化一下就什么都没了)
4.不能判断输赢
第二部分:这部分代码用于解决重绘的问题
第一个类:
package gobang228.copy;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
//定义棋盘类让其继承面板类,原因为之后要重写棋盘面板类的paint方法,将棋盘面板重置
public class GoBangMain extends JPanel implements GoBangDate {
// 定义初始化界面函数
public void initUI() {
JFrame jf = new JFrame();
jf.setTitle("五子棋对战");
jf.setSize(760, 630);
jf.setDefaultCloseOperation(3);
jf.setLocationRelativeTo(null);
jf.setResizable(false);
// 整体布局为边框布局,JFrame默认布局为边框布局
jf.setLayout(new BorderLayout());
// 添加棋盘面板,添加到边框布局的中部
jf.add(this, BorderLayout.CENTER);
this.setBackground(Color.gray);
// 功能面板,默认为流式布局
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(150, 0));
JLabel label = new JLabel();
label.setPreferredSize(new Dimension(140, 120));
panel.add(label);
// 添加功能面板
jf.add(panel, BorderLayout.EAST);
// 添加功能按钮
JButton bu1 = new JButton("开始新游戏");
JButton bu2 = new JButton("悔棋");
JButton bu3 = new JButton("认输");
bu1.setPreferredSize(new Dimension(140, 60));
bu2.setPreferredSize(new Dimension(140, 60));
bu3.setPreferredSize(new Dimension(140, 60));
panel.add(bu1);
panel.add(bu2);
panel.add(bu3);
JRadioButton jr1 = new JRadioButton("人人对战");
JRadioButton jr2 = new JRadioButton("人机对战");
jr1.setPreferredSize(new Dimension(80, 40));
jr2.setPreferredSize(new Dimension(80, 40));
ButtonGroup bg = new ButtonGroup();
bg.add(jr1);
bg.add(jr2);
// 默认选中为jr1按钮,即人人对战
jr1.setSelected(true);
panel.add(jr1);
panel.add(jr2);
// 复选框
JCheckBox jc = new JCheckBox("AI先手");
jc.setPreferredSize(new Dimension(80, 40));
panel.add(jc);
jf.setVisible(true);
// 实例化画笔对象
Graphics g = this.getGraphics();
// 实例化监听接口,并传参,参数为画笔对象
GoBangListener gl = new GoBangListener(g);
this.addMouseListener(gl);
}
@Override
public void paint(Graphics g) {
super.paint(g);
// 调用棋盘面板初始化的方法,使棋盘面板初始化
drawChessBorder(g);
// 棋盘面板的重绘
for (int r = 0; r < FLAG.length; r++) {
for (int c = 0; c < FLAG[r].length; c++) {
if (FLAG[r][c] != 0) {
int x = X + c * SIZE - CHESSSIZE / 2;
int y = Y + r * SIZE - CHESSSIZE / 2;
if (FLAG[r][c] == 1) {
g.setColor(Color.BLACK);
} else {
g.setColor(Color.white);
}
g.fillOval(x, y, CHESSSIZE, CHESSSIZE);
}
}
}
}
// 定义棋盘面板初始化的方法
private void drawChessBorder(Graphics g) {
for (int i = 0; i < ROW; i++)
g.drawLine(X, Y + i * SIZE, X + (COLUMN - 1) * SIZE, Y + i * SIZE);
for (int i = 0; i < COLUMN; i++)
g.drawLine(X + i * SIZE, Y, X + i * SIZE, Y + (ROW - 1) * SIZE);
}
public static void main(String[] args) {
// 实例化棋盘类对象,调用初始化函数
GoBangMain go = new GoBangMain();
go.initUI();
}
}
第二个类:
package gobang228.copy;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class GoBangListener implements MouseListener, GoBangDate {
private Graphics g;
private int x, y, row, col;
// 标志位,确认棋子颜色
private int flag = 1;
// 构造方法
public GoBangListener(Graphics g) {
this.g = g;
}
@Override
public void mouseClicked(MouseEvent e) {
x = e.getX();
y = e.getY();
// 计算点击位置的行和列,确认棋子把棋子放在相应交叉点
row = Math.round(y / SIZE);
System.out.println("这个棋子在第" + row + "行!");
y = Y - CHESSSIZE / 2 + (row - 1) * SIZE;
col = Math.round(x / SIZE);
System.out.println("这个棋子在第" + col + "列!");
x = X - CHESSSIZE / 2 + (col - 1) * SIZE;
// 确保点击位置在棋盘上
if (row <= ROW && col <= COLUMN) {
if (FLAG[row - 1][col - 1] == 0 && flag == 1) {
g.setColor(Color.black);
g.fillOval(x, y, CHESSSIZE, CHESSSIZE);
// 黑棋置1
FLAG[row - 1][col - 1] = 1;
flag = 2;
} else if (FLAG[row - 1][col - 1] == 0 && flag == 2) {
g.setColor(Color.white);
g.fillOval(x, y, CHESSSIZE, CHESSSIZE);
// 白棋置2
FLAG[row - 1][col - 1] = 2;
flag = 1;
}
}
// 判断输赢
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
}
第三个接口:
package gobang228.copy;
public interface GoBangDate {
// 设置棋盘面板的起始坐标
public int X = 50;
public int Y = 50;
// 设置棋盘面板的横线竖线个数
public int ROW = 15;
public int COLUMN = 15;
// 设置棋盘面板的格子大小,SIZE为正方形方格的长宽,CHESSSIZE为棋子的长宽
public int SIZE = 35;
public int CHESSSIZE = 25;
// 设置一个二维数组,默认值为0
public int FLAG[][] = new int[ROW][COLUMN];
}
运行结果:我们下了两个棋子,最小化后打开,棋子还在哎!!!
第三部分:解决判断输赢的问题
第一个类:
package gobang31.copy.copy;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
//定义棋盘类让其继承面板类,原因为之后要重写棋盘面板类的paint方法,将棋盘面板重置
public class GoBangMain extends JPanel implements GoBangDate {
// 定义初始化界面函数
public void initUI() {
JFrame jf = new JFrame();
jf.setTitle("五子棋对战");
jf.setSize(760, 630);
jf.setDefaultCloseOperation(3);
jf.setLocationRelativeTo(null);
jf.setResizable(false);
// 整体布局为边框布局,JFrame默认布局为边框布局
jf.setLayout(new BorderLayout());
// 添加棋盘面板,添加到边框布局的中部
jf.add(this, BorderLayout.CENTER);
this.setBackground(Color.gray);
// 功能面板,默认为流式布局
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(150, 0));
JLabel label = new JLabel();
label.setPreferredSize(new Dimension(140, 120));
panel.add(label);
// 添加功能面板
jf.add(panel, BorderLayout.EAST);
// 添加功能按钮
JButton bu1 = new JButton("开始新游戏");
JButton bu2 = new JButton("悔棋");
JButton bu3 = new JButton("认输");
bu1.setPreferredSize(new Dimension(140, 60));
bu2.setPreferredSize(new Dimension(140, 60));
bu3.setPreferredSize(new Dimension(140, 60));
panel.add(bu1);
panel.add(bu2);
panel.add(bu3);
JRadioButton jr1 = new JRadioButton("人人对战");
JRadioButton jr2 = new JRadioButton("人机对战");
jr1.setPreferredSize(new Dimension(80, 40));
jr2.setPreferredSize(new Dimension(80, 40));
ButtonGroup bg = new ButtonGroup();
bg.add(jr1);
bg.add(jr2);
// 默认选中为jr1按钮,即人人对战
jr1.setSelected(true);
panel.add(jr1);
panel.add(jr2);
// 复选框
JCheckBox jc = new JCheckBox("AI先手");
jc.setPreferredSize(new Dimension(80, 40));
panel.add(jc);
jf.setVisible(true);
// 实例化画笔对象
Graphics g = this.getGraphics();
// 实例化监听接口,并传参,参数为画笔对象
GoBangListener gl = new GoBangListener(g, this);
this.addMouseListener(gl);
}
@Override
public void paint(Graphics g) {
super.paint(g);
// 调用棋盘面板初始化的方法,使棋盘面板初始化
drawChessBorder(g);
// 棋盘面板的重绘
for (int r = 0; r < FLAG.length; r++) {
for (int c = 0; c < FLAG[r].length; c++) {
if (FLAG[r][c] != 0) {
int x = X + c * SIZE - CHESSSIZE / 2;
int y = Y + r * SIZE - CHESSSIZE / 2;
if (FLAG[r][c] == 1) {
g.setColor(Color.BLACK);
} else {
g.setColor(Color.white);
}
g.fillOval(x, y, CHESSSIZE, CHESSSIZE);
}
}
}
}
// 定义棋盘面板初始化的方法
private void drawChessBorder(Graphics g) {
for (int i = 0; i < ROW; i++)
g.drawLine(X, Y + i * SIZE, X + (COLUMN - 1) * SIZE, Y + i * SIZE);
for (int i = 0; i < COLUMN; i++)
g.drawLine(X + i * SIZE, Y, X + i * SIZE, Y + (ROW - 1) * SIZE);
}
public static void main(String[] args) {
// 实例化棋盘类对象,调用初始化函数
GoBangMain go = new GoBangMain();
go.initUI();
}
}
第二个类:
package gobang31.copy.copy;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JOptionPane;
public class GoBangListener implements MouseListener, GoBangDate {
private Graphics g;
private int x, y, row, col;
// 标志位,确认棋子颜色
private int flag = 1;
private String str;
private GoBangMain gobangMain;
// 构造方法
public GoBangListener(Graphics g, GoBangMain gobangMain) {
this.g = g;
this.gobangMain = gobangMain;
}
@Override
public void mouseClicked(MouseEvent e) {
x = e.getX();
y = e.getY();
// 计算点击位置的行和列,确认棋子把棋子放在相应交叉点
// row为棋子行数,col为棋子列数,row范围为1-15,col也是
// x,y为棋子左上角的坐标值
row = Math.round(y / SIZE);
y = Y - CHESSSIZE / 2 + (row - 1) * SIZE;
col = Math.round(x / SIZE);
x = X - CHESSSIZE / 2 + (col - 1) * SIZE;
// 确保点击位置在棋盘上
if (row <= ROW && col <= COLUMN) {
if (FLAG[row - 1][col - 1] == 0 && flag == 1) {
g.setColor(Color.black);
g.fillOval(x, y, CHESSSIZE, CHESSSIZE);
// 黑棋置1
// FLAG为二维数组,起始位置为FLAG[0][0],此时row和col值均为1,故两者需要减去1
FLAG[row - 1][col - 1] = 1;
flag = 2;
} else if (FLAG[row - 1][col - 1] == 0 && flag == 2) {
g.setColor(Color.white);
g.fillOval(x, y, CHESSSIZE, CHESSSIZE);
// 白棋置2
FLAG[row - 1][col - 1] = 2;
flag = 1;
}
}
// 判断输赢
if (GoBangWin.validate(row, col)) {
if (FLAG[row - 1][col - 1] == 1) {
str = "黑棋胜利!";
} else if (FLAG[row - 1][col - 1] == 2) {
str = "白棋胜利!";
}
JOptionPane.showMessageDialog(gobangMain, str);
}
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
}
第三个接口:
package gobang31.copy.copy;
public interface GoBangDate {
// 设置棋盘面板的起始坐标
public int X = 50;
public int Y = 50;
// 设置棋盘面板的横线竖线个数
public int ROW = 15;
public int COLUMN = 15;
// 设置棋盘面板的格子大小,SIZE为正方形方格的长宽,CHESSSIZE为棋子的长宽
public int SIZE = 35;
public int CHESSSIZE = 25;
// 设置一个二维数组,默认值为0
public int FLAG[][] = new int[ROW][COLUMN];
}
第四个类:在这里定义了判断胜利的方法,方法为以鼠标点击位置为原点,分别判断左,右,上,下,左上,左下,右上,右下八个方向的跟所下棋子颜色相同的棋子个数是否大于等于5
package gobang31.copy.copy;
public class GoBangWin implements GoBangDate {
// 判断同一行上颜色相同的棋子个数是否大于等于5
// 参数为r(该棋子所在的行),c(该棋子所在的列)
public static boolean validate(int r, int c) {
if (countZ(r, c) >= 5 || countY(r, c) >= 5 || countX(r, c) >= 5 || countS(r, c) >= 5 || countZS(r, c) >= 5
|| countZX(r, c) >= 5 || countYS(r, c) >= 5 || countYX(r, c) >= 5) {
return true;
} else {
return false;
}
}
// 计算同一行上颜色相同的棋子个数
// 参数为row(该棋子所在的行),col(该棋子所在的列)
public static int countZ(int row, int col) {
int count = 1;
for (int col1 = col - 1; col1 > 0; col1--) {
if (FLAG[row - 1][col1 - 1] == FLAG[row - 1][col - 1]) {
count++;
} else {
break;
}
}
return count;
}
public static int countY(int row, int col) {
int count = 1;
for (int col1 = col + 1; col1 < COLUMN; col1++) {
if (FLAG[row - 1][col1 - 1] == FLAG[row - 1][col - 1]) {
count++;
} else {
break;
}
}
return count;
}
public static int countX(int row, int col) {
int count = 1;
for (int row1 = row + 1; row1 < ROW; row1++) {
if (FLAG[row1 - 1][col - 1] == FLAG[row - 1][col - 1]) {
count++;
} else {
break;
}
}
return count;
}
public static int countS(int row, int col) {
int count = 1;
for (int row1 = row - 1; row1 > 0; row1--) {
if (FLAG[row1 - 1][col - 1] == FLAG[row - 1][col - 1]) {
count++;
} else {
break;
}
}
return count;
}
public static int countZS(int row, int col) {
int count = 1;
for (int row1 = row - 1, col1 = col - 1; row1 > 0 && col1 > 0; row1--, col1--) {
if (FLAG[row1 - 1][col1 - 1] == FLAG[row - 1][col - 1]) {
count++;
} else {
break;
}
}
return count;
}
public static int countYX(int row, int col) {
int count = 1;
for (int row1 = row + 1, col1 = col + 1; row1 < ROW && col1 < COLUMN; row1++, col1++) {
if (FLAG[row1 - 1][col1 - 1] == FLAG[row - 1][col - 1]) {
count++;
} else {
break;
}
}
return count;
}
public static int countZX(int row, int col) {
int count = 1;
for (int row1 = row + 1, col1 = col - 1; row1 < ROW && col1 > 0; row1++, col1--) {
if (FLAG[row1 - 1][col1 - 1] == FLAG[row - 1][col - 1]) {
count++;
} else {
break;
}
}
return count;
}
public static int countYS(int row, int col) {
int count = 1;
for (int row1 = row - 1, col1 = col + 1; row1 > 0 && col1 < COLUMN; row1--, col1++) {
if (FLAG[row1 - 1][col1 - 1] == FLAG[row - 1][col - 1]) {
count++;
} else {
break;
}
}
return count;
}
}
运行结果:我们知道如何判断输赢了哎!
第四部分:实现功能按钮面板的功能,让棋盘游戏更加贴近真实状况
第一个类:
package gobang32.copy.copy.copy;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
//定义棋盘类让其继承面板类,原因为之后要重写棋盘面板类的paint方法,将棋盘面板重置
public class GoBangMain extends JPanel implements GoBangDate {
// 定义初始化界面函数
public void initUI() {
JFrame jf = new JFrame();
jf.setTitle("五子棋对战");
jf.setSize(760, 630);
jf.setDefaultCloseOperation(3);
jf.setLocationRelativeTo(null);
jf.setResizable(false);
// 整体布局为边框布局,JFrame默认布局为边框布局
jf.setLayout(new BorderLayout());
// 添加棋盘面板,添加到边框布局的中部
jf.add(this, BorderLayout.CENTER);
this.setBackground(Color.gray);
// 功能面板,默认为流式布局
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(150, 0));
// 在功能面板上方添加空白区域
JLabel label = new JLabel();
label.setPreferredSize(new Dimension(140, 120));
panel.add(label);
// 添加功能面板
jf.add(panel, BorderLayout.EAST);
// 添加功能按钮
JButton bu1 = new JButton("开始新游戏");
JButton bu2 = new JButton("悔棋");
JButton bu3 = new JButton("认输");
bu1.setPreferredSize(new Dimension(140, 60));
bu2.setPreferredSize(new Dimension(140, 60));
bu3.setPreferredSize(new Dimension(140, 60));
panel.add(bu1);
panel.add(bu2);
panel.add(bu3);
JRadioButton jr1 = new JRadioButton("人人对战");
JRadioButton jr2 = new JRadioButton("人机对战");
jr1.setPreferredSize(new Dimension(80, 40));
jr2.setPreferredSize(new Dimension(80, 40));
ButtonGroup bg = new ButtonGroup();
bg.add(jr1);
bg.add(jr2);
// 默认选中为jr1按钮,即人人对战
jr1.setSelected(true);
panel.add(jr1);
panel.add(jr2);
// 复选框
JCheckBox jc = new JCheckBox("AI先手");
jc.setPreferredSize(new Dimension(80, 40));
panel.add(jc);
jc.setEnabled(false);
jf.setVisible(true);
// 实例化监听接口
GoBangListener gl = new GoBangListener(this, bu1, bu2, bu3, jr1, jr2, jc);
bu1.addActionListener(gl);
bu2.addActionListener(gl);
bu2.setEnabled(false);
bu3.addActionListener(gl);
bu3.setEnabled(false);
jr1.addActionListener(gl);
jr2.addActionListener(gl);
jc.addActionListener(gl);
}
@Override
public void paint(Graphics g) {
super.paint(g);
// 调用棋盘面板初始化的方法,使棋盘面板初始化
drawChessBorder(g);
// 棋盘面板的重绘
for (int r = 0; r < FLAG.length; r++) {
for (int c = 0; c < FLAG[r].length; c++) {
if (FLAG[r][c] != 0) {
int x = X + c * SIZE - CHESSSIZE / 2;
int y = Y + r * SIZE - CHESSSIZE / 2;
if (FLAG[r][c] == 1) {
g.setColor(Color.BLACK);
} else {
g.setColor(Color.white);
}
g.fillOval(x, y, CHESSSIZE, CHESSSIZE);
}
}
}
}
// 定义棋盘面板初始化的方法
private void drawChessBorder(Graphics g) {
for (int i = 0; i < ROW; i++)
g.drawLine(X, Y + i * SIZE, X + (COLUMN - 1) * SIZE, Y + i * SIZE);
for (int i = 0; i < COLUMN; i++)
g.drawLine(X + i * SIZE, Y, X + i * SIZE, Y + (ROW - 1) * SIZE);
}
public static void main(String[] args) {
// 实例化棋盘类对象,调用初始化函数
GoBangMain go = new GoBangMain();
go.initUI();
}
}
第二个类:
package gobang32.copy.copy.copy;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JOptionPane;
import javax.swing.JRadioButton;
public class GoBangListener implements MouseListener, GoBangDate, ActionListener {
private Graphics g;
private int x, y, row, col;
// 标志位,确认棋子颜色
private int flag = 1;
private String str, str1;
private GoBangMain gobangMain;
private JButton bu1, bu2, bu3;
private JRadioButton jr1, jr2;
private JCheckBox jc;
private String ss = "人人对战";
private ArrayList list = new ArrayList();
// 构造方法
public GoBangListener(GoBangMain gobangMain, JButton bu1, JButton bu2, JButton bu3, JRadioButton jr1,
JRadioButton jr2, JCheckBox jc) {
this.gobangMain = gobangMain;
this.bu1 = bu1;
this.bu2 = bu2;
this.bu3 = bu3;
this.jr1 = jr1;
this.jr2 = jr2;
this.jc = jc;
}
@Override
public void mouseClicked(MouseEvent e) {
x = e.getX();
y = e.getY();
// 计算点击位置的行和列,确认棋子把棋子放在相应交叉点
// row为棋子行数,col为棋子列数,row范围为1-15,col也是
// x,y为棋子左上角的坐标值
if (ss.equals("人人对战")) {
row = Math.round(y / SIZE);
y = Y - CHESSSIZE / 2 + (row - 1) * SIZE;
col = Math.round(x / SIZE);
x = X - CHESSSIZE / 2 + (col - 1) * SIZE;
list.add(new Point(row, col));
System.out.println("这个数组队列大小为:" + list.size());
// 确保点击位置在棋盘上
if (row <= ROW && col <= COLUMN) {
if (FLAG[row - 1][col - 1] == 0 && flag == 1) {
g.setColor(Color.black);
g.fillOval(x, y, CHESSSIZE, CHESSSIZE);
// 黑棋置1
// FLAG为二维数组,起始位置为FLAG[0][0],此时row和col值均为1,故两者需要减去1
FLAG[row - 1][col - 1] = 1;
// 下一个棋子时白棋
flag = 2;
} else if (FLAG[row - 1][col - 1] == 0 && flag == 2) {
g.setColor(Color.white);
g.fillOval(x, y, CHESSSIZE, CHESSSIZE);
// 白棋置2
FLAG[row - 1][col - 1] = 2;
// 下一个棋子是黑棋
flag = 1;
}
}
// 判断输赢
if (GoBangWin.validate(row, col)) {
if (FLAG[row - 1][col - 1] == 1) {
str = "黑棋胜利!";
} else if (FLAG[row - 1][col - 1] == 2) {
str = "白棋胜利!";
}
JOptionPane.showMessageDialog(gobangMain, str);
// 胜利之后也不能继续落子了
gobangMain.removeMouseListener(this);
bu1.setEnabled(true);
bu2.setEnabled(false);
bu3.setEnabled(false);
jr1.setEnabled(true);
jr2.setEnabled(true);
}
} else {
JOptionPane.showMessageDialog(gobangMain, "人机对战还未实现,请稍后。。。");
}
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
@Override
public void actionPerformed(ActionEvent e) {
// 获取按钮文字信息
String s = e.getActionCommand();
if (s.equals("开始新游戏")) {
g = gobangMain.getGraphics();
bu1.setEnabled(false);
bu2.setEnabled(true);
bu3.setEnabled(true);
jr1.setEnabled(false);
jr2.setEnabled(false);
jc.setEnabled(false);
// 清除二维数组中的内容
for (int r = 0; r < FLAG.length; r++) {
for (int c = 0; c < FLAG[r].length; c++) {
FLAG[r][c] = 0;
}
}
// 棋盘界面重绘
gobangMain.paint(g);
// 标志位置1位黑棋优先
flag = 1;
// 开始新游戏之后棋盘界面才能被监听,也就是开始下棋
gobangMain.addMouseListener(this);
} else if (s.equals("悔棋")) {
if (ss.equals("人人对战")) {
if (list.size() > 2) {
Point p = list.remove(list.size() - 1);
System.out.println("此时这个数组队列大小为:" + list.size());
FLAG[p.x - 1][p.y - 1] = 0;
gobangMain.paint(g);
if (flag == 1) {
flag = 2;
} else if (flag == 2) {
flag = 1;
}
}
} else if (ss.equals("人机对战")) {
// 人机对战悔棋代码
}
} else if (s.equals("认输")) {
if (ss.equals("人人对战")) {
// flag等于1说明轮到黑棋方下棋
if (flag == 1) {
str1 = "黑棋认输,白棋胜利!";
} else if (flag == 2) {
str1 = "白棋认输,黑棋胜利!";
}
JOptionPane.showMessageDialog(gobangMain, str1);
// 认输之后不能继续落子了
gobangMain.removeMouseListener(this);
bu1.setEnabled(true);
bu2.setEnabled(false);
bu3.setEnabled(false);
jr1.setEnabled(true);
jr2.setEnabled(true);
} else {
// 此处应该为人机对战认输代码
}
} else if (s.equals("人人对战")) {
jc.setEnabled(false);
ss = s;
} else if (s.equals("人机对战")) {
jc.setEnabled(true);
ss = s;
} else if (s.equals("AI先手")) {
}
}
}
第三个接口:
package gobang32.copy.copy.copy;
public interface GoBangDate {
// 设置棋盘面板的起始坐标
public int X = 50;
public int Y = 50;
// 设置棋盘面板的横线竖线个数
public int ROW = 15;
public int COLUMN = 15;
// 设置棋盘面板的格子大小,SIZE为正方形方格的长宽,CHESSSIZE为棋子的长宽
public int SIZE = 35;
public int CHESSSIZE = 25;
// 设置一个二维数组,默认值为0
public int FLAG[][] = new int[ROW][COLUMN];
}
第四个类:
package gobang32.copy.copy.copy;
public class GoBangWin implements GoBangDate {
// 判断同一行上颜色相同的棋子个数是否大于等于5
// 参数为r(该棋子所在的行),c(该棋子所在的列)
public static boolean validate(int r, int c) {
if (countZ(r, c) >= 5 || countY(r, c) >= 5 || countX(r, c) >= 5 || countS(r, c) >= 5 || countZS(r, c) >= 5
|| countZX(r, c) >= 5 || countYS(r, c) >= 5 || countYX(r, c) >= 5) {
return true;
} else {
return false;
}
}
// 计算同一行上颜色相同的棋子个数
// 参数为row(该棋子所在的行),col(该棋子所在的列)
public static int countZ(int row, int col) {
int count = 1;
for (int col1 = col - 1; col1 > 0; col1--) {
if (FLAG[row - 1][col1 - 1] == FLAG[row - 1][col - 1]) {
count++;
} else {
break;
}
}
return count;
}
public static int countY(int row, int col) {
int count = 1;
for (int col1 = col + 1; col1 < COLUMN; col1++) {
if (FLAG[row - 1][col1 - 1] == FLAG[row - 1][col - 1]) {
count++;
} else {
break;
}
}
return count;
}
public static int countX(int row, int col) {
int count = 1;
for (int row1 = row + 1; row1 < ROW; row1++) {
if (FLAG[row1 - 1][col - 1] == FLAG[row - 1][col - 1]) {
count++;
} else {
break;
}
}
return count;
}
public static int countS(int row, int col) {
int count = 1;
for (int row1 = row - 1; row1 > 0; row1--) {
if (FLAG[row1 - 1][col - 1] == FLAG[row - 1][col - 1]) {
count++;
} else {
break;
}
}
return count;
}
public static int countZS(int row, int col) {
int count = 1;
for (int row1 = row - 1, col1 = col - 1; row1 > 0 && col1 > 0; row1--, col1--) {
if (FLAG[row1 - 1][col1 - 1] == FLAG[row - 1][col - 1]) {
count++;
} else {
break;
}
}
return count;
}
public static int countYX(int row, int col) {
int count = 1;
for (int row1 = row + 1, col1 = col + 1; row1 < ROW && col1 < COLUMN; row1++, col1++) {
if (FLAG[row1 - 1][col1 - 1] == FLAG[row - 1][col - 1]) {
count++;
} else {
break;
}
}
return count;
}
public static int countZX(int row, int col) {
int count = 1;
for (int row1 = row + 1, col1 = col - 1; row1 < ROW && col1 > 0; row1++, col1--) {
if (FLAG[row1 - 1][col1 - 1] == FLAG[row - 1][col - 1]) {
count++;
} else {
break;
}
}
return count;
}
public static int countYS(int row, int col) {
int count = 1;
for (int row1 = row - 1, col1 = col + 1; row1 > 0 && col1 < COLUMN; row1--, col1++) {
if (FLAG[row1 - 1][col1 - 1] == FLAG[row - 1][col - 1]) {
count++;
} else {
break;
}
}
return count;
}
}
运行结果:这是初始化界面,只有“开始新游戏”,“人人”,“人机对战可以被选择”,默认选中“人人”,当选中人机时,复选框“AI先手”可以被选中,而且未点击“开始新游戏”不能落下棋子,即没有开启棋盘面板的监听
当点击“开始新游戏”按钮后,只有“悔棋”,“认输”按钮可以选中
下面我们开始下棋
胜利之后不能继续在棋盘面板上下棋(撤去监听),把按钮是否可选置为初始化状态
认输:认输后也不能继续下棋了(撤去监听),功能按钮置位初始化状态
如何确定哪方认输?
是通过棋子标志位来参控的。
悔棋:
悔棋前状态:
悔棋后状态:
但是不能无限悔棋,棋子最少有两颗。
人机对战:
未完待续。。。