利用Java中的监听器和界面,可以实现简易五子棋的功能(这篇博客还不能实现人机对弈,只能实现两人互下)。
思路步骤如下:
1.创建一个界面,界面上安装上相关按钮;
2.在界面上绘制19*19的五子棋盘;
3.给界面添加监听器,以便确定下棋的位置;
4.设置棋子大小及颜色;
5.创建二维数组,记录空位置;
6.设计算法判断输赢;
7.实现重绘(这篇文章不设计,太复杂了,可以单独开一篇博客了,不过最后面的代码实现了)。
接下来,我们一步一步实现五子棋。
(一)创建界面:
Java中自带JFrame包,创建一个界面直接创建界面对象即可,方法如下:
JFrame jf=new JFrame();//新建对象
jf.setSize(Const.STAGE_SIZEW,Const.STAGE_SIZEH);//设置界面大小,这里我用了常量代替数字,以便于修改。设置常亮的方法见“注意事项”
jf.setLocationRelativeTo(null);//设置界面居中
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置关掉界面的同时关掉程序
jf.setResizable(false);//设置窗体大小不可调
关于创建按钮,我们可以直接创建在JFrame上。或者,我们还可以用到Java的JPanel类,单独创建一个面板放置按钮。用法如下:
JPanel ejp=new JPanel();//创建面板对象
Dimension panelsize=new Dimension(Const.EJP_SIZE,0);//设置面板大小
ejp.setPreferredSize(panelsize);//设置面板大小
ejp.setBackground(Color.LIGHT_GRAY);//设置面板颜色
按钮我们可以利用数组创建,这样写较简便:
String tnstr1[] = {"开始游戏","重新开始","认输","悔棋"};
for (int i = 0; i < tnstr1.length; i++) {
JButton btButton = new JButton(tnstr1[i]);
btButton.setPreferredSize(new Dimension(100,30));//设置按钮大小
ejp.add(btButton);//将按钮添加到面板上
btButton.addActionListener(dl);//这是添加监听器,下面会讲到
}
这样,一个简单的界面就算做完了。如下:
(二)绘制棋盘:
绘制棋盘需要用到Java当中的画笔,Java当中的画笔用起来比较方便。不过,调用画笔的方式与创建对象有些不同,用法如下:
Graphics g=this.getGraphics();//这个this暂时不用管,下面会讲到。可以先将它理解为ejp(n那个面板);另外,注意这个getGraphics()的使用
接下来,用一个for循环,即可实现棋盘的绘制:
for(int i=0;i
(关于drawline()函数的用法,可以百度一下,这里就不再讲啦)
为了简便起见,我把绘制棋盘写在了重绘里面,这个先不管。如下:
(三)添加监听器:
监听器是干什么用的?可以通俗的理解为获取坐标。比如,鼠标监听器可以让你得到点击位置的坐标(界面左上角的坐标为(0,0))。
添加监听器需要用到接口(用法和继承差不多吧我觉得,就是关键字的区别),步骤如下:
1.创建监听器类;
2.接口。
代码就一句:
public class DrawListener implements MouseListener,ActionListener
我们这里用到了鼠标监听器和动作监听器,用动作监听器获取按钮上的字符串,用鼠标监听器获取下棋的位置。这里需要注意的是,监听器里面的方法需要重写,方法是按住“Ctrl”键,将鼠标移动至MouseListener,ActionListener上,即可打开监听器,将里面的方法复制出来。
比如:
将动作监听器的这个方法复制到监听器类里面就可以啦!
下面进行字符串的获取:
public void actionPerformed(ActionEvent e){
str=e.getActionCommand();
}
只需一个函数而已。
获得下棋的位置:
public void mouseClicked(MouseEvent e){
// System.out.println("点击");
int x1=e.getX();
int y1=e.getY();
}
(哈哈,还是只需要一个函数)
(四)关于棋子
棋子的绘制也很简单只需要用到g.fillOval()。这里我们不妨多设立一个变量n,用于检验黑棋白棋。
if (n % 2 == 1) {
g.setColor(Color.white);//设置棋子颜色
cl = g.getColor();
g.fillOval(x2, y2, Const.CHESS_SIZE, Const.CHESS_SIZE);
a[i][j] = 1;//这个数组用来判断位置是否空,我们接下来会讲
n++;
} else if (n % 2 == 0) {
g.setColor(Color.black);
cl = g.getColor();
g.fillOval(x2, y2, Const.CHESS_SIZE, Const.CHESS_SIZE);
a[i][j] = 2;
n++;
}
(五)判断位置是否为空:
我的思路是创建一个二维数组,初始值为0,下了白棋后变1,下了黑棋后变2。
这里我们有同学可能要问了:我们得到的x、y均为实际的坐标,怎么能把它们与数组的下标进行统一呢?大家有没有发现,如果我们完全按照得到的坐标下棋,棋子很可能不会落到格子上。那么在这里,我们需要进行计算,将得到的坐标四舍五入使棋子准确的落在格子上。公式如下:
X=(得到的x坐标-棋盘移动的位置)/格子的大小
落子圆心位置X=X*格子大小+棋盘移动的位置-格子大小的一半
Y同理。关于四舍五入的问题,我是先设X为double,接着判断小数部分是否大于0.5。这样之后,数组的下标也可算出。
之后每次下棋都遍历这个数组,即可判断该位置可不可下棋。
(六)设计算法判断输赢:
大家都知道五子棋怎么判断输赢,但是如何让计算机判断呢?还是数组的遍历!
我是分为了四个方向,分为横、竖、左斜、右斜。分别找到四个方向的初始位置,开始遍历,遇到五个数字一样的就结束遍历,判断输赢。例子如下:
// 横向判断输赢
for (int m = 0; m < Const.CELL_NUMBER + 1; m++) {
if (m + 4 > Const.CELL_NUMBER) {
break;
}
if (a[m][j] == 1) {
if (a[m + 1][j] == 1) {
if (a[m + 2][j] == 1) {
if (a[m + 3][j] == 1) {
if (a[m + 4][j] == 1) {
System.out.println("白棋获胜!");
againUIw();
return;
}
}
}
}
} else if (a[m][j] == 2) {
if (a[m + 1][j] == 2) {
if (a[m + 2][j] == 2) {
if (a[m + 3][j] == 2) {
if (a[m + 4][j] == 2) {
System.out.println("黑棋获胜!");
againUIb();
return;
}
}
}
}
}
}
注意事项:
1.在设定棋子大小等常量的时候,可以单独建一个类存放它们,这样便于修改,详细请见源代码的Const类。
2.设置界面居中的语句一定要放在设置大小的后面。
3.在给监听器传值时,传值的部分一定要放到setVisible(true)后(我就是犯了这个错嘤嘤嘤)
源代码如下:
package gobang;
public class Manage {
public static void main(String []args){
MyPanel newpanel=new MyPanel();
newpanel.ShowUI();
}
}
放主函数的类
package gobang;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import gobang.Shape;
import java.awt.Graphics;
public class MyPanel extends JPanel{
int a[][]=new int[19][19];
Shape[] shapedata=new Shape[Const.CELL_NUMBER*Const.CELL_NUMBER];
public void ShowUI(){
JFrame jf=new JFrame();
jf.setSize(Const.STAGE_SIZEW,Const.STAGE_SIZEH);
jf.setLocationRelativeTo(null);//居中
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setResizable(false);
//面板
JPanel ejp=new JPanel();
Dimension panelsize=new Dimension(Const.EJP_SIZE,0);
ejp.setPreferredSize(panelsize);
ejp.setBackground(Color.LIGHT_GRAY);
FlowLayout fl = new FlowLayout();//实例化流式布局器
ejp.setLayout(fl); //设置布局器
this.setLayout(fl);
jf.add(this,BorderLayout.CENTER);
jf.add(ejp,BorderLayout.EAST);
//设置按钮
Dimension buttnsize=new Dimension(100,40);
JButton jb1=new JButton("开始游戏");
jb1.setPreferredSize(buttnsize);
ejp.add(jb1);
JButton jb2=new JButton("重新开始");
jb2.setPreferredSize(buttnsize);
ejp.add(jb2);
JButton jb3=new JButton("认输");
jb3.setPreferredSize(buttnsize);
ejp.add(jb3);
JButton jb4=new JButton("悔棋");
jb4.setPreferredSize(buttnsize);
ejp.add(jb4);
//添加监听器
Listener l=new Listener();
jb1.addActionListener(l);
jb2.addActionListener(l);
jb3.addActionListener(l);
jb4.addActionListener(l);
this.addMouseListener(l);
jb3.addMouseListener(l);
jf.setVisible(true);
//传值
Graphics g=this.getGraphics();
l.g=g;
l.cjp=this;
l.shapedata=shapedata;
l.cl=getBackground();
}
public void paint(Graphics g){
super.paint(g);
int n=1;
for(int i=0;i
}
//设置界面的类
package gobang;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.*;
import java.awt.Color;
import java.awt.Graphics;
public class Listener implements ActionListener,MouseListener{
String str="";
Graphics g;
Color cl;
JPanel cjp;
int n=1;
int a[][]=new int[19][19];
Shape shapedata[];
int count=0;
public void actionPerformed(ActionEvent e){
str=e.getActionCommand();
if("悔棋".equals(str)){
shapedata[count]=null;
System.out.println("count="+count);
if(count<0){
System.out.println("错误");
count++;
return;
}else{
a[shapedata[count-1].i][shapedata[count-1].j]=0;
count-=1;
g.setColor(cl);
g.fillRect(0, 0, Const.STAGE_SIZEW,Const.STAGE_SIZEH );
g.setColor(Color.black);
for(int i=0;i
//监听器类
package gobang;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JOptionPane;
import com.sun.corba.se.impl.orbutil.closure.Constant;
public class Shape {
String str = "";
int x1=0, y1=0;
Color cl;
int i=0,j=0;
public int begin(int n, int x, int y, int a[][], int e, Graphics g) {
if ("认输".equals(str)) {
if (n % 2 == 1) {
System.out.println("白棋输了!");
againUIb();
} else {
System.out.println("黑棋输了!");
againUIw();
}
} else {
// 计算数组的下标
float tempi, tempj;
tempi = ((float) x - (float) Const.MOVE_LEFT) / (float) Const.CELL_SIZE;
tempj = ((float) y - (float) Const.MOVE_DOWN) / (float) Const.CELL_SIZE;
i = (x - Const.MOVE_LEFT) / Const.CELL_SIZE;
j = (y - Const.MOVE_DOWN) / Const.CELL_SIZE;
// System.out.println("tempi="+tempi);
// System.out.println("tempj="+tempj);
if (tempi - i >= 0.5) {
i = i + 1;
}
if (tempj - j >= 0.5) {
j = j + 1;
}
// System.out.println("i="+i);
// System.out.println("j="+j);
// 计算下棋的位置
int x2, y2;
x2 = i * Const.CELL_SIZE + Const.MOVE_LEFT - Const.CHESS_SIZE / 2;
y2 = j * Const.CELL_SIZE + Const.MOVE_DOWN - Const.CHESS_SIZE / 2;
// System.out.println("x2="+x2);
// System.out.println("y2="+y2);
if (a[i][j] != 0 && e == 1) {
System.out.println("请重新选择位置");
str="请重新选择位置";
System.out.println("@@@");
return 1;
} else {
if (n % 2 == 1) {
g.setColor(Color.white);
cl = g.getColor();
g.fillOval(x2, y2, Const.CHESS_SIZE, Const.CHESS_SIZE);
a[i][j] = 1;
n++;
} else if (n % 2 == 0) {
g.setColor(Color.black);
cl = g.getColor();
g.fillOval(x2, y2, Const.CHESS_SIZE, Const.CHESS_SIZE);
a[i][j] = 2;
n++;
}
}
winOrnot(a, i, j);
}
return n;
}
public void winOrnot(int a[][], int i, int j) {
// 判断输赢
// 横向判断输赢
for (int m = 0; m < Const.CELL_NUMBER + 1; m++) {
if (m + 4 > Const.CELL_NUMBER) {
break;
}
if (a[m][j] == 1) {
if (a[m + 1][j] == 1) {
if (a[m + 2][j] == 1) {
if (a[m + 3][j] == 1) {
if (a[m + 4][j] == 1) {
System.out.println("白棋获胜!");
againUIw();
return;
}
}
}
}
} else if (a[m][j] == 2) {
if (a[m + 1][j] == 2) {
if (a[m + 2][j] == 2) {
if (a[m + 3][j] == 2) {
if (a[m + 4][j] == 2) {
System.out.println("黑棋获胜!");
againUIb();
return;
}
}
}
}
}
}
// 纵向判断
for (int m = 0; m < Const.CELL_NUMBER + 1; m++) {
if (m + 4 > Const.CELL_NUMBER) {
break;
}
if (a[i][m] == 1) {
if (a[i][m + 1] == 1) {
if (a[i][m + 2] == 1) {
if (a[i][m + 3] == 1) {
if (a[i][m + 4] == 1) {
System.out.println("白棋获胜!");
againUIw();
return;
}
}
}
}
} else if (a[i][m] == 2) {
if (a[i][m + 1] == 2) {
if (a[i][m + 2] == 2) {
if (a[i][m + 3] == 2) {
if (a[i][m + 4] == 2) {
System.out.println("黑棋获胜!");
againUIb();
return;
}
}
}
}
}
}
// 左斜判断
if (i >= j) {
for (int n = 0, m = i - j; m < Const.CELL_NUMBER + 1 && n < Const.CELL_NUMBER + 1; m++, n++) {
if (m + 4 > Const.CELL_NUMBER || n + 4 > Const.CELL_NUMBER) {
break;
}
if (a[m][n] == 2) {
if (a[m + 1][n + 1] == 2) {
if (a[m + 2][n + 2] == 2) {
if (a[m + 3][n + 3] == 2) {
if (a[m + 4][n + 4] == 2) {
System.out.println("黑棋获胜!");
againUIb();
return;
}
}
}
}
} else if (a[m][n] == 1) {
if (a[m + 1][n + 1] == 1) {
if (a[m + 2][n + 2] == 1) {
if (a[m + 3][n + 3] == 1) {
if (a[m + 4][n + 4] == 1) {
System.out.println("白棋获胜!");
againUIw();
return;
}
}
}
}
}
}
}
if (i < j) {
for (int n = 0, m = j - i; m < Const.CELL_NUMBER + 1 && n < Const.CELL_NUMBER + 1; m++, n++) {
if (m + 4 > Const.CELL_NUMBER || n + 4 > Const.CELL_NUMBER) {
break;
}
if (a[n][m] == 2) {
if (a[n + 1][m + 1] == 2) {
if (a[n + 2][m + 2] == 2) {
if (a[n + 3][m + 3] == 2) {
if (a[n + 4][m + 4] == 2) {
System.out.println("黑棋获胜!");
againUIb();
return;
}
}
}
}
} else if (a[n][m] == 1) {
if (a[n + 1][m + 1] == 1) {
if (a[n + 2][m + 2] == 1) {
if (a[n + 3][m + 3] == 1) {
if (a[n + 4][m + 4] == 1) {
System.out.println("白棋获胜!");
againUIw();
return;
}
}
}
}
}
}
}
// 右斜判断
if (i + j <= Const.CELL_NUMBER) {
for (int n = 0, m = i + j; m >= 0 && n < Const.CELL_NUMBER + 1; m--, n++) {
if (m - 4 < 0 || n + 4 > Const.CELL_NUMBER) {
break;
}
if (a[m][n] == 2) {
if (a[m - 1][n + 1] == 2) {
if (a[m - 2][n + 2] == 2) {
if (a[m - 3][n + 3] == 2) {
if (a[m - 4][n + 4] == 2) {
System.out.println("黑棋获胜!");
againUIb();
return;
}
}
}
}
} else if (a[m][n] == 1) {
if (a[m - 1][n + 1] == 1) {
if (a[m - 2][n + 2] == 1) {
if (a[m - 3][n + 3] == 1) {
if (a[m - 4][n + 4] == 1) {
System.out.println("白棋获胜!");
againUIw();
return;
}
}
}
}
}
}
} else if (i + j > Const.CELL_NUMBER) {
for (int m = Const.CELL_NUMBER, n = i + j - Const.CELL_NUMBER; m > 0
&& n < Const.CELL_NUMBER + 1; m--, n++) {
if (m - 4 < 0 || n + 4 > Const.CELL_NUMBER) {
break;
}
if (a[m][n] == 2) {
if (a[m - 1][n + 1] == 2) {
if (a[m - 2][n + 2] == 2) {
if (a[m - 3][n + 3] == 2) {
if (a[m - 4][n + 4] == 2) {
System.out.println("黑棋获胜!");
againUIb();
return;
}
}
}
}
} else if (a[m][n] == 1) {
if (a[m - 1][n + 1] == 1) {
if (a[m - 2][n + 2] == 1) {
if (a[m - 3][n + 3] == 1) {
if (a[m - 4][n + 4] == 1) {
System.out.println("白棋获胜!");
againUIw();
return;
}
}
}
}
}
}
}
}
public void AIshow(int a[][]){
int B[][]=new int[19][19];
int i,j;
for(i=0;i=0){
if(a[i-1][j]==1){
B[i][j]=Const.WEIGHT_NUMBER;
if(a[i-2][j]==1){
B[i][j]=2*Const.WEIGHT_NUMBER;
if(a[i-3][j]==1){
B[i][j]=3*Const.WEIGHT_NUMBER;
if(a[i-4][j]==1)
B[i][j]=4*Const.WEIGHT_NUMBER;
}
}
}
}
}
}
}
}
public void againUIw() {
int result=JOptionPane.showConfirmDialog(null, "白棋获胜!是否重新开始?");
if(result==0){
str="重新开始";
System.out.println(str);
}
}
public void againUIb() {
int result=JOptionPane.showConfirmDialog(null, "黑棋获胜!是否重新开始?");
if(result==0){
str="重新开始";
System.out.println(str);
}
}
}
//重绘类,里面包含了各种函数
package gobang;
public class Const {
//棋盘大小
public static final int STAGE_SIZEW=800,STAGE_SIZEH=750;
//东面板大小
public static final int EJP_SIZE=150;
//格子个数
public static final int CELL_NUMBER=18;
//零点漂移
public static final int MOVE_LEFT=20;
public static final int MOVE_DOWN=20;
//格子大小
public static final int CELL_SIZE=32;
//棋子的大小
public static final int CHESS_SIZE=20;
//每个权值的比重
public static final int WEIGHT_NUMBER=10;
}
//存放常量的类