java学习ing——五子棋的制作(人人对战)
自从上次完成了一次画图板,接下来的一个小项目的制作就是五子棋。包括了人人对战还有就是人机对战。这一片文章就先说一下人人对战,人机之后再来完善
#^_^
先附一张效果图哈~
先来制定一个制作五子棋大体的一个思路吧:
1.要先有个窗体,有棋盘。
2.要能在上面画出棋子(也就是下棋),并且要完成黑白交替的下棋。
3.要能够判断输赢,判断是否有某个颜色的棋子五个相连。
人人的比较简单,基本的思路就是这样,然后再来一步步的完成。
制作前期的准备工作
我们可以先定义一个存放五子棋他各个属性的一个接口,这样在创建棋盘等等的地方就可以通过直接调用这个接口中的静态属性来完成。这样的好处就是在修改某一参数的时候就能够直接通过修改这个接口中的属性的数值来完成。
/*
* 五子棋相关属性的类
*/
public interface WZQ_config {
/*
*设置棋盘网格行数列数为15
*/
public static final int Row = 15;
public static final int Column = 15;
/*
* 设置棋盘初始位置坐标
*/
public static final int X = 30;
public static final int Y = 60;
/*
* 设置棋子大小
*/
public static final int Chess_size = 40;
/*
* 设置棋盘格子大小
*/
public static final int WZQ_JianJu = 40;
}
窗体界面的实现
实现五子棋界面的方法可能也是蛮多的,我知道的呢有一种是在一个窗体上面分别在指定的位置使用循环绘制横竖15条线来形成一个棋盘的网格。第二种方法是直接在一个窗体上面添加一个棋盘完整的图片,这种比较简单省事儿吧。~~但。我自己用的是绘制网格线的方法。
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class WZQ_Board extends JFrame {
public Graphics g;
public static WZQ_Board wzq;
/*
* 重载构造方法
*/
public WZQ_Board() {
this.initUI();
}
/*
* 初始化界面的方法
*/
void initUI() {
/*
* 设置棋盘属性
*/
this.setTitle("吉吉的五子棋");
this.setSize(new Dimension(650, 650));
this.setResizable(false);
this.setDefaultCloseOperation(3);
this.setLocationRelativeTo(null);
this.setLayout(null);
/*
* 添加一块棋盘
*/
this.setLayout(null);
JPanel jp = new JPanel() {
/*
* (non-Javadoc)定义一个匿名内部类重写paint方法
*
* @see javax.swing.JComponent#paint(java.awt.Graphics)
*/
public void paint(Graphics g) {
g.setColor(Color.BLACK);
super.paint(g);
// 画15行
for (int i = 0; i < 15; i++) {
g.drawLine(20, 20 + i * WZQ_config.WZQ_JianJu, 20
+ (WZQ_config.Column - 1) * WZQ_config.WZQ_JianJu,
20 + i * WZQ_config.WZQ_JianJu);
}
// 画15列
for (int i = 0; i < 15; i++) {
g.drawLine(20 + i * WZQ_config.WZQ_JianJu, 20, 20 + i
* WZQ_config.WZQ_JianJu, 20
+ (WZQ_config.Column - 1) * WZQ_config.WZQ_JianJu);
}
g.setColor(Color.BLACK);
g.fillOval(133, 133, 15, 15);
g.fillOval(293, 133, 15, 15);
g.fillOval(453, 133, 15, 15);
g.fillOval(133, 293, 15, 15);
g.fillOval(293, 293, 15, 15);
g.fillOval(453, 293, 15, 15);
g.fillOval(133, 453, 15, 15);
g.fillOval(293, 453, 15, 15);
g.fillOval(453, 453, 15, 15);
// 重绘棋子
for (int i = 0; i < 650; i++) {
for (int j = 0; j < 650; j++) {
if (WZQ_listener.array[i][j] == "black") {
g.setColor(Color.BLACK);
g.fillOval(i, j, WZQ_config.Chess_size,
WZQ_config.Chess_size);
} else if (WZQ_listener.array[i][j] == "white") {
g.setColor(Color.WHITE);
g.fillOval(i, j, WZQ_config.Chess_size,
WZQ_config.Chess_size);
}
}
}
}
};
jp.setBackground(new Color(209, 167, 78));
jp.setBounds(10, 10, 602, 602);
this.add(jp);
this.setVisible(true);
g = jp.getGraphics();
/*
* 添加监听器
*/
WZQ_listener lis = new WZQ_listener(g);
jp.addMouseListener(lis);
}
}
这里绘制棋盘的方法是重写在他的重绘方法当中。在JFrame窗体上新建了一个带有颜色的JPanel,再在这个panel上面进行画线,这样呢就使得自己的棋盘变得~~美观些吧!
棋子的实现
下棋功能的实现需要考虑的地方也蛮多的:
1.首先想到下棋就是使用一个监听器来监听之前创建的panel棋盘,在鼠标释放的时候执行画园儿的操作。
2.怎么完成黑白交替着下
3.怎么使得棋子都下在正确的位置(网格线的相交点上)
4.怎么使得一个位置上只能存在一个棋子
啊~~我们再来一条一条的完善。
第一步很简单了,创建一个监听器来继承MouseAdapter这个抽象类。至于为什么不是实现MouseListener这个接口呢,原因很简单a~
因为实现MouseAdapter这个抽象类我们只需再重写我们需要用到的方法就可以了,而实现一个接口就要把他所有的抽象方法都要实现。这个五子棋的我们只用到的就是MouseReleased鼠标释放这一个,所以继承MouseAdapter显然更为简单。
然后重写其中MouseReleased方法,在鼠标释放的时候获取该点的xy坐标,在panel上获取画布:getGraphics(); 后就可以在上面画棋子了~~这样第一步也就完成了。
实现黑白交替呢~这里只需要一个控制变量,我使用的是一个boolean值state用来存储,true的时候表示该下黑子了,false的时候表示改下白子了。我们只需判断
if(state){
下黑子;
state = false;
}
else{
下白子;
state = true;
}
这样就完成了黑白子交替着下的功能~~
下一步是让棋子正位,我使用的方法是又自定义了一个坐标修正的函数。
/*
* 下棋位置坐标修正的方法
*/
public int correctXY(int x) {
x = x / 40;
return x * 40;
}
我就是用这样一个correctXY方法,在获取所点位置的xy坐标的时候进行一个修正,例如: int x = correctXY(e.getX());
这样就把所获得到的点通过这个方法给修正了,看似好像除以四十又返回一个乘以四十好像没有变化,但这样是使得每一个获取到的坐标都是四十的倍数,也就是在正确的位置上。
下棋的最后一步就是使得一个点位只能下一个棋子,这个就是很简单了,只要我们定义一个二维数组,行列均为15,也就是这个棋盘的行列数,在每一个位置下棋后都在二维数组的对应位置中存入下的什么棋子,例如下的黑棋则在那个位置附上1,白子则附为-1。所以只要在下棋的时候不只只是判定state的true或者false,同时在判定所下位置二维数组是否为0,若不为0则说明该位置有棋子则不执行下棋操作。so easy~~~
这样我们就可以在这个棋盘上面下棋了~~
最后一步~就是判段输赢的方法了
使用的方法就是每在我们下棋的时候都应该判定一次,通过获得每次所下棋子的位置来向四周八个方向分别判断是否已经有五个棋子相连了。如果有则返回一个true。然后在用一个方法来当有判断五连的方法有返回true的话,就看当前点的棋子是什么颜色的,黑子的话就是黑子五连了,否则就是白子五连。
监听器中的所有代码都放在一起啦:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Random;
import javax.swing.JPanel;
public class WZQ_listener extends MouseAdapter {
/*
* 设置黑白棋标识 true表示黑子,false表示白子
*/
public static boolean state = true;
public Graphics g;
public int x, y;
public static String[][] array = new String[700][700];
public static int[][] array_win = new int[15][15];
public static int[][] array_pve = new int[15][15];
public static int count_max;
public static int count_where = 0;
public JPanel panel;
public static Result result;
public static List list;
public static int val;
/*
* 重载他·的构造方法
*/
public WZQ_listener(Graphics g) {
this.g = g;
// this.panel = panel;
}
/*
* 鼠标释放执行的方法
*/
public void mouseReleased(MouseEvent e) {
x = correctXY(e.getX());
y = correctXY(e.getY());
System.out.println("x:"+x+" y:"+y);
/*
* 判定为人人对战
*/
if (ActListener.GameModel == 1) {
if (x < 582 && x >= 0 && y < 582 && y >= 0) {
if (state && array[x][y] == null) {
g.setColor(Color.BLACK);
g.fillOval(x, y, WZQ_config.Chess_size,
WZQ_config.Chess_size);
array[x][y] = "black";
array_win[getXY(y)][getXY(x)] = 1;
state = false;
} else if (array[x][y] == null) {
g.setColor(Color.WHITE);
g.fillOval(x, y, WZQ_config.Chess_size,
WZQ_config.Chess_size);
array[x][y] = "white";
array_win[getXY(y)][getXY(x)] = -1;
state = true;
}
if (Win(getXY(y), getXY(x)) == 1) {
result = new Result(1);
result.initUI();
} else if (Win(getXY(y), getXY(x)) == -1) {
result = new Result(-1);
result.initUI();
}
for (int i = 0; i < 15; i++) {
for (int j = 0; j < 15; j++) {
System.out.print(array_win[i][j] + " ");
}
System.out.println("");
}
System.out.println("");
}
}
/*
* 人机对战
*/
else if (ActListener.GameModel == 2) {
if (x < 582 && x > 10 && y < 582 && y > 10 && array[x][y] == null) {
g.setColor(Color.BLACK);
g.fillOval(x - WZQ_config.Chess_size / 2, y
- WZQ_config.Chess_size / 2, WZQ_config.Chess_size,
WZQ_config.Chess_size);
array[x][y] = "black";
array_win[getXY(y)][getXY(x)] = 1;
array_pve[getXY(y)][getXY(x)] = 0;
for (int i = 0; i < 15; i++) {
for (int j = 0; j < 15; j++) {
System.out.print(array_pve[i][j] + " ");
}
System.out.println("");
}
System.out.println("");
}
}
}
/*
* 下棋位置坐标修正的方法
*/
public int correctXY(int x) {
x = x / 40;
return x * 40;
}
public int getXY(int x) {
x = x / 40;
return x;
}
/*
* 判赢方法
*/
/*
* 判定横向五个相连
*/
public boolean winRow(int row, int column) {
int count = 1;
for (int i = column + 1; i < 15; i++) {// 向右查找
if (array_win[row][column] == array_win[row][i]) {
count++;
} else
break;
}
for (int i = column - 1; i >= 0; i--) {// 向左查找
if (array_win[row][column] == array_win[row][i]) {
count++;
} else
break;
}
if (count >= 5) {
return true;
} else
return false;
}
/*
* 判定竖向五个相连
*/
public boolean winColumn(int row, int column) {
int count = 1;
for (int i = row + 1; i < 15; i++) {// 向右查找
if (array_win[row][column] == array_win[i][column]) {
count++;
} else
break;
}
for (int i = row - 1; i >= 0; i--) {// 向左查找
if (array_win[row][column] == array_win[i][column]) {
count++;
} else
break;
}
if (count >= 5) {
return true;
} else
return false;
}
/*
* 判定斜向右下五个相连
*/
public boolean winRightDown(int row, int column) {
int count = 1;
for (int i = column + 1, j = row + 1; i < 15 && j < 15; i++, j++) {// 向右查找
if (array_win[row][column] == array_win[j][i]) {
count++;
} else
break;
}
for (int i = column - 1, j = row - 1; i >= 0 && j >= 0; i--, j--) {// 向左查找
if (array_win[row][column] == array_win[j][i]) {
count++;
} else
break;
}
if (count >= 5) {
return true;
} else
return false;
}
/*
* 判定斜向左下五个相连
*/
public boolean winLeftDown(int row, int column) {
int count = 1;
for (int i = column - 1, j = row + 1; i >=0 && j < 15; i--, j++) {// 向右查找
if (array_win[row][column] == array_win[j][i]) {
count++;
} else
break;
}
for (int i = column + 1, j = row - 1; i <15 && j >= 0; i++, j--) {// 向左查找
if (array_win[row][column] == array_win[j][i]) {
count++;
} else
break;
}
if (count >= 5) {
return true;
} else
return false;
}
public int Win(int row, int column) {
if (winRow(row, column) || winColumn(row, column)
|| winRightDown(row, column) || winLeftDown(row, column)) {
if (array_win[row][column] == 1)
return 1;
else if (array_win[row][column] == -1)
return -1;
}
return 0;
}
}
最后还有一点可以完善的,就是我所做的是判断有五连之后又会弹出一个新的界面,上面提示某某子五连,某某子获得胜利。同时提供两个按钮选择重新开始或者退出。~
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.AbstractButton;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Result extends JFrame{
int i;
JPanel panel;
public Result(int i){
this.i = i;
}
/*
* 定义一个生成界面的方法
*/
public void initUI(){
this.setTitle("结果");
this.setSize(new Dimension(400,200));
this.setLocationRelativeTo(null);
this.setResizable(false);
this.setLayout(new BorderLayout());
this.setDefaultCloseOperation(HIDE_ON_CLOSE);
panel = new JPanel();
panel.setLayout(new FlowLayout());
this.add(panel,BorderLayout.CENTER);
if(i == 1){
JLabel lab = new JLabel("黑子五连,黑子胜!");
panel.add(lab,BorderLayout.CENTER);
}
else if(i == -1){
JLabel lab = new JLabel("白子五连,白子胜!");
panel.add(lab);
}
JPanel pal = new JPanel();
JButton btn_restart = new JButton("重新开始");
JButton btn_exit = new JButton("退出游戏");
btn_restart.setActionCommand("restart");
btn_exit.setActionCommand("exit");
ActListener al = new ActListener();
btn_restart.addActionListener(al);
btn_exit.addActionListener(al);
btn_restart.addMouseListener(al);
btn_exit.addMouseListener(al);
pal.setLayout(new FlowLayout());
this.add(pal,BorderLayout.SOUTH);
pal.add(btn_restart);
pal.add(btn_exit);
this.setVisible(true);
}
}
这样,这个人人对战的五子棋可以说是就完成了。~~人机的之后会在完善的!
有缺点不足麻烦指出~~#^_^。谢谢各位看的盆友~~~~~
最后附一张效果图哈: