ZBLOG

Good Luck To You!

简易五子棋的实现

五子棋实现功能:

1、黑白棋交替下,进行正常的五子棋的输赢判断;

2、实现重新开始游戏清屏、悔棋(不限步数)、认输、人机对战、人人对战(手动交替下黑白棋)


五子棋实现效果:

棋盘界面


五子棋设计简述

ps: 类分少了可能代码可读性有些差


“两个类 一个接口”


先说接口:

这个接口的使用其实就是将一些常用的变量定义,之后在改变的时候方便改变值,使用时只要implements这个接口即可。上图可能更明显。


主要谈谈类

一、界面类(含主函数)

里面有4个方法:

1、main方法 :初始化一个对象,调用对象的 initUI()函数。

2、public void initUI()方法:显示界面,Jframe上放两块画布,一块画棋盘(继承JPanel得): 横竖线,一块安各种操作按钮(new):重新开始,悔棋等等。

3、public void paint (Graphics g)方法:重绘功能,调用super.paint()就是为了除了绘制你需要定制的line之外,还要保证绘制这个组件自身的其它元素!因为在刷新、覆盖等操作中,这个组件需要被重新绘制。
paint()方法的调用是awt线程来控制的,jvm提供了这样一个线程来管理组件的各种工作。一旦这个组件被某个其它窗口覆盖之后,或者最小化最大化的过程中,组件本身都会接到awt的重绘事件申请,组件便调用paint()方法来绘制自身和add到组件之上的各种对象。
也就是说一旦发生变化,自动调用paint()进行重绘!


因为以上原理,所以我们需要在这个函数里重绘:窗体+棋盘(横竖线)+棋子(是否下棋用二维数组形式存储)

4、private void drawChessTable(Graphics g) 方法:循环画横竖线


二、监听类(核心操作部分)

在对棋盘上落子鼠标释放、在对”重新开始“”认输“等按钮点击操作等都进行监听处理。

三大部分:

1、在对”重新开始“”认输“等按钮点击棋盘上落子鼠标释放

2、棋盘上落子鼠标释放棋盘上落子鼠标释放

3、判断人机对战算法——权值法(基础、理论是好的,要设计出合适的有效的 a little difficult)


1、在对”重新开始“”认输“等按钮点击棋盘上落子鼠标释放方法

name = e.getActionCommand();得到按钮上的字符串,然后嘞,就根据name内容不同,利用if...else...结构进行不同的x处理。值得注意的是里面y需要调用paint()方法,方法是通过对象调用的,所以记得要把界面类中的对象传来,不能在此类直接新建一个对象来调用。

悔棋利用了数组队列存储点,可以进行不限步数的悔棋,重绘界面更新等。

2、棋盘上落子鼠标释放棋盘上落子鼠标释放

分人人对战与人机对战两部分,详细说下人人对战

黑白子交替下,其中有两个难点:1、下棋,棋子要下在棋盘的十字交叉处;2、要做好存储,不能重复下,要交替下。针对1,则是需要计算找出要下的地方的坐标,填充个圆形那个出来,画的时候,不同的设置画笔颜色白黑交替设置。针对2,利用二维数组存储,黑子存1,白子存-1。

每下完一个棋就要判断该位置,横,竖,斜右、斜左4个方向上有没有连成5个一样的,若果有,就游戏结束。

3、判断人机对战算法——权值法

权值法,设置一定的规则,计算可以下的位置的权值,找出权值最大的位置下棋。

我这个权值法还是雏形,有点笨,还待更新。

对每个位置的8个方向进行检索,每个方向得到的棋盘情况可以对应规则得到一个value值,所有valueh值加就是这个位置的最终权值。用一个chessValue[][]存储权值,遍历找到最大权值处,在此位置上下棋。


五子棋实现详情(代码注释ing)

Config.java(接口)

package Chesses;

public interface Config {
	public static final int X0=100;   //表格左上角起点的x值
	public static final int Y0=100;    //表格左上角起点的y值
	public static final int ROWS=11;   //横向线条数
	public static final int COLUMNS=11;   //纵向线条数
	public static final int CHESS_SIZE=80;   //棋子直径
	public static final int SIZE=100;         //单元格的大小
}

FiveChessUI.java(界面类)

package Chesses;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;

import Draw.shape;

public class FiveChessUI extends JPanel  implements Config {
	
	private int chesses[][]= new int[ROWS][COLUMNS];
	static FiveChessUI fcUI=new FiveChessUI();
		//主函数
	public static void main(String args[]) {
		
		fcUI.initUI();
	}
	
	
	//
	public void initUI() {
		ChessListener cl=new ChessListener();
		
		JFrame jf=new JFrame();
		jf.setTitle("五子棋");
		jf.setSize(1500, 1400);
		jf.setDefaultCloseOperation(3);
		jf.setVisible(true);
		
		 
		//棋盘的画布
		//Graphics g = this.getGraphics();
		this.setBackground(Color.orange);
		this.setPreferredSize(new Dimension(1000,400));
		
		
		
		//安操作按钮的jp
		JPanel jp=new JPanel();
		jp.setBackground(Color.gray);
		jp.setPreferredSize(new Dimension(300,400));
		
		String st[]= {"重新开始","认输","悔棋"};
		for(int i=0;i<st.length;i++) {
			JButton jb= new JButton(st[i]);
			jb.setFont(new Font("宋体", Font.BOLD, 20));
			jb.setPreferredSize(new Dimension(200,100));
			jp.add(jb);
			jb.addActionListener(cl);
		}
		
		JComboBox jcb = new JComboBox();
		jcb.setPreferredSize(new Dimension(200,100));
		jcb.setFont(new Font("宋体", Font.BOLD, 25));
		//jcb.set
		jcb.addItem("人人对战");
		jcb.addItem("人机对战");
		
		
		jp.add(jcb);
		jcb.addActionListener(cl);
		
		
		
		jf.add(this,BorderLayout.CENTER);
		jf.add(jp,BorderLayout.EAST);
		jf.setVisible(true);
		
		//监听器
		Graphics g = this.getGraphics();   //画笔在界面可见后获取

		
		cl.setg(g);
		cl.setc(chesses);
		cl.sets(fcUI);
		cl.setj(jcb);
		this.addMouseListener(cl);
		
		
	}
	
	public void paint (Graphics g)
	{   //重绘窗体
		super.paint(g);
		//重绘窗体同时绘制棋盘
		drawChessTable(g);
		//重绘棋子
		for(int j=0;j< ROWS;j++) {
    		for(int i=0;i< COLUMNS;i++) {
    			if(chesses[i][j]==1) {
    				g.setColor(Color.BLACK);
    				int x= X0+ SIZE*i; //横坐标
	    			int y= Y0+ SIZE*(j); //纵坐标
	    			g.fillOval(x-CHESS_SIZE/2,y-CHESS_SIZE/2,CHESS_SIZE,CHESS_SIZE);
    			}else if(chesses[i][j]==-1) {
    				g.setColor(Color.white);
    				int x= X0+ SIZE*i; //横坐标
	    			int y= Y0+ SIZE*(j); //纵坐标
	    			g.fillOval(x-CHESS_SIZE/2,y-CHESS_SIZE/2,CHESS_SIZE,CHESS_SIZE);
    			}
    			
    		}
    		}
		
	}

	private void drawChessTable(Graphics g) {
		//画棋盘横线
		for(int i=0;i< ROWS;i++) {
			g.drawLine( X0,  Y0+i* SIZE,  X0+( 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);
			
		}
		
	}
	
	
	
	
}

ChessListener.java(监听类)

package Chesses;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.HashMap;

import javax.swing.JComboBox;
import javax.swing.JOptionPane;

public class ChessListener extends MouseAdapter implements Config, ActionListener {
	private String name = null, name1 = "人人对战";
	private boolean game = true;
	private Graphics g;
	private int count = 0, r = 0, l = 0, max = 0;
	private int[][] chesses;
	private int[][] chessValue = new int[ROWS][COLUMNS];
	FiveChessUI fc = new FiveChessUI();
	private JComboBox jcb;
	int num = 0;
	 ArrayList<Point> list = new ArrayList<Point>();
	

	HashMap<String, Integer> hm = new HashMap<String, Integer>();

	public void hash() {
		hm.put("1", 20);
		hm.put("11", 200);
		hm.put("111", 2000);
		hm.put("1111", 3000);

		hm.put("1-1", 10);
		hm.put("11-1", 100);
		hm.put("111-1", 1000);
		hm.put("1111-1", 2000);
	}
//传参
	public void setg(Graphics g) {
		this.g = g;
	}

	public void setc(int[][] chesses) {
		this.chesses = chesses;
	}

	public void sets(FiveChessUI fc) {
		this.fc = fc;
	}

	public void setj(JComboBox jcb) {
		this.jcb = jcb;
	}

	public void mouseReleased(MouseEvent e) {

		if ("人人对战".equals(name1)) {
			// 得到鼠标事件发生时光标的位置
			int x1 = e.getX();
			int y1 = e.getY();

			// 按行遍历棋盘,坐标(i,j)
			for (int j = 0; j < ROWS; j++) {
				for (int i = 0; i < COLUMNS; i++) {
					// 得到交叉点的坐标
					int x = X0 + SIZE * i; // 横坐标
					int y = Y0 + SIZE * j; // 纵坐标
					// 得到交叉点的行列

					// 与圆心的误差为size/3
					if (x1 > x - SIZE / 2 && x1 < x + SIZE / 2 && y1 > y - SIZE / 2 && y1 < y + SIZE / 2 && game) {
						if (chesses[i][j] == 0) {

							if (count == 0) {
								chesses[i][j] = 1; // 黑子为1
								Point p=new Point();
								p.setLocation(i, j);
								
								list.add(p);
								g.setColor(Color.black);
								count++;
							} else {
								chesses[i][j] = -1; // 白子为-1
								Point p=new Point();
								p.setLocation(i, j);
								list.add(p);
								g.setColor(Color.white);
								count--;
							}
							// 画棋子
							g.fillOval(x - CHESS_SIZE / 2, y - CHESS_SIZE / 2, CHESS_SIZE, CHESS_SIZE);

							this.win(i, j);

						}

					}
				}
			}
		} else if ("人机对战".equals(name1)) {
			// 得到鼠标事件发生时光标的位置
			int x1 = e.getX();
			int y1 = e.getY();
			// 按行遍历棋盘,坐标(i,j)
			for (int j = 0; j < ROWS; j++) {
				for (int i = 0; i < COLUMNS; i++) {
					// 得到交叉点的坐标
					int x = X0 + SIZE * i; // 横坐标
					int y = Y0 + SIZE * j; // 纵坐标
					// 得到交叉点的行列

					// 与圆心的误差为size/3
					if (x1 > x - SIZE / 2 && x1 < x + SIZE / 2 && y1 > y - SIZE / 2 && y1 < y + SIZE / 2 && game) {
						if (chesses[i][j] == 0) {
							// 人下黑棋子
							if (count == 0) {
								chesses[i][j] = 1; // 黑子为1
								Point p=new Point();
								p.setLocation(i, j);
								list.add(p);
								g.setColor(Color.black);
								count++;
							}
							// 画棋子
							g.fillOval(x - CHESS_SIZE / 2, y - CHESS_SIZE / 2, CHESS_SIZE, CHESS_SIZE);
							this.win(i, j);
						}
					}
				}
			}
			////////////////////////////////////////////////////////////
			// 机器画白棋子
			// 找到value最大的位置的i j
			// while(true) {
			if (game) {
				this.count();

				for (int j = 0; j < ROWS; j++) {
					for (int i = 0; i < COLUMNS; i++) {
						if (chessValue[i][j] > max) {
							max = chessValue[i][j];
							r = i;
							l = j;

						}
					}
				}

				// System.out.println(r + " "+l);
				// for(int i=0;i<11;i++)
				// for(int j=0;j<11;j++) {
				// System.out.print(chessValue[i][j]+" ");
				// num++;
				// if(num==11) {
				// System.out.println(" ");
				// num=0;
				// }
				// }

				// 清空
				for (int i = 0; i < ROWS; i++) {
					for (int j = 0; j < COLUMNS; j++)
						chessValue[i][j] = 0;
				}
				max = 0;
				// 最大位置是(r,l)
				if (count == 1) {
					g.setColor(Color.white);
					Point p=new Point();
					p.setLocation(r, l);
					list.add(p);
					chesses[r][l] = -1; // 机器下白子
					count--;
				}
				g.fillOval(X0 + SIZE * r - CHESS_SIZE / 2, Y0 + SIZE * l - CHESS_SIZE / 2, CHESS_SIZE, CHESS_SIZE);
				this.win(r, l);
			}
			// }
		} // 人机

	}// 释放

	public void count() {

		for (int i = 0; i < chesses.length; i++) {
			for (int j = 0; j < chesses[i].length; j++) {
				// 判断当前是否为空
				if (chesses[i][j] == 0) {
					// 搜索该空位八个方向上棋局情况,并计算value值
					// 定义两个变量分别保存棋局,以及颜色
					String code = "";
					int color = 0;

					// 向下方向
					for (int k = i + 1; k < ROWS; k++) {
						if (chesses[k][j] == 0) { // 下一个为空就停止匹配
							break;
						} else {
							if (color == 0) { // 下面的第1颗棋子
								color = chesses[k][j]; // 保存颜色
								code += chesses[k][j]; // 保存棋局
							} else if (chesses[k][j] == color) { // 下边第2/3/4...同颜色棋子
								code += chesses[k][j]; // 保存棋局
							} else { // 下边第2/3/4....不同颜色
								code += chesses[k][j]; // 保存棋局
								break;
							}
						}
					}
					// 根据code取出hm对应的权值
					Integer value = hm.get(code);
					if (value != null) {
						chessValue[i][j] += value; // 权值
					}
					code = "";
					color = 0;

					// 向上方向
					for (int k = i - 1; k >= 0; k--) {
						if (chesses[k][j] == 0) { // 下一个为空就停止匹配
							break;
						} else {
							if (color == 0) { // 下面的第1颗棋子
								color = chesses[k][j]; // 保存颜色
								code += chesses[k][j]; // 保存棋局
							} else if (chesses[k][j] == color) { // 右边第2/3/4...同颜色棋子
								code += chesses[k][j]; // 保存棋局
							} else { // 下边第2/3/4....不同颜色
								code += chesses[k][j]; // 保存棋局
								break;
							}
						}
					}
					// 根据code取出hm对应的权值
					Integer value1 = hm.get(code);
					if (value1 != null) {
						chessValue[i][j] += value1; // 权值
					}
					code = "";
					color = 0;

					// 向右方向
					for (int k = j + 1; k < COLUMNS; k++) {
						if (chesses[i][k] == 0) { // 下一个为空就停止匹配
							break;
						} else {
							if (color == 0) { // 下面的第1颗棋子
								color = chesses[i][k]; // 保存颜色
								code += chesses[i][k]; // 保存棋局
							} else if (chesses[i][k] == color) { // 右边第2/3/4...同颜色棋子
								code += chesses[i][k]; // 保存棋局
							} else { // 下边第2/3/4....不同颜色
								code += chesses[i][k]; // 保存棋局
								break;
							}
						}
					}
					// 根据code取出hm对应的权值
					Integer value2 = hm.get(code);
					if (value2 != null) {
						chessValue[i][j] += value2; // 权值
					}
					code = "";
					color = 0;

					// 向左方向
					for (int k = j - 1; k >= 0; k--) {
						if (chesses[i][k] == 0) { // 下一个为空就停止匹配
							break;
						} else {
							if (color == 0) { // 下面的第1颗棋子
								color = chesses[i][k]; // 保存颜色
								code += chesses[i][k]; // 保存棋局
							} else if (chesses[i][k] == color) { // 右边第2/3/4...同颜色棋子
								code += chesses[i][k]; // 保存棋局
							} else { // 下边第2/3/4....不同颜色
								code += chesses[i][k]; // 保存棋局
								break;
							}
						}
					}
					// 根据code取出hm对应的权值
					Integer value3 = hm.get(code);
					if (value3 != null) {
						chessValue[i][j] += value3; // 权值
					}
					code = "";
					color = 0;

					// 向左上方向
					for (int k = j - 1, l = i - 1; k >= 0 && l >= 0; k--, l--) {

						if (chesses[l][k] == 0) { // 下一个为空就停止匹配
							break;
						} else {
							if (color == 0) { // 下面的第1颗棋子
								color = chesses[l][k]; // 保存颜色
								code += chesses[l][k]; // 保存棋局
							} else if (chesses[l][k] == color) { // 右边第2/3/4...同颜色棋子
								code += chesses[l][k]; // 保存棋局
							} else { // 下边第2/3/4....不同颜色
								code += chesses[l][k]; // 保存棋局
								break;
							}
						}
					}
					// 根据code取出hm对应的权值
					Integer value4 = hm.get(code);
					if (value4 != null) {
						chessValue[i][j] += value4; // 权值
					}
					code = "";
					color = 0;

					// 向左下方向
					for (int k = j - 1, l = i + 1; k >= 0 && l < ROWS; k--, l++) {

						if (chesses[l][k] == 0) { // 下一个为空就停止匹配
							break;
						} else {
							if (color == 0) { // 下面的第1颗棋子
								color = chesses[l][k]; // 保存颜色
								code += chesses[l][k]; // 保存棋局
							} else if (chesses[l][k] == color) { // 右边第2/3/4...同颜色棋子
								code += chesses[l][k]; // 保存棋局
							} else { // 下边第2/3/4....不同颜色
								code += chesses[l][k]; // 保存棋局
								break;
							}
						}
					}
					// 根据code取出hm对应的权值
					Integer value5 = hm.get(code);
					if (value5 != null) {
						chessValue[i][j] += value5; // 权值
					}
					code = "";
					color = 0;

					// 向右下方向
					for (int k = j + 1, l = i + 1; k < COLUMNS && l < ROWS; k++, l++) {

						if (chesses[l][k] == 0) { // 下一个为空就停止匹配
							break;
						} else {
							if (color == 0) { // 下面的第1颗棋子
								color = chesses[l][k]; // 保存颜色
								code += chesses[l][k]; // 保存棋局
							} else if (chesses[l][k] == color) { // 右边第2/3/4...同颜色棋子
								code += chesses[l][k]; // 保存棋局
							} else { // 下边第2/3/4....不同颜色
								code += chesses[l][k]; // 保存棋局
								break;
							}
						}
					}
					// 根据code取出hm对应的权值
					Integer value6 = hm.get(code);
					if (value6 != null) {
						chessValue[i][j] += value6; // 权值
					}
					code = "";
					color = 0;

					// 向右上方向
					for (int k = j + 1, l = i - 1; k < COLUMNS && l >= 0; k++, l--) {

						if (chesses[l][k] == 0) { // 下一个为空就停止匹配
							break;
						} else {
							if (color == 0) { // 下面的第1颗棋子
								color = chesses[l][k]; // 保存颜色
								code += chesses[l][k]; // 保存棋局
							} else if (chesses[l][k] == color) { // 右边第2/3/4...同颜色棋子
								code += chesses[l][k]; // 保存棋局
							} else { // 下边第2/3/4....不同颜色
								code += chesses[l][k]; // 保存棋局
								break;
							}
						}
					}
					// 根据code取出hm对应的权值
					Integer value7 = hm.get(code);
					if (value7 != null) {
						chessValue[i][j] += value7; // 权值
					}

					code = "";
					color = 0;

				}

			}
		}

	}

	private void win(int i, int j) {

		if (this.checkRow(i, j) >= 5 || this.checkColumn(i, j) >= 5 || this.checkL_R(i, j) >= 5
				|| this.checkR_L(i, j) >= 5) {

			if (count == 1) {
				System.out.println("黑方赢了"); // 如何停止游戏
				game = false;
				JOptionPane.showMessageDialog(null, "不好意思,黑方赢了");
			}

			else if (count == 0) {
				System.out.println("白方赢了");
				game = false;
				JOptionPane.showMessageDialog(null, "不好意思,白方赢了");
			}
		}
	}

	// 斜向左下检查
	private int checkR_L(int x, int y) {
		// TODO Auto-generated method stub
		int count = 0;
		for (int i = x - 1, j = y + 1; i >= 0 && j < ROWS; i--, j++) { // 纵向向下检测
			if (chesses[i][j] == chesses[x][y]) {
				count++;
			} else
				break;
		}
		for (int i = x, j = y; i < COLUMNS && j >= 0; i++, j--) // 向上
		{
			if (chesses[i][j] == chesses[x][y]) {
				count++;
			} else
				break;
		}
		return count;
	}

	// 斜向右下检查
	private int checkL_R(int x, int y) {
		// TODO Auto-generated method stub
		int count = 0;
		for (int i = x + 1, j = y + 1; i < COLUMNS && j < ROWS; i++, j++) { // 纵向向下检测
			if (chesses[i][j] == chesses[x][y]) {
				count++;
			} else
				break;
		}
		for (int i = x, j = y; i >= 0 && j >= 0; i--, j--) // 向上
		{
			if (chesses[i][j] == chesses[x][y]) {
				count++;
			} else
				break;
		}
		return count;
	}

	// 纵向检测
	private int checkColumn(int x, int y) {
		// TODO Auto-generated method stub
		int count = 0;
		for (int i = y + 1; i < ROWS; i++) { // 纵向向下检测
			if (chesses[x][i] == chesses[x][y]) {
				count++;
			} else
				break;
		}
		for (int i = y; i >= 0; i--) // 向上
		{
			if (chesses[x][i] == chesses[x][y]) {
				count++;
			} else
				break;
		}
		return count;
	}

	// 横向检测
	private int checkRow(int x, int y) {
		// TODO Auto-generated method stub
		int count = 0;
		for (int i = x + 1; i < COLUMNS; i++) { // 横向向右检测
			if (chesses[x][y] == chesses[i][y]) {
				count++;
			} else
				break;
		}
		for (int i = x; i >= 0; i--) {
			if (chesses[x][y] == chesses[i][y]) {
				count++;
			} else
				break;
		}
		return count;
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub
		name = e.getActionCommand();
	
		//按钮判断
		 if("重新开始".equals(name)) {
				 for(int m=0;m< ROWS;m++) {
					 for(int n=0;n< COLUMNS;n++) {
						 chesses[m][n] = 0;
						 //System.out.println( chesses[m][n]);
					}
				}
				fc.paint(g);
				 name=null;
				 count=0;
				 game=true;
		 }
		
		 else if("认输".equals(name)&&game) {
			 	if(count==1) {
			 		JOptionPane.showMessageDialog(null, "白方认输");
			 	}else if(count==0) {
			 		JOptionPane.showMessageDialog(null, "黑方认输");
			 	}
			 game=false;			 			 
		 }
		 else if("悔棋".equals(name)&&game) {
           
			 if(list.size()>0) {
				 Point p=new Point();
				p= list.remove(list.size()-1);
				 chesses[(int)p.getX()][(int)p.getY()]=0;				
	             fc.paint(g);			     
  				    if(count==1) count--;
  				    else if(count==0) count++;
  				    
			 }   
		 }
		 else {
			 name1=(String)jcb.getSelectedItem();
			 if("人机对战".equals(name1)) {
				  this.hash();
			 }else if("人人对战".equals(name1)) {
				 game=true;
				 
			 }
			 
		 }
	}
}

5462f38fcdd34a39abbe0935f13b4b2d_th[1].jpg

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

«    2024年11月    »
123
45678910
11121314151617
18192021222324
252627282930
搜索

Powered By Z-BlogPHP 1.7.2

Copyright Your WebSite.Some Rights Reserved.