在本模块五子棋的开发中,主要实现以下几个功能:
(1)人人对战
(2)悔棋、重新开始
(3)人机对战
我们就按以上几个顺序进行阐述。
(1)绘制棋盘
在设计五子棋之前,我们需要的首要任务就是绘制棋盘,在绘制棋盘时我们需要考虑这几个问题:棋盘的大小,棋盘横竖线的条数以及单元格的大小、左上角起始点的位置,同时需要在可视化界面出现时就存在棋盘。那我们怎么去完成呢?
第一个问题:在可视化界面出现时就存在棋盘。
我们知道画笔是在界面出现后才能获取画笔对象,界面显示以JFrame中setVisible(ture)方法结尾,在界面未出现之前是不可以调用画笔对象的。因此获取画笔对象必须在setVisible(ture)之后出现。同时,要保证界面出现时就存在棋盘,必须采用JFrame类中的paint(Graphics g)方法进行重绘。
第二个问题: 绘制棋盘时棋盘的大小,棋盘横竖线的条数以及单元格的大小、左上角起始点的位置以及后期保存棋子的大小都是固定的,那我们该如何在后期方便的修改和调整这些参数值呢?
其实对于这个问题,我们有一个较好的方法,也就是定义一个接口类Config,将这些固定量写在接口中,让类去继承这个接口。
(2)实现人人对战
在这里我们要思考的问题有以下几个:
第一个问题:如何实现鼠标点击某处实现在距离该点击位置最近的位置落棋?
首先需要对窗体添加鼠标监听,在这里我们要关注一下鼠标监听的两个方式,类 MouseAdapter和其继承的接口MouseListener,在这里我选择MouseAdapter,为什么呢?因为重写继承类,只需对那个类中那个方法进行重写,而接口类重写必须将其所有方法显示后使用,比较麻烦。
接下来新建一个名为chessListener的类,让其继承MouseAdapter。
在类中写下棋子的方法。重写MouseAdapter中的mouseClicked(MouseEvent e)方法,即鼠标单击首先获取窗体上的某点坐标,当然这个点坐标不一定在交点处,那我们就需要将棋子下在离其最近的交叉点。这里我们采取这样的一个方法,见下图。点击点坐标为(x,y),左上角第一个交点为(x0,y0),我们用(x-x0)/每格大小的余数与每格大小/2进行比较,当其小于每格大小/2时我们将棋子下在点击点的左交点,否则,右交点。同样的,我们用(y-y0)/每格大小的余数与每格大小/2进行比较,当其小于每格大小/2时我们将棋子下在点击点的上交点。
第二个问题:怎么去确定其下棋子黑白交替,并保证所下棋子不能棋子重复下在同一位置?
可以采用计数的方式。即计数为0,表示其交叉点无棋子,计数为奇数,表示下黑棋,奇数为偶数,下白棋。
定义一个二维数组来存储每个交叉点棋子状态。
接下来需要对棋子进行重绘。
第三个问题:如何判断输赢?
我们知道判断输赢就看哪中颜色棋子首先达到五子相连。若果黑棋先达到五子相连,则黑棋赢,否则,白棋赢。也就是我们在下每个棋子时都要判断它的八个方向的棋子相连个数,见下图。如果判断某一方向与其相邻点的颜色相同,将循环计数。如果不相同,则跳出循环。最后统计四条线上的相邻相同棋子的个数。在这里我们需要注意边界点的范围,在循环的时候注意设置边界条件。新建一个名为Win的类,并在类中写判断输赢的方法。
(3)实现悔棋、重新开始
问题1:如何实现悔棋?
要实现悔棋,那么我们首先需要在窗体上添加一个悔棋按钮,并添加动作监听器,并在悔棋时依次寻找到最后一个棋子的位置,这就需要再定义两个一维数组在每次落子后存入坐标点来依次存储每次白棋和黑棋的位置。然后在每次点击按钮时,if (“悔棋”.equals(e.getActionCommand())),将取出最后一个棋子的坐标点的棋子号,并将其赋值为0。最后进行重绘,特别注意要将FiveChess类中的重绘传过来,调用paint的子类方法repaint()。
注意:设置范围。Index减小最小值要大于等于0。
问题2:如何重新开始?
将棋盘的所有坐标棋子号都归零。然后重写方法。
(4)实现人机对战
问题1:怎么让电脑能确定所下位置呢?
采用权值法进行。即对每一种棋子分布情况附权值分数,最后将分数进行累加,索引全部坐标点的权值,权值分数最大者所在位置即棋子落棋点。
那么用什么建立起棋子布局情况与权值分数一一对应关系呢?
可以采用Hashmap(哈希表)。
Hashmap是一个散列表,它存储的内容是键值对(key-value)映射。
1.创建权值表:HashMap
<>:泛型(泛指类:类,接口,数组)
在这里,String和Integer是引用数据类型。为封装的类。
2.获取Key对应的value。用get()方法。
value = hm.get(code);
在这里,code代表key。
问题2:怎么解决人先下,判断输赢?
在chessListener中,添加人机大战按钮响应,设置mode变量来确定是人机大战还是人人对战;然后再代表人先画,然后调用AI()方法,传入画笔和数组。
问题3:搜索棋盘上棋局情况,设置权值
首先需要定义一个chessValue数组来保存棋盘上的权值;接下来两个循环遍历找到无棋子点的位置,再在位置上搜索其八个方向是否有权值,若下一个紧挨着点无棋子,跳出,有棋子,则保存这个点的颜色和当前棋局情况;继续进行搜索,若紧接着点的颜色与上一个相同,则同样保存此时的棋局情况,若不相同则跳出循环;再根据棋局保存情况,通过Hashmap的get()方法得到其Key对应的value值。每个方向权值进行相加,最后得到最终权值。接下来搜索chessValue权值,得到最大权值所在位置。最后在权值最大位置处将其位置点的chessArray赋值为2,代表白棋已存入。最后再把所有chessValue清空。
代码如下:
FiveChess类:
package com.wej.fivechess1207;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import javax.swing.JButton;
import javax.swing.JFrame;
public class FiveChess extends JFrame implements Config{
private static final long serialVersionUID = 1L;
private int[][] chessArray=new int[rows][columns];
public static void main(String[] args) {
FiveChess fc=new FiveChess();
fc.intoUI();
}
public void intoUI(){
this.setTitle("五子棋界面");
this.setSize(length, wide);
// this.setResizable(false);
this.setDefaultCloseOperation(3);
this.setLocationRelativeTo(null);
this.getContentPane().setBackground(Color.yellow);
FlowLayout flow=new FlowLayout();
this.setLayout(flow);
JButton bu_reset=new JButton("悔棋");
this.add(bu_reset);
JButton bu_reStart=new JButton("重新开始");
this.add(bu_reStart);
JButton bu_r2r=new JButton("人人对战");
this.add(bu_r2r);
JButton bu_r2m=new JButton("人机对战");
this.add(bu_r2m);
this.setVisible(true);
Graphics g=this.getGraphics();//获取画笔对象
chessListener ch=new chessListener(g,chessArray,this);
this.addMouseListener(ch);
bu_reset.addActionListener(ch);
bu_reStart.addActionListener(ch);
bu_r2r.addActionListener(ch);
bu_r2m.addActionListener(ch);
// System.out.println("chessArray="+chessArray);
}
//重绘
public void paint(Graphics g){
super.paint(g);//调用父类的重写方法
drawChessTable(g);
}
public void drawChessTable(Graphics g){
for(int i=0;i<rows;i++){
g.drawLine(x0, y0+i*size, x0+(Config.columns-1)*size, y0+i*size);
}
for(int j=0;j<columns;j++){
g.drawLine(x0+j*size, y0, x0+j*size, y0+(rows-1)*size);
}
paintChess(g);
}
public void paintChess(Graphics g){
for(int i=0;i<chessArray.length;i++){
for(int j=0;j<chessArray.length;j++){
if(chessArray[i][j]==1){
g.setColor(Color.black);
g.fillOval(x0+i*size-chess_size/2, y0+j*size-chess_size/2, chess_size, chess_size);
}
if(chessArray[i][j]==2){
g.setColor(Color.white);
g.fillOval(x0+i*size-chess_size/2, y0+j*size-chess_size/2, chess_size, chess_size);
}
}
}
// for(int i=0;i
// for(int j=0;j
// System.out.print(" "+chessArray[i][j]);
// }
// System.out.println();
// }
}
}
chessListener类
package com.wej.fivechess1207;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
public class chessListener extends MouseAdapter implements Config,
ActionListener {
private int x, y, xx, yy;
private Graphics g;
private int count;
private int[][] chessArray = new int[rows][columns];
private Win win;
private int[] heng = new int[100];
private int[] shu = new int[100];
private int index = 0;
private JFrame paint;
private int mode;
AI1 al;
public chessListener(Graphics g, int[][] chessArray, JFrame paint) {
this.g = g;
this.chessArray = chessArray;
win = new Win(chessArray);
this.paint = paint;
al = new AI1(chessArray, g); //因为要传入画笔和数组,所以只能在构造函数中定义对象,供窗体使用。
}
public void mouseClicked(MouseEvent e) {
x = e.getX();
y = e.getY();
if ((x - x0) % size > size / 2) {
xx = (x - x0) / size + 1;
} else {
xx = (x - x0) / size;
}
if ((y - y0) % size > size / 2) {
yy = (y - y0) / size + 1;
} else {
yy = (y - y0) / size;
}
if (mode == 1) {
if (chessArray[xx][yy] == 0) { // 等于0代表空白,可以执行
if (count % 2 == 0) {
g.setColor(Color.black);
chessArray[xx][yy] = 1; // 代表黑棋已存入
} else {
g.setColor(Color.white);
chessArray[xx][yy] = 2; // 代表白棋已存入
}
count++;
g.fillOval(x0 + xx * size - chess_size / 2, y0 + yy * size
- chess_size / 2, chess_size, chess_size);
win.isWin(xx, yy);
}
}
if (mode == 2) {
g.setColor(Color.black);
chessArray[xx][yy] = 1; // 代表黑棋已存入
g.fillOval(x0 + xx * size - chess_size / 2, y0 + yy * size
- chess_size / 2, chess_size, chess_size);
win.isWin(xx, yy);
// System.out.println("x="+xx);
// System.out.println("y="+yy);
al.AI();
// for (int i = 0; i < chessArray.length; i++) {
// for (int j = 0; j < chessArray.length; j++){
// System.out.print(chessArray[j][i]+" ");
// }
// System.out.println();
// }
// System.out.println();
}
heng[index] = xx;
shu[index] = yy;
index++;
}
public void actionPerformed(ActionEvent e) {
if ("人人对战".equals(e.getActionCommand())) {
mode = 1;
}
if ("人机对战".equals(e.getActionCommand())) {
mode = 2;
}
index--;
if (index >= 0) {
if ("悔棋".equals(e.getActionCommand())) {
// System.out.println("index="+index);
chessArray[heng[index]][shu[index]] = 0;
paint.repaint();
}
if ("重新开始".equals(e.getActionCommand())) {
// System.out.println("index="+index);
for (int i = 0; i < chessArray.length; i++) {
for (int j = 0; j < chessArray.length; j++)
chessArray[i][j] = 0;
}
paint.repaint();
}
} else {
index = 0;
}
}
}
Config类
package com.wej.fivechess1207;
public interface Config {
public static final int x0=50;//表格左上角起点
public static final int y0=70;//
public static final int rows=15; //横向线条数
public static final int columns=15;//纵向线条数
public static final int chess_size=30;//棋子直径
public static final int size=40;//单元格大小
public static final int length=800; //屏幕长
public static final int wide=800;// 屏幕宽
}
Win类
package com.wej.fivechess1207;
import javax.swing.JOptionPane;
public class Win {
private int[][] chessArray;
public Win(int[][] chessArray) {
this.chessArray = chessArray;
}
public void isWin(int x, int y) {
if (dp(x, y) >= 5 || sp(x, y) >= 5||sxp(x, y) >= 5||xxp(x, y) >= 5) {
if (chessArray[x][y] == 1) {
JOptionPane.showMessageDialog(null, "黑棋赢");
}
if (chessArray[x][y] == 2) {
JOptionPane.showMessageDialog(null, "白棋赢");
}
}
}
// 横
public int dp(int x, int y) {
int count = 1;
for (int i = x + 1; i < chessArray.length; i++) {
if (chessArray[x][y] == chessArray[i][y]) {
count++;
} else {
break;
}
}
for (int i = x-1; i >= 0; i--) {
if (chessArray[i][y] == chessArray[x][y]) {
count++;
} else {
break;
}
}
return count;
}
public int sp(int x, int y) {
int count = 1;
for (int i = y + 1; i < chessArray.length; i++) {
if (chessArray[x][i] == chessArray[x][y]) {
count++;
} else {
break;
}
}
for (int i = y-1; i >= 0; i--) {
if (chessArray[x][i] == chessArray[x][y]) {
count++;
} else {
break;
}
}
return count;
}
public int sxp(int x, int y) {
int count = 1;
for (int i = x + 1, j = y + 1; i < chessArray.length
&& j < chessArray.length; i++,j++) {
if (chessArray[i][j] == chessArray[x][y]) {
count++;
} else {
break;
}
}
for (int i = x-1, j = y-1 ; i >= 0 && j >=0; i--,j--) {
if (chessArray[i][j] == chessArray[x][y]) {
count++;
} else {
break;
}
}
return count;
}
public int xxp(int x, int y) {
int count = 1;
for (int i = x + 1, j = y - 1; i < chessArray.length && j >=0; i++,j--) {
if (chessArray[i][j] == chessArray[x][y]) {
count++;
} else {
break;
}
}
for (int i = x - 1, j = y + 1; i >= 0 && j < chessArray.length; i--,j++) {
if (chessArray[i][j] == chessArray[x][y]) {
count++;
} else {
break;
}
}
return count;
}
}
AI1类
package com.wej.fivechess1207;
import java.awt.Color;
import java.awt.Graphics;
import java.util.HashMap;
public class AI1 implements Config {
private int[][] chessArray = new int[rows][columns];
private int[][] chessValue = new int[rows][columns];
HashMap<String, Integer> hm = new HashMap<String, Integer>();
private Graphics g;
private Win win;
public AI1(int[][] chessArray, Graphics g) {
this.chessArray = chessArray;
this.g = g;
win = new Win(chessArray);
hm.put("1", 20);
hm.put("11", 200);
hm.put("111", 1000);
hm.put("1111", 2000);
hm.put("12", 20);
hm.put("112", 200);
hm.put("1112", 1000);
hm.put("11112", 2000);
hm.put("2", 20);
hm.put("22", 200);
hm.put("222", 1000);
hm.put("2222", 2000);
hm.put("21", 20);
hm.put("221", 200);
hm.put("2221", 1000);
hm.put("22221", 2000);
}
public void AI() {
for (int i = 0; i < chessArray.length; i++) {
for (int j = 0; j < chessArray.length; j++) {
if (chessArray[i][j] == 0) {
String code = "";
int color = 0;
for (int k = i + 1; k <chessArray.length; k++) { // 向下
if (chessArray[k][j] == 0) {
break;
} else {
if (color == 0) { // 下面第一颗棋子
color = chessArray[k][j]; // 保存颜色
code += chessArray[k][j]; // 保存棋局
} else if (chessArray[k][j] == color) { // 下面相同颜色
code += chessArray[k][j];
} else { // 下面不同颜色
code += chessArray[k][j];
break;
}
}
}
Integer value = hm.get(code);
if (value != null) {
chessValue[i][j] = +value;
// 归零
code = "";
color = 0;
}
for (int k = i - 1; k>=0; k--) { // 向上
if (chessArray[k][j] == 0) {
break;
} else {
if (color == 0) { // 下面第一颗棋子
color = chessArray[k][j]; // 保存颜色
code += chessArray[k][j]; // 保存棋局
} else if (chessArray[k][j] == color) { // 下面相同颜色
code += chessArray[k][j];
} else { // 下面不同颜色
code += chessArray[k][j];
break;
}
}
}
value = hm.get(code);
if (value != null) {
chessValue[i][j] = +value;
// 归零
code = "";
color = 0;
}
for (int k = j + 1; k <chessArray.length; k++) { // 向右
if (chessArray[i][k] == 0) {
break;
} else {
if (color == 0) { // 下面第一颗棋子
color = chessArray[i][k]; // 保存颜色
code += chessArray[i][k]; // 保存棋局
} else if (chessArray[i][k] == color) { // 下面相同颜色
code += chessArray[i][k];
} else { // 下面不同颜色
code += chessArray[i][k];
break;
}
}
}
value = hm.get(code);
if (value != null) {
chessValue[i][j] = +value;
// 归零
code = "";
color = 0;
}
for (int k = j - 1; k>=0; k--) { // 向左
if (chessArray[i][k] == 0) {
break;
} else {
if (color == 0) { // 下面第一颗棋子
color = chessArray[i][k]; // 保存颜色
code += chessArray[i][k]; // 保存棋局
} else if (chessArray[i][k] == color) { // 下面相同颜色
code += chessArray[i][k];
} else { // 下面不同颜色
code += chessArray[i][k];
break;
}
}
}
value = hm.get(code);
if (value != null) {
chessValue[i][j] = +value;
// 归零
code = "";
color = 0;
}
for (int m = i + 1, n = j + 1; m <chessArray.length
&&n <chessArray.length; m++, n++) { // 右下
if (chessArray[m][n] == 0) {
break;
} else {
if (color == 0) { // 下面第一颗棋子
color = chessArray[m][n]; // 保存颜色
code += chessArray[m][n]; // 保存棋局
} else if (chessArray[m][n] == color) { // 下面相同颜色
code += chessArray[m][n];
} else { // 下面不同颜色
code += chessArray[m][n];
break;
}
}
}
value = hm.get(code);
if (value != null) {
chessValue[i][j] = +value;
// 归零
code = "";
color = 0;
}
for (int m = i - 1, n = j - 1; m >=0&&n>=0; m--, n--) { // 左上
if (chessArray[m][n] == 0) {
break;
} else {
if (color == 0) { // 下面第一颗棋子
color = chessArray[m][n]; // 保存颜色
code += chessArray[m][n]; // 保存棋局
} else if (chessArray[m][n] == color) { // 下面相同颜色
code += chessArray[m][n];
} else { // 下面不同颜色
code += chessArray[m][n];
break;
}
}
}
value = hm.get(code);
if (value != null) {
chessValue[i][j] = +value;
// 归零
code = "";
color = 0;
}
for (int m = i + 1, n = j - 1; m <chessArray.length
&&n>=0; m++, n--) { // 左下
if (chessArray[m][n] == 0) {
break;
} else {
if (color == 0) { // 下面第一颗棋子
color = chessArray[m][n]; // 保存颜色
code += chessArray[m][n]; // 保存棋局
} else if (chessArray[m][n] == color) { // 下面相同颜色
code += chessArray[m][n];
} else { // 下面不同颜色
code += chessArray[m][n];
break;
}
}
}
value = hm.get(code);
if (value != null) {
chessValue[i][j] = +value;
// 归零
code = "";
color = 0;
}
for (int m = i - 1, n = j + 1; m>=0
&& n <chessArray.length; m--, n++) { // 右上
if (chessArray[m][n] == 0) {
break;
} else {
if (color == 0) { // 下面第一颗棋子
color = chessArray[m][n]; // 保存颜色
code += chessArray[m][n]; // 保存棋局
} else if (chessArray[m][n] == color) { // 下面相同颜色
code += chessArray[m][n];
} else { // 下面不同颜色
code += chessArray[m][n];
break;
}
}
}
value = hm.get(code);
if (value != null) {
chessValue[i][j] = +value;
}
}
}
}
// 找出最大值所在位置
int max = 0;
int c = 0;
int r = 0;
for (int i = 0; i < chessValue.length; i++) {
for (int j = 0; j < chessValue.length; j++) {
if (chessValue[i][j] >= max) {
max = chessValue[i][j];
c = i;
r = j;
}
}
}
g.setColor(Color.white);
chessArray[c][r] = 2; // 代表白棋已存入
// System.out.println("c="+c);
// System.out.println("r="+r);
// System.out.println("c="+c);
// System.out.println("g=" + g);
g.fillOval(x0 + c * size - chess_size / 2, y0 + r * size - chess_size
/ 2, chess_size, chess_size);
win.isWin(c, r);
// for (int i = 0; i < chessArray.length; i++) {
// for (int j = 0; j < chessArray.length; j++){
// System.out.print(chessValue[j][i]+" ");
// }
// System.out.println();
// }
// System.out.println();
for (int i = 0; i < chessArray.length; i++) {
for (int j = 0; j < chessArray.length; j++){
chessValue[i][j]=0;
// System.out.print(chessValue[j][i]+" ");
}
// System.out.println();
}
// System.out.println();
// array[0]=c;
// array[1]=r;
// return array;
}
}