这是我第一次做个人项目,虽然难度不大,但也还是花了挺多时间的。
第一步建立了棋子类,用于定义棋子。
import java.awt.Color;
import java.awt.Graphics;
public class Chess implements ChessInterface {
protected Color color;
public int x, y;
public Chess(int x, int y, Color color) {
this.x = x;
this.y = y;
this.color = color;
}
public void draw(Graphics g) {
g.setColor(color);
g.fillOval(X + x * Size - Size / 2, Y + y * Size - Size / 2, Size, Size);
}
}
第二步画棋盘,同时将监听器也进行绑定,我将监听器绑定在了按键而非棋盘上。重写paint方法用于重绘。这里要注意的一点是,最好创建一个接口保存棋盘的间距、行数、列数等信息,方便之后修改。同时在这个接口中,还声明了一个二维数组用于保存棋局(棋子的颜色)。第二个二维数组是之后人机对战用到的,之后再详述。棋盘代码如下:
public class ChessPane extends JPanel implements ChessInterface {
/**
*
*/
private static final long serialVersionUID = 1L;
Chess chess[] = new Chess[100];
public static void main(String[] args) {
ChessPane chesspanel = new ChessPane();
chesspanel.showUI();
}
// 创建窗体对象
public void showUI() {
JFrame jf = new JFrame();
jf.setSize(800, 660);
jf.setTitle("五子棋");
// 设置进程的方法
jf.setDefaultCloseOperation(3);
// 设置居中显示
jf.setLocationRelativeTo(null);
jf.getContentPane().setBackground(Color.WHITE);
jf.setLayout(new BorderLayout());
// this.setBackground(Color.BLUE);
jf.add(this, BorderLayout.CENTER);
JPanel pan = new JPanel();
pan.setBackground(Color.DARK_GRAY);
pan.setPreferredSize(new Dimension(150, 0));
jf.add(pan, BorderLayout.EAST);
// 添加监听器
ChessListener mouse = new ChessListener();
this.addMouseListener(mouse);
mouse.setC(chess);
mouse.setP(this);
String button[] = { "开始游戏", "悔 棋", "认 输", "人机对战", "双人对战" };
for (int i = 0; i < button.length; i++) {
JButton jbu = new JButton(button[i]);
pan.add(jbu);
jbu.addActionListener(mouse);
}
jf.setVisible(true);
Graphics g = this.getGraphics();
mouse.setGr(g);
}
public void paint(Graphics g) {
super.paint(g);
// 画棋盘
for (int i = 0; i < 15; i++) {
g.drawLine(X, Y + i * Size, X + (Coloum - 1) * Size, Y + i * Size);
g.drawLine(X + i * Size, Y, X + i * Size, Y + (Row - 1) * Size);
}
// 画棋子
for (int i = 0; i < chess.length; i++) {
Chess ch = chess[i];
if (ch != null)
ch.draw(g);
}
}
}
接口代码:
public interface ChessInterface {
//棋子和棋盘的大小
public static final int Size=40;
public static final int X=30;
public static final int Y=30;
public static final int Row=15;
public static final int Coloum=15;
//存棋子
public static final int[][]array=new int[Row][Coloum];
public static final int[][]chessValue=new int[Row][Coloum];
}
接下来是监听器部分,由于功能比较多,所以写的有些混乱,请多包涵。
几个功能的实现思想如下:
1)双人对战:通过监听器获取点击坐标,但是要注意把坐标进行转换,才能让棋子落在棋盘的交叉点处。通过一个num变量用于计数,从而判定棋子的颜色。用filloval函数绘制棋子,注意的是要将棋子保存进数组,因为要进行重绘。(事实上,每下一颗棋子就进行了一次重绘)。
2)开始游戏:这个按钮的意思是重新开始游戏,其实只要明白“下子就是重绘”这一原理,就很好解决了。只需要将保存棋子的数组清空,棋盘就无法进行重绘,也就是重新开始新的一轮游戏了。
3)悔棋:悔棋的原理同 2),之前提到用num来计数,只需要更改num值,就能对数组中保存的值进行修改,也就是对棋局进行修改。
4)人机对战:人机对战有很多种实现方式,小白采用的是最简单的权值表法,也就是遍历整个棋盘,根据之前设定的权值生成每一个位置的权值表,选取权值最大的位置下子。这里又创建了一个二维数组,用于存储每个格子的权值。
首先,设立权值;然后,根据权值建立每个可能位置的权值表(八个方位,权值进行累加);通过循环找到权值最大的位置,然后下子(这里要注意的是,不同的方向要记得及时把之前累加的权值清零。);下子之后,把整个棋盘的权值表清零(二维数组清零)这里还有一个小细节,由于我把监听器绑定在按键上,所以是通过获取按键上的字符串来判断当前的功能的,建议还是将不同的功能写成函数进行调用,这样就能提高代码复用。可以通过设定一个变量来控制代码的运行。
package com.fzj.Chess0421;
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 java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.HashMap;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class ChessListener extends MouseAdapter
implements ChessInterface, MouseListener, ActionListener, MouseMotionListener {
private int x, y, i = 0;
private Graphics g;
private int num = 0;
Chess[] chess;
private String str;
Color chessc;
CheckWin win = new CheckWin();
ChessPane cp;
public void setGr(Graphics gr) {
g = gr;
}
public void setC(Chess[] c) {
chess = c;
}
public void setP(ChessPane p) {
cp = p;
}
public void mouseReleased(MouseEvent e) {
x = e.getX();
y = e.getY();
int row = 1;
int line = 1;
// 判断棋子的位置
int a = (x - X) / Size;// 取商
int b = (x - X) % Size;// 取余数
if (b <= (Size / 2)) {
row = a;
} else {
row = a + 1;
}
int c = (y - Y) / Size;// 取商
int d = (y - Y) % Size;// 取余数
if (d <= (Size / 2)) {
line = c;
} else {
line = c + 1;
}
if (array[row][line] == 0) {
if (num % 2 == 0) {
g.setColor(Color.black);
array[row][line] = 1;
} else {
g.setColor(Color.white);
array[row][line] = 2;
}
g.fillOval(X + row * Size - Size / 2, Y + line * Size - Size / 2, Size, Size);
Chess ch = new Chess(row, line, g.getColor());
chess[num] = ch;
num++;
if (i == 1) {
AI();
}
win.isWin(row, line);
}
}
public void restart(){
for (int i = 0; i < chess.length; i++) {
chess[i] = null;
}
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array.length; j++) {
array[i][j] = 0;
}
}
num = 0;
cp.paint(g);
}
public void actionPerformed(ActionEvent e) {
str = e.getActionCommand();
if ("开始游戏".equals(str)) {
restart();
}
if ("悔 棋".equals(str)) {
if(i==2){
if (num > 0) {
num--;
x = chess[num].x;
y = chess[num].y;
array[x][y] = 0;
chess[num] = null;
cp.repaint();
}}
}
if ("人机对战".equals(str)) {
restart();
i = 1;
// 人先下(黑子),并判断输赢
// AI();
}
if ("双人对战".equals(str)) {
restart();
i = 0;
// 人先下(黑子),并判断输赢
// AI();
}
}
HashMap hm = new HashMap();
public ChessListener() {
//black
hm.put("1", 10);
hm.put("11", 100);
hm.put("111", 5000);
hm.put("1111", 8000);
hm.put("12", 5);
hm.put("112", 80);
hm.put("1112", 3000);
hm.put("11112", 10000);
hm.put("21", 11);
hm.put("211", 110);
hm.put("2111", 1100);
hm.put("21111", 11000);
//white
hm.put("2", 20);
hm.put("22", 200);
hm.put("222", 4500);
hm.put("2222", 10000);
hm.put("221", 100);
hm.put("2221", 3000);
hm.put("22221", 12000);
hm.put("122", 5);
hm.put("1222", 500);
hm.put("12222", 10000);
}
public void AI() {
// 人先下(黑子),并判断输赢
// 建立权值
// 水平方向
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
if (array[i][j] == 0) {
String code = "";
int color = 0;
// 向右
for (int k = i + 1; k < array.length; k++) {
if (array[k][j] == 0) {
break;
} else {
if (color == 0) {
color = array[k][j];
code += array[k][j];
} else if (array[k][j] == color) {
code += array[k][j];
} else {
code += array[k][j];
break;
}
}
}
// 根据code取出对应的权值
Integer value1 = hm.get(code);
if (value1 != null) {
chessValue[i][j] += value1;
}
// 向左
code = "";
color = 0;
// 向左
for (int k = i; k > 0; k--) {
if (array[k][j] == 0) {
break;
} else {
if (color == 0) {
color = array[k][j];
code += array[k][j];
} else if (array[k][j] == color) {
code += array[k][j];
} else {
code += array[k][j];
break;
}
}
}
value1 = hm.get(code);
if (value1 != null) {
chessValue[i][j] += value1;
}
// 垂直方向
// 向上
color = 0;
code = "";
for (int k = j + 1; k < array.length; k++) {
if (array[i][k] == 0) {
break;
} else {
if (color == 0) {
color = array[i][k];
code += array[i][k];
} else if (array[i][k] == color) {
code += array[i][k];
} else {
code += array[i][k];
break;
}
}
}
// 根据code取出对应的权值
Integer value11 = hm.get(code);
if (value11 != null) {
chessValue[i][j] += value11;
}
// 向下
color = 0;
code = "";
for (int k = j; k > 0; k--) {
if (array[i][k] == 0) {
break;
} else {
if (color == 0) {
color = array[i][k];
code += array[i][k];
} else if (array[i][k] == color) {
code += array[i][k];
} else {
code += array[i][k];
break;
}
}
}
value1 = hm.get(code);
if (value1 != null) {
chessValue[i][j] += value1;
}
code = "";
color = 0;
//右斜
//向下
for (int k = 0; k < (array.length - i)&&k<(array.length-j); k++) {
if (array[i + k][j + k] == 0) {
break;
} else {
if (color == 0) {
color = array[i + k][j + k];
code += array[i + k][j + k];
} else if (array[i + k][j + k] == color) {
code += array[i + k][j + k];
} else {
code += array[i + k][j + k];
break;
}
}
}
value1 = hm.get(code);
if (value1 != null) {
chessValue[i][j] += value1;
}
code = "";
color = 0;
// 向上
for (int k = 0; (j - k) > 0 && (i - k) > 0; k++) {
if (array[i - k][j - k] == 0) {
break;
} else {
if (color == 0) {
color = array[i - k][j - k];
code += array[i - k][j - k];
} else if (array[i - k][j - k] == color) {
code += array[i - k][j - k];
} else {
code += array[i - k][j - k];
break;
}
}
}
value1 = hm.get(code);
if (value1 != null) {
chessValue[i][j] += value1;
}
code = "";
color = 0;
// 向下
for (int k = 0; (i - k) > 0 && k > (array.length - j); k++) {
if (array[i - k][j + k] == 0) {
break;
} else {
if (color == 0) {
color = array[i - k][j + k];
code += array[i - k][j + k];
} else if (array[i - k][j + k] == color) {
code += array[i - k][j + k];
} else {
code += array[i - k][j + k];
break;
}
}
}
value1 = hm.get(code);
if (value1 != null) {
chessValue[i][j] += value1;
}
code = "";
color = 0;
//
for (int k = 0; k < (array.length - i) && (j - k) > 0; k++) {
if (array[i + k][j - k] == 0) {
break;
} else {
if (color == 0) {
color = array[i + k][j - k];
code += array[i + k][j - k];
} else if (array[i + k][j - k] == color) {
code += array[i + k][j - k];
} else {
code += array[i + k][j - k];
break;
}
}
}
value1 = hm.get(code);
if (value1 != null) {
chessValue[i][j] += value1;
}
}
}
}
// 找到权值最大的位置,并下子
int max = 0;
int x1 = 0;
int y1 = 0;
for (int a = 0; a < chessValue.length; a++) {
for (int b = 0; b < chessValue.length; b++) {
if (chessValue[a][b] > max) {
max = chessValue[a][b];
x1 = a;
y1 = b;
}
}
}
for (int a = 0; a < chessValue.length; a++) {
for (int b = 0; b < chessValue.length; b++) {
System.out.print(chessValue[a][b] + " ");
}
System.out.println();
}
System.out.println();
// System.out.println("x1="+x1+" y1="+y1);
g.setColor(Color.white);
g.fillOval(X + x1 * Size - Size / 2, Y + y1 * Size - Size / 2, Size, Size);
array[x1][y1] = 2;
Chess ch = new Chess(x1, y1, Color.white);
chess[num] = ch;
num++;
win.isWin(x1, y1);
// 清空权值表
for (int a = 0; a < chessValue.length; a++) {
for (int b = 0; b < chessValue.length; b++) {
chessValue[a][b] = 0;
}
}
}
}
接下来,也是比较重要的一步,判断输赢,我专门建立了一个类用于判断输赢,只需要创建一个对象,就能调用判定的方法。其实判定其实很简单,用一个变量进行计数,再采用一个循环,同色则+1,异色或无子则break,也是对八个方位进行判定,代码如下:
import javax.swing.JOptionPane;
public class CheckWin implements ChessInterface {
public void isWin(int x,int y){
if(horizontal(x,y)>=5||vertical(x,y)>=5||westnorth(x,y)>=5||eastnorth(x,y)>=5){
if(array[x][y]==1)
JOptionPane.showMessageDialog(null, "black win");
else if(array[x][y]==2)
JOptionPane.showMessageDialog(null, "white win");
}
}
public int horizontal(int x, int y) {
int count = 0;
for (int i = x + 1; i < array.length; i++) {
if (array[i][y] == array[x][y]) {
count++;
} else
break;
}
for (int i = x; i >= 0; i--) {
if (array[i][y] == array[x][y]) {
count++;
} else
break;
}
return count;
}
public int vertical(int x, int y) {
int count = 0;
for (int i = y + 1; i < array.length; i++) {
if (array[x][i] == array[x][y]) {
count++;
} else
break;
}
for (int i = y; i >= 0; i--) {
if (array[x][i] == array[x][y]) {
count++;
} else
break;
}
return count;
}
public int westnorth(int x, int y) {
int count = 0;
for (int i = 0; i <(array.length-x)&&i<(array.length-x); i++) {
if (array[x+i][y+i] == array[x][y]) {
count++;
} else
break;
}
for (int i = 1; (x-i)>=0&&(y-i)>=0; i++) {
if (array[x-i][y-i] == array[x][y]) {
count++;
} else
break;
}
return count;
}
public int eastnorth(int x, int y) {
int count = 0;
for (int i = 0; i <(array.length-x)&&(y-i)>0; i++) {
if (array[x+i][y-i] == array[x][y]) {
count++;
} else
break;
}
for (int i = 1; (x-i)>=0&&i <(array.length-y); i++) {
if (array[x-i][y+i] == array[x][y]) {
count++;
} else
break;
}
return count;
}
}
至此,一个简陋的五子棋就完成了。