这是学习Java以来自己设计的第一款小游戏,虽然整体设计有点粗糙,电脑智能也比较低,不过也能满足基本需求,心里还是有点小激动。至于更高深的算法及其他功能的实现只能等以后再实现了。好了,闲话少述,咱们直奔主题吧!
先上一张效果图:
一、五子棋设计要求:
1、设计一个能够实现双人对战及人机对战的五子棋游戏;
2、游戏可实现悔棋及认输等基本操作;
3、设计时尽量满足面向对象基本原则;
二、五子棋设计思路:
类:
1、五子棋主界面 数据处理中心
调用绘制棋盘、绘制棋子方法,
键盘控制指令
2、棋子监听器类 提供棋子的坐标及二维数组(颜色) put: xlist,ylist,chessArray[i][j]
提供通过按钮事件获取的操作指令 put: name
需要控制指令gameOver锁定监听器 get: Boolean gameOver
需要主界面对象调用控制方法 get: MainUI ui
3、棋盘类 重绘方法中调用,绘制棋盘,需要画笔g get:g
4、棋子类 绘制棋子方法(坐标及颜色) get:g, chessArray[][],xlist,ylist;
5、判断输赢 需要当前点坐标 ,棋子二维数组 get: chessArray[][],xlist,ylist;
put:gameOver
弹出消息提示框
6、Robot 计算各点位置权值 ,需要棋子二维数组 get: chessArray[][],xlist,ylist
put: xlist,ylist
7、常数接口类
三、五子棋设计说明:
1、执黑先行;
2、本次设计的权值算法较为简单,存在较为明显的缺陷;
四、代码实现
主界面
package com.Liao.FiveChess0705.v1;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.util.LinkedList;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class MainUI extends JFrame {
private static final long serialVersionUID = 1L;
private int[][] chessArray = new int[15][15];
private LinkedList xlist = new LinkedList<>();
private LinkedList ylist = new LinkedList<>();
private Chess ch;
private CheckChess cc;
private ChessListener cl;
private JOptionPane pane;
private ChessTable ct;
private Robot rt;
private Graphics g;
private Boolean isRobot = false;
public void initUI() {
this.setTitle("五子棋.Liao");
this.setSize(760, 670);
// 设置居中
this.setLocationRelativeTo(null);
// 设置大小不可调
this.setResizable(false);
// 设置窗体退出
this.setDefaultCloseOperation(3);
// 设置边界布局
this.setLayout(new BorderLayout());
// 在窗体右方添加JPanel容器
JPanel jp = new JPanel();
jp.setPreferredSize(new Dimension(100, 750));
jp.setBackground(new Color(180, 100, 100));
this.add(jp, BorderLayout.EAST);
//创建监听器对象
cl = new ChessListener(this, xlist, ylist, chessArray);
String[] buttonArray = { "重新开始", "我方先手", "电脑先手", "悔棋", "认输" };
for (int i = 0; i < buttonArray.length; i++) {
JButton jbu = new JButton(buttonArray[i]);
jbu.setBackground(Color.orange);
jbu.setPreferredSize(new Dimension(90, 30));
jbu.addActionListener(cl);
jp.add(jbu);
}
this.addMouseListener(cl);
this.setVisible(true);
//获取画笔
g = this.getGraphics();
//创建棋子对象
ch = new Chess(g, chessArray, xlist, ylist);
//创建判断方法对象
cc = new CheckChess(chessArray, xlist, ylist);
}
// 绘制棋子
public void drawChess() {
//调用绘棋方法
ch.drawChess();
//判断输赢
cc.judge();
//设置gameOver变量
if (cc.getGameOver()) {
cl.setGameOver(cc.getGameOver());
}
//判断是否人机对战
if (!cc.getGameOver()) {
if (isRobot) {
rt = new Robot(chessArray, xlist, ylist);
//计算各空位权值
rt.AI();
//获取权值最高的坐标
rt.getMax();
//下棋
ch.drawChess();
//清除权值
rt.clearValue();
//判断输赢
cc.judge();
}
}
}
// 重绘方法
public void paint(Graphics g) {
super.paint(g);
ct = new ChessTable(g);
// 重绘棋盘
ct.drawChessTable();
// 重绘棋子
ch.drawChess(g);
}
// 控制指令
public void control(String name) {
if ("重新开始".equals(name)) {
isRobot = false;
cl.setGameOver(false);
cc.setGameOver();
//清除存储数据
xlist.clear();
ylist.clear();
for (int i = 0; i < chessArray.length; i++) {
for (int j = 0; j < chessArray[i].length; j++) {
chessArray[i][j] = 0;
}
}
this.repaint();
}
if ("我方先手".equals(name)) {
isRobot = true;
}
if ("电脑先手".equals(name)) {
isRobot = true;
xlist.add(7);
ylist.add(7);
chessArray[7][7] = 1;
ch.drawChess();
}
if ("悔棋".equals(name)) {
cl.setGameOver(false);
cc.setGameOver();
chessArray[xlist.getLast()][ylist.getLast()] = 0;
xlist.removeLast();
ylist.removeLast();
this.repaint();
}
if ("认输".equals(name)) {
cl.setGameOver(true);
if (xlist.size() % 2 == 0) {
JOptionPane.showMessageDialog(pane, "白棋胜!");
} else {
JOptionPane.showMessageDialog(pane, "黑棋胜!");
}
}
}
// 主函数
public static void main(String[] args) {
MainUI mi = new MainUI();
mi.initUI();
}
}
常数接口类
package com.Liao.FiveChess0705.v1;
public interface Config {
public static final int X0=50;
public static final int Y0=65;
public static final int ROWS=15;
public static final int COLUMNS=15;
public static final int SIZE=40;
public static final int CHESS_SIZE=30;
}
棋盘类
package com.Liao.FiveChess0705.v1;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.ImageIcon;
public class ChessTable implements Config {
private Graphics g;
ImageIcon p0 = new ImageIcon(this.getClass().getResource("p0.png"));
public ChessTable() {
}
public ChessTable(Graphics g) {
super();
this.g = g;
}
public void drawChessTable() {
g.drawImage(p0.getImage(), 0, 20, 660, 650, null);
g.setColor(Color.black);
// 绘制棋盘横线
for (int i = 0; i < ROWS; i++) {
g.drawLine(X0, Y0 + i * SIZE, X0 + (COLUMNS - 1) * SIZE, Y0 + i * SIZE);
}
// 绘制棋盘竖线
for (int i = 0; i < COLUMNS; i++) {
g.drawLine(X0 + i * SIZE, Y0, X0 + i * SIZE, Y0 + (ROWS - 1) * SIZE);
}
}
}
监听器类
package com.Liao.FiveChess0705.v1;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.LinkedList;
public class ChessListener extends MouseAdapter implements ActionListener, Config {
private LinkedList xlist, ylist;
private String name;
private MainUI ui;
private int[][] chessArray;
private Boolean gameOver = false;
public ChessListener() {
}
//构造函数传参
public ChessListener(MainUI ui, LinkedList xlist, LinkedList ylist, int[][] chessArray) {
super();
this.ui = ui;
this.xlist = xlist;
this.ylist = ylist;
this.chessArray = chessArray;
}
//设置gameOver
public void setGameOver(Boolean gameOver) {
this.gameOver = gameOver;
}
//获取控制指令
public String getName() {
return name;
}
public void actionPerformed(ActionEvent e) {
name = e.getActionCommand();
//调用控制方法
ui.control(name);
}
public void mouseReleased(MouseEvent e) {
if (!gameOver) {
int x = e.getX();
int y = e.getY();
for (int i = 0; i < COLUMNS; i++) {
for (int j = 0; j < ROWS; j++) {
int x1 = X0 + SIZE * i;
int y1 = Y0 + SIZE * j;
if (x > x1 - SIZE / 2 && x < x1 + SIZE / 2 && y > y1 - SIZE / 2 && y < y1 + SIZE / 2) {
// 判断位置是否有棋子
if (chessArray[i][j] == 0) {
xlist.add(i);
ylist.add(j);
// System.out.println(xlist.size() + " i:" + i + "
// j:" + j);
if (xlist.size() % 2 == 1) {
chessArray[i][j] = 1;
}
if (xlist.size() % 2 == 0) {
chessArray[i][j] = 2;
}
ui.drawChess();
}
}
}
}
}
}
}
棋子类:
package com.Liao.FiveChess0705.v1;
import java.awt.Color;
import java.awt.Graphics;
import java.util.LinkedList;
public class Chess implements Config {
private int[][] chessArray;
private Graphics g;
private LinkedList xlist;
private LinkedList ylist;
public Chess() {
}
public Chess(Graphics g, int[][] chessArray, LinkedList xlist, LinkedList ylist) {
super();
this.g = g;
this.chessArray = chessArray;
this.xlist = xlist;
this.ylist = ylist;
}
// 绘棋方法
public void drawChess(int x, int y, Color color) {
g.setColor(color);
g.fillOval(X0 + x * SIZE - CHESS_SIZE / 2, Y0 + y * SIZE - CHESS_SIZE / 2, CHESS_SIZE, CHESS_SIZE);
}
// 绘制棋子
public void drawChess() {
// 判断队列是否中是否有棋子
System.out.println(xlist.size());
if (xlist.size() != 0) {
if (xlist.size() % 2 == 1) {
drawChess(xlist.getLast(), ylist.getLast(), Color.black);
}
if (xlist.size() % 2 == 0) {
drawChess(xlist.getLast(), ylist.getLast(), Color.white);
}
}
}
// 重绘棋子
public void drawChess(Graphics g) {
for (int i = 0; i < chessArray.length; i++) {
for (int j = 0; j < chessArray[i].length; j++) {
if (chessArray[i][j] == 1) {
// System.out.println("绘制黑棋");
drawChess(i, j, Color.black);
}
if (chessArray[i][j] == 2) {
// System.out.println("绘制白棋");
drawChess(i, j, Color.white);
}
}
}
}
}
判断输赢
package com.Liao.FiveChess0705.v1;
import java.util.LinkedList;
import javax.swing.JOptionPane;
public class CheckChess implements Config {
private volatile int[][] chessArray;
private LinkedList xlist;
private LinkedList ylist;
private Boolean gameOver = false;
private JOptionPane pane = new JOptionPane();
public Boolean getGameOver() {
return gameOver;
}
public void setGameOver() {
this.gameOver = false;
}
public CheckChess(int[][] chessArray, LinkedList xlist, LinkedList ylist) {
this.chessArray = chessArray;
this.xlist = xlist;
this.ylist = ylist;
}
public void judge() {
// 水平方向
int count = 1;
for (int i = xlist.getLast() + 1; i < COLUMNS; i++) {
if (chessArray[i][ylist.getLast()] == chessArray[xlist.getLast()][ylist.getLast()]) {
count++;
} else {
break;
}
}
for (int i = xlist.getLast() - 1; i > -1; i--) {
if (chessArray[i][ylist.getLast()] == chessArray[xlist.getLast()][ylist.getLast()]) {
count++;
} else {
break;
}
}
if (count >= 5) {
gameOver = true;
if (chessArray[xlist.getLast()][ylist.getLast()] == 1) {
JOptionPane.showMessageDialog(pane, "黑棋胜!");
}
if (chessArray[xlist.getLast()][ylist.getLast()] == 2) {
JOptionPane.showMessageDialog(pane, "白棋胜!");
}
}
// 竖直方向
count = 1;
for (int j = ylist.getLast() + 1; j < ROWS; j++) {
if (chessArray[xlist.getLast()][j] == chessArray[xlist.getLast()][ylist.getLast()]) {
count++;
} else {
break;
}
}
for (int j = ylist.getLast() - 1; j > -1; j--) {
if (chessArray[xlist.getLast()][j] == chessArray[xlist.getLast()][ylist.getLast()]) {
count++;
} else {
break;
}
}
if (count >= 5) {
gameOver = true;
if (chessArray[xlist.getLast()][ylist.getLast()] == 1) {
JOptionPane.showMessageDialog(pane, "黑棋胜!");
}
if (chessArray[xlist.getLast()][ylist.getLast()] == 2) {
JOptionPane.showMessageDialog(pane, "白棋胜!");
}
}
// 右斜向上方向
count = 1;
for (int i = xlist.getLast() + 1, j = ylist.getLast() - 1; i < COLUMNS && j > -1; i++, j--) {
if (chessArray[i][j] == chessArray[xlist.getLast()][ylist.getLast()]) {
count++;
} else {
break;
}
}
for (int i = xlist.getLast() - 1, j = ylist.getLast() + 1; i > -1 && j < ROWS; i--, j++) {
if (chessArray[i][j] == chessArray[xlist.getLast()][ylist.getLast()]) {
count++;
} else {
break;
}
}
if (count >= 5) {
gameOver = true;
if (chessArray[xlist.getLast()][ylist.getLast()] == 1) {
JOptionPane.showMessageDialog(pane, "黑棋胜!");
}
if (chessArray[xlist.getLast()][ylist.getLast()] == 2) {
JOptionPane.showMessageDialog(pane, "白棋胜!");
}
}
// 右斜向下方向
count = 1;
for (int i = xlist.getLast() + 1, j = ylist.getLast() + 1; i < COLUMNS && j < ROWS; i++, j++) {
if (chessArray[i][j] == chessArray[xlist.getLast()][ylist.getLast()]) {
count++;
} else {
break;
}
}
for (int i = xlist.getLast() - 1, j = ylist.getLast() - 1; i > -1 && j > -1; i--, j--) {
if (chessArray[i][j] == chessArray[xlist.getLast()][ylist.getLast()]) {
count++;
} else {
break;
}
}
if (count >= 5) {
gameOver = true;
if (chessArray[xlist.getLast()][ylist.getLast()] == 1) {
JOptionPane.showMessageDialog(pane, "黑棋胜!");
}
if (chessArray[xlist.getLast()][ylist.getLast()] == 2) {
JOptionPane.showMessageDialog(pane, "白棋胜!");
}
}
}
}
Robot类
package com.Liao.FiveChess0705.v1;
import java.util.HashMap;
import java.util.LinkedList;
public class Robot implements Config {
private int c, d;
private int[][] chessArray;
private LinkedList xlist;
private LinkedList ylist;
private int[][] chessValue = new int[15][15];
private HashMap hm = new HashMap<>();
public Robot() {
}
public Robot(int[][] chessArray, LinkedList xlist, LinkedList ylist) {
super();
this.chessArray = chessArray;
this.xlist = xlist;
this.ylist = ylist;
setValue();
}
//设置权值
public void setValue() {
// 白色
hm.put("2", 13);
hm.put("22", 130);
hm.put("222", 1300);
hm.put("2222", 11000);
hm.put("21", 11);
hm.put("221", 110);
hm.put("2221", 1100);
hm.put("22221", 11000);
// 黑色
hm.put("1", 12);
hm.put("11", 120);
hm.put("111", 1200);
hm.put("1111", 10000);
hm.put("12", 10);
hm.put("112", 100);
hm.put("1112", 1000);
hm.put("11112", 10000);
}
//判断棋局
public void AI() {
for (int i = 0; i < COLUMNS; i++) {
for (int j = 0; j < ROWS; j++) {
// 当前位置为空
if (chessArray[i][j] == 0) {
// 向右判断
String code = "";
int color = 0;
for (int m = i + 1, n = j; m < COLUMNS; m++) {
// 下一位为空则跳出
if (chessArray[m][n] == 0) {
break;
} else {
// 判断是否为第一颗棋子
if (color == 0) {
color = chessArray[m][n];
code += chessArray[m][n];
} else {
// 判断颜色是否相同
if (color == chessArray[m][n]) {
code += chessArray[m][n];
} else {
code += chessArray[m][n];
break;
}
}
}
}
Integer value = hm.get(code);
if (value != null) {
chessValue[i][j] += value;
}
// 向左判断
code = "";
color = 0;
for (int m = i - 1, n = j; m > -1; m--) {
// 下一位为空则跳出
if (chessArray[m][n] == 0) {
break;
} else {
// 判断是否为第一颗棋子
if (color == 0) {
color = chessArray[m][n];
code += chessArray[m][n];
} else {
// 判断颜色是否相同
if (color == chessArray[m][n]) {
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, n = j - 1; n > -1; n--) {
// 下一位为空则跳出
if (chessArray[m][n] == 0) {
break;
} else {
// 判断是否为第一颗棋子
if (color == 0) {
color = chessArray[m][n];
code += chessArray[m][n];
} else {
// 判断颜色是否相同
if (color == chessArray[m][n]) {
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, n = j + 1; n < ROWS; n++) {
// 下一位为空则跳出
if (chessArray[m][n] == 0) {
break;
} else {
// 判断是否为第一颗棋子
if (color == 0) {
color = chessArray[m][n];
code += chessArray[m][n];
} else {
// 判断颜色是否相同
if (color == chessArray[m][n]) {
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 < COLUMNS && n > -1; m++, n--) {
// 下一位为空则跳出
if (chessArray[m][n] == 0) {
break;
} else {
// 判断是否为第一颗棋子
if (color == 0) {
color = chessArray[m][n];
code += chessArray[m][n];
} else {
// 判断颜色是否相同
if (color == chessArray[m][n]) {
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 < COLUMNS && n < ROWS; m++, n++) {
// 下一位为空则跳出
if (chessArray[m][n] == 0) {
break;
} else {
// 判断是否为第一颗棋子
if (color == 0) {
color = chessArray[m][n];
code += chessArray[m][n];
} else {
// 判断颜色是否相同
if (color == chessArray[m][n]) {
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 > -1 && n > -1; m--, n--) {
// 下一位为空则跳出
if (chessArray[m][n] == 0) {
break;
} else {
// 判断是否为第一颗棋子
if (color == 0) {
color = chessArray[m][n];
code += chessArray[m][n];
} else {
// 判断颜色是否相同
if (color == chessArray[m][n]) {
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 > -1 && n < ROWS; m--, n++) {
// 下一位为空则跳出
if (chessArray[m][n] == 0) {
break;
} else {
// 判断是否为第一颗棋子
if (color == 0) {
color = chessArray[m][n];
code += chessArray[m][n];
} else {
// 判断颜色是否相同
if (color == chessArray[m][n]) {
code += chessArray[m][n];
} else {
code += chessArray[m][n];
break;
}
}
}
}
value = hm.get(code);
if (value != null) {
chessValue[i][j] += value;
}
}
}
}
// 输出权值表
/*
* for (int i = 0; i < COLUMNS; i++) { for (int j = 0; j < ROWS; j++) {
* System.out.print(chessValue[i][j] + "\t"); } System.out.println(); }
*/
}
//获取最大权值坐标
public void getMax() {
int n = 0, max = 0;
for (int i = 0; i < COLUMNS; i++) {
for (int j = 0; j < ROWS; j++) {
if (chessValue[i][j] != 0) {
if (n == 0) {
max = chessValue[i][j];
c = i;
d = j;
n++;
} else {
if (chessValue[i][j] > max) {
max = chessValue[i][j];
c = i;
d = j;
}
}
}
}
}
System.out.println("c d" + c + " " + d);
xlist.add(c);
ylist.add(d);
if (xlist.size() % 2 == 1) {
chessArray[c][d] = 1;
} else {
chessArray[c][d] = 2;
}
}
// 下完棋后清空chessValue
public void clearValue() {
for (int i = 0; i < COLUMNS; i++) {
for (int j = 0; j < ROWS; j++) {
chessValue[i][j] = 0;
}
}
}
}
小结:
此次设计,重点放在了面向对象设计思想(人机部分除外)及五子棋基本功能的实现上,对算法研究非常浅,所以给出的权值表也比较粗糙,存在明显bug:如电脑执黑先手时更注重防守了,再如棋局判断时只单独判断一个方向等等,所以此版本的人机对战仅供娱乐了~后续会有五子棋算法篇更新。