java实现AI五子棋

       这是学习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<Integer> xlist = new LinkedList<>();
	private LinkedList<Integer> 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<Integer> xlist, ylist;
	private String name;
	private MainUI ui;
	private int[][] chessArray;
	private Boolean gameOver = false;

	public ChessListener() {
	}
	//构造函数传参
	public ChessListener(MainUI ui, LinkedList<Integer> xlist, LinkedList<Integer> 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<Integer> xlist;
	private LinkedList<Integer> ylist;

	public Chess() {
	}

	public Chess(Graphics g, int[][] chessArray, LinkedList<Integer> xlist, LinkedList<Integer> 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<Integer> xlist;
	private LinkedList<Integer> 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<Integer> xlist, LinkedList<Integer> 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<Integer> xlist;
	private LinkedList<Integer> ylist;
	private int[][] chessValue = new int[15][15];
	private HashMap<String, Integer> hm = new HashMap<>();

	public Robot() {
	}
	
	public Robot(int[][] chessArray, LinkedList<Integer> xlist, LinkedList<Integer> 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:如电脑执黑先手时更注重防守了,再如棋局判断时只单独判断一个方向等等,所以此版本的人机对战仅供娱乐了~后续会有五子棋算法篇更新。

猜你喜欢

转载自blog.csdn.net/LIAO_7053/article/details/81072140