Java游戏开发 —— 五子棋

 引言:

        五子棋的代码实现很简单,难的是计算机的AI算法,在网上找了很多资料,费了好半天劲才弄明白其实现的原理,真的挺开阔思路的,很有意思!

思路:

        1、创建主窗口,加载菜单及游戏面板。

        2、在游戏面板中初始化各种参数,并建立各种功能组件。

        3、利用paint()函数开始画棋盘,5个定位点,落子指示器,棋子(并标记最后一个棋子的红矩形框),五子成线。

        4、利用mouseMoved()鼠标移动函数设置落子指示器的位置。

        5、利用mouseClicked()鼠标单击函数来判断是否可以下棋,由哪方来下,判断是否平局或胜利。如果是人机对战要计算电脑要下棋的最佳位置。

        6、游戏结束,收尾,准备下一局。

代码: 

图片位置与包位置平齐,因为我装载图片时是从类路径开始取,取绝对路径是不认可的。

        本游戏用的是JDK1.8,编码UTF-8;

        共有4个类,Gobang.java是游戏入口类。GameFrame.java是主窗口类。GamePanel.java是游戏面板类。GameLogic.java是游戏逻辑类。先一口气把所有的代码贴上来再说。

        1、Gobang.java 游戏入口类

package com.game.gobang;

/**
 * 功能:五子棋<br>
 * 作者:我是小木鱼(Lag)<br>
 */
public class Gobang 
{

	public static void main(String[] args) 
	{
		new GameFrame();
	}

}

        2、GameFrame.java 主窗口类。

package com.game.gobang;

import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

/**
 * 功能:游戏窗口<br>
 * 作者:我是小木鱼(Lag)<br>
 */
public class GameFrame extends JFrame implements ActionListener
{
	private static final long serialVersionUID = 1L;

	/** 游戏面板 */
	private GamePanel gamePanel;

	/**
	 * 功能:构造函数<br>
	 */
	public GameFrame()
	{
		try
		{
			//菜单
			JMenuBar jmb_gobang = new JMenuBar();
			JMenu jm_game = new JMenu("游戏");
			jm_game.setFont(new Font("微软雅黑",Font.PLAIN,12));
			JMenuItem jmi_game_new = jm_game.add("新游戏");
			jmi_game_new.setFont(new Font("微软雅黑",Font.PLAIN,12));
			jmi_game_new.addActionListener(this);
			jmi_game_new.setActionCommand("new");
			JMenuItem jmi_game_undo = jm_game.add("悔棋");
			jmi_game_undo.setFont(new Font("微软雅黑",Font.PLAIN,12));
			jmi_game_undo.addActionListener(this);
			jmi_game_undo.setActionCommand("undo");
			JMenuItem jmi_surrender = jm_game.add("认输");
			jmi_surrender.setFont(new Font("微软雅黑",Font.PLAIN,12));
			jmi_surrender.addActionListener(this);
			jmi_surrender.setActionCommand("surrender");
			jm_game.addSeparator();
			JMenuItem jmi_game_exit = jm_game.add("退出");
			jmi_game_exit.setFont(new Font("微软雅黑",Font.PLAIN,12));
			jmi_game_exit.addActionListener(this);
			jmi_game_exit.setActionCommand("exit");
			jmb_gobang.add(jm_game);
			JMenu jm_help = new JMenu("帮助");
			jm_help.setFont(new Font("微软雅黑",Font.PLAIN,12));
			JMenuItem jmi_help_about = jm_help.add("关于");
			jmi_help_about.setFont(new Font("微软雅黑",Font.PLAIN,12));
			jmi_help_about.addActionListener(this);
			jmi_help_about.setActionCommand("about");
			jmb_gobang.add(jm_help);
			this.setJMenuBar(jmb_gobang);
			//面板
			this.gamePanel = new GamePanel();
			this.add(this.gamePanel);
			//显示
			this.setTitle("五子棋");
			this.setLayout(null);
			this.setSize(760,680);
			this.setResizable(false);
			this.setLocationRelativeTo(null);
			this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			this.setVisible(true);
		}
		catch(Exception e)
		{
			JOptionPane.showMessageDialog(this,"程序出现异常错误,即将退出!\r\n\r\n"+e.toString(),"提示",JOptionPane.ERROR_MESSAGE);
			System.exit(0);
		}
	}
	
	/**
	 * 功能:事件监听<br>
	 */
	@Override
	public void actionPerformed(ActionEvent e)
	{
		String command = e.getActionCommand();
		if("new".equals(command))
		{
			this.gamePanel.newGame();
		}
		else if("undo".equals(command))
		{
			this.gamePanel.undo();
		}
		else if("surrender".equals(command))
		{
			this.gamePanel.surrender();
		}
		else if("exit".equals(command))
		{
			System.exit(0);
		}
		else if("about".equals(command))
		{
			JOptionPane.showMessageDialog(this,"我是小木鱼(Lag)","提示",JOptionPane.INFORMATION_MESSAGE);
		}
	}

}

        3、GamePanel.java 游戏面板类。

package com.game.gobang;

import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.BorderFactory;
import java.awt.Font;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RadialGradientPaint;
import java.awt.RenderingHints;
import java.awt.BasicStroke;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Ellipse2D;

/**
 * 功能:游戏面板<br>
 * 作者:我是小木鱼(Lag)<br>
 */
public class GamePanel extends JPanel implements MouseListener,MouseMotionListener,ActionListener
{
	private static final long serialVersionUID = -7450693911538496165L;

	/** 游戏逻辑 */
	private GameLogic gameLogic;

	/** 格子大小 */
	final int spaceSize = 40;

	/** 棋子大小(直径) */
	final int chessSize = 30;

	/** 棋盘X方向格数 */
	final int chessBoradXGrids = 15;

	/** 棋盘Y方向格数 */
	final int chessBoradYGrids = 15;

	/** 棋盘左上角X坐标 */
	final int chessBoradX = 30;

	/** 棋盘左上角Y坐标 */
	final int chessBoradY = 30;
	
	/** 棋盘宽度 */
	final int chessBoradWidth = spaceSize * (chessBoradXGrids - 1);

	/** 棋盘高度 */
	final int chessBoradHeight = spaceSize * (chessBoradYGrids - 1);
	
	/** 黑棋标识 */
	final int BLACKCHESS = 1;

	/** 白棋标识 */
	final int WHITECHESS = 2;
			
	/** 对战方式(0-人机对战,1-人人对战) */
	int fightType ;

	/** 先手选择(0-玩家先手,1-电脑先手) */
	int playFirst ;

	/** 黑白选择(0-玩家执黑,1-玩家执白) */
	int chessColor ;
	
	/** 电脑棋子颜色 */
	int computerChess = -1 ;
	
	/** 玩家棋子颜色 */
	int playerChess = -1 ;
	
	/** 白棋悔棋数 */
	int whiteUndoNum = 3;
	
	/** 黑棋悔棋数 */
	int blackUndoNum = 3;
	
	/** 全部下棋信息 */
	List<Map<String,Integer>> listChess = new ArrayList<Map<String,Integer>>();

	/** 白棋下棋信息 */
	List<Map<String,Integer>> listChessWhite = new ArrayList<Map<String,Integer>>();
	
	/** 黑棋下棋信息 */
	List<Map<String,Integer>> listChessBlack = new ArrayList<Map<String,Integer>>();

	/** 胜利下棋信息(胜利后要将五子成线的那五个棋子用红线连在一起显示) */
	List<Map<String,Integer>> listChessWin = new ArrayList<Map<String,Integer>>();

	/** 落子指示器 */
	Map<String,Integer> mapPointer = new HashMap<String,Integer>();
	
	/** 判断游戏是否结束(true-结束,false-未结束) */
	boolean isGameOver = true;
	
	/** 组合框控件 */
	private JComboBox<String> jcb_fightType,jcb_playFirst,jcb_chessColor;

	/** 按钮控件 */
	private JButton jb_new,jb_undo,jb_surrender;
	
	/** 标签控件 */
	JLabel jlb_blackUndoText,jlb_blackStateText,jlb_whiteUndoText,jlb_whiteStateText;

	/**
	 * 功能:构造函数<br>
	 */
	public GamePanel()
	{
		//与主窗口大小保持一致,并设置背景色(去掉菜单高度)
		this.setSize(760,620);
		this.setBackground(new Color(209,146,17));

		//右边功能区布局
		this.option();
		
		//鼠标点击与移动监听
		this.addMouseListener(this);
		this.addMouseMotionListener(this);
		
		//游戏逻辑
		this.gameLogic = new GameLogic(this);

		//初始化游戏
		this.initGame();

	}
	
	/**
	 * 功能:右边功能区布局<br>
	 */
	private void option()
	{
		this.setLayout(null);
		//对战方式
		JLabel jlb_fightType = new JLabel("对战方式:");
		jlb_fightType.setFont(new Font("微软雅黑",Font.PLAIN,12));
		jlb_fightType.setForeground(Color.WHITE);
		jlb_fightType.setBounds(this.chessBoradX + this.chessBoradWidth + 30,chessBoradY,100,24);
		this.add(jlb_fightType);
		this.jcb_fightType = new JComboBox<String>(new String[]{"人机对战","人人对战"});
		this.jcb_fightType.setFont(new Font("微软雅黑",Font.PLAIN,12));
		this.jcb_fightType.setBounds(this.chessBoradX + this.chessBoradWidth + 30,chessBoradY + 30,100,24);
		this.add(this.jcb_fightType);
		//谁先手
		JLabel jlb_playFirst = new JLabel("先手选择:");
		jlb_playFirst.setBounds(this.chessBoradX + this.chessBoradWidth + 30,chessBoradY + 70,100,24);
		jlb_playFirst.setFont(new Font("微软雅黑",Font.PLAIN,12));
		jlb_playFirst.setForeground(Color.WHITE);
		this.add(jlb_playFirst);
		this.jcb_playFirst = new JComboBox<String>(new String[]{"玩家先手","电脑先手"});
		this.jcb_playFirst.setFont(new Font("微软雅黑",Font.PLAIN,12));
		this.jcb_playFirst.setBounds(this.chessBoradX + this.chessBoradWidth + 30,chessBoradY + 100,100,24);
		this.add(this.jcb_playFirst);
		//谁执黑
		JLabel jlb_chessColor = new JLabel("黑白选择:");
		jlb_chessColor.setBounds(this.chessBoradX + this.chessBoradWidth + 30,chessBoradY + 140,100,24);
		jlb_chessColor.setFont(new Font("微软雅黑",Font.PLAIN,12));
		jlb_chessColor.setForeground(Color.WHITE);
		this.add(jlb_chessColor);
		this.jcb_chessColor = new JComboBox<String>(new String[]{"玩家执黑","玩家执白"});
		this.jcb_chessColor.setFont(new Font("微软雅黑",Font.PLAIN,12));
		this.jcb_chessColor.setBounds(this.chessBoradX + this.chessBoradWidth + 30,chessBoradY + 170,100,24);
		this.add(this.jcb_chessColor);
		//按钮
		this.jb_new = new JButton("开始游戏");
		this.jb_new.setFont(new Font("微软雅黑",Font.PLAIN,12));
		this.jb_new.setBounds(this.chessBoradX + this.chessBoradWidth + 30, chessBoradY + 230,100,30);
		this.jb_new.setActionCommand("newGame");
		this.jb_new.addActionListener(this);
		this.add(this.jb_new);
		this.jb_undo = new JButton("我要悔棋");
		this.jb_undo.setFont(new Font("微软雅黑",Font.PLAIN,12));
		this.jb_undo.setBounds(this.chessBoradX + this.chessBoradWidth + 30, chessBoradY + 280,100,30);
		this.jb_undo.setActionCommand("undo");
		this.jb_undo.addActionListener(this);
		this.jb_undo.setEnabled(false);
		this.add(this.jb_undo);
		this.jb_surrender = new JButton("我认输了");
		this.jb_surrender.setFont(new Font("微软雅黑",Font.PLAIN,12));
		this.jb_surrender.setBounds(this.chessBoradX + this.chessBoradWidth + 30, chessBoradY + 330,100,30);
		this.jb_surrender.setActionCommand("surrender");
		this.jb_surrender.addActionListener(this);
		this.jb_surrender.setEnabled(false);
		this.add(this.jb_surrender);
		//黑棋提示
		JPanel groupBoxBlack = new JPanel();
		groupBoxBlack.setLayout(null);
		groupBoxBlack.setBackground(this.getBackground());
		groupBoxBlack.setBounds(this.chessBoradX + this.chessBoradWidth + 30, chessBoradY + 380,100,80);
		groupBoxBlack.setBorder(BorderFactory.createTitledBorder("黑棋"));
		this.add(groupBoxBlack);
		JLabel jlb_blackUndo = new JLabel("悔棋:");
		jlb_blackUndo.setFont(new Font("微软雅黑",Font.PLAIN,12));
		jlb_blackUndo.setForeground(Color.WHITE);
		jlb_blackUndo.setBounds(10,16,40,30);
		groupBoxBlack.add(jlb_blackUndo);
		this.jlb_blackUndoText = new JLabel("剩"+Integer.toString(this.blackUndoNum)+"次");
		this.jlb_blackUndoText.setFont(new Font("微软雅黑",Font.BOLD,12));
		this.jlb_blackUndoText.setForeground(Color.darkGray);
		this.jlb_blackUndoText.setBounds(44,16,50,30);
		groupBoxBlack.add(this.jlb_blackUndoText);
		JLabel jlb_blackState = new JLabel("状态:");
		jlb_blackState.setFont(new Font("微软雅黑",Font.PLAIN,12));
		jlb_blackState.setForeground(Color.WHITE);
		jlb_blackState.setBounds(10,44,40,30);
		groupBoxBlack.add(jlb_blackState);
		this.jlb_blackStateText = new JLabel("未开始");
		this.jlb_blackStateText.setFont(new Font("微软雅黑",Font.BOLD,12));
		this.jlb_blackStateText.setForeground(Color.darkGray);
		this.jlb_blackStateText.setBounds(44,44,50,30);
		groupBoxBlack.add(this.jlb_blackStateText);
		//白棋提示
		JPanel groupBoxWhite = new JPanel();
		groupBoxWhite.setLayout(null);
		groupBoxWhite.setBackground(this.getBackground());
		groupBoxWhite.setBounds(this.chessBoradX + this.chessBoradWidth + 30, chessBoradY + 480,100,80);
		groupBoxWhite.setBorder(BorderFactory.createTitledBorder("白棋"));
		this.add(groupBoxWhite);
		JLabel jlb_whiteUndo = new JLabel("悔棋:");
		jlb_whiteUndo.setFont(new Font("微软雅黑",Font.PLAIN,12));
		jlb_whiteUndo.setForeground(Color.WHITE);
		jlb_whiteUndo.setBounds(10,16,40,30);
		groupBoxWhite.add(jlb_whiteUndo);
		this.jlb_whiteUndoText = new JLabel("剩"+Integer.toString(this.whiteUndoNum)+"次");
		this.jlb_whiteUndoText.setFont(new Font("微软雅黑",Font.BOLD,12));
		this.jlb_whiteUndoText.setForeground(Color.darkGray);
		this.jlb_whiteUndoText.setBounds(44,16,50,30);
		groupBoxWhite.add(this.jlb_whiteUndoText);
		JLabel jlb_whiteState = new JLabel("状态:");
		jlb_whiteState.setFont(new Font("微软雅黑",Font.PLAIN,12));
		jlb_whiteState.setForeground(Color.WHITE);
		jlb_whiteState.setBounds(10,44,40,30);
		groupBoxWhite.add(jlb_whiteState);
		this.jlb_whiteStateText = new JLabel("未开始");
		this.jlb_whiteStateText.setFont(new Font("微软雅黑",Font.BOLD,12));
		this.jlb_whiteStateText.setForeground(Color.darkGray);
		this.jlb_whiteStateText.setBounds(44,44,50,30);
		groupBoxWhite.add(this.jlb_whiteStateText);
		
	}
	
	/**
	 * 功能:初始化游戏<br>
	 */
	public void initGame()
	{
		this.isGameOver = true;
		//清空下棋列表
		this.listChess.clear();
		this.listChessBlack.clear();
		this.listChessWhite.clear();
		this.listChessWin.clear();
		//落子指示器初始化
		this.mapPointer.put("x",-1);
		this.mapPointer.put("y",-1);
		this.mapPointer.put("show",0);	//0-不显示,1-显示
		//对战方式
		if("人人对战".equals(this.jcb_fightType.getSelectedItem().toString()))
		{
			this.fightType = 1;
		}
		else
		{
			this.fightType = 0;
		}
		//先手选择
		if("电脑先手".equals(this.jcb_playFirst.getSelectedItem().toString()))
		{
			this.playFirst = 1;
		}
		else
		{
			this.playFirst = 0;
		}
		//黑白选择
		if("玩家执白".equals(this.jcb_chessColor.getSelectedItem().toString()))
		{
			this.chessColor = 1;
		}
		else
		{
			this.chessColor = 0;
		}
		//电脑与玩家棋子颜色
		if(this.fightType == 0)
		{
			if(this.chessColor == 1)
			{
				this.playerChess = this.WHITECHESS;
				this.computerChess = this.BLACKCHESS;
			}
			else
			{
				this.computerChess = this.WHITECHESS;
				this.playerChess = this.BLACKCHESS;
			}
		}
		//悔棋数初始化
		this.whiteUndoNum = 3;
		this.blackUndoNum = 3;
		//设置控件状态
		this.setComponentState(false);
	}
	
	/**
	 * 功能:设置控件状态<br>
	 * 参数:true-新开局;false-未开局<br>
	 */
	public void setComponentState(boolean _flag)
	{
		if(_flag)	//新游戏已经开始了
		{
			this.jcb_fightType.setEnabled(false);
			this.jcb_playFirst.setEnabled(false);
			this.jcb_chessColor.setEnabled(false);
			this.jb_new.setEnabled(false);
			this.jb_undo.setEnabled(true);
			this.jb_surrender.setEnabled(true);
		}
		else	//新游戏还未开始
		{
			this.jcb_fightType.setEnabled(true);
			this.jcb_playFirst.setEnabled(true);
			this.jcb_chessColor.setEnabled(true);
			this.jb_new.setEnabled(true);
			this.jb_undo.setEnabled(false);
			this.jb_surrender.setEnabled(false);
		}
	}
	
	/**
	 * 功能:绘图<br>
	 */
	@Override
	public void paint(Graphics g)
	{
		//调用父类,让其做一些事前的工作,如刷新屏幕等
		super.paint(g);

		//清屏
		g.setColor(this.getBackground());
		g.fillRect(this.chessBoradX,this.chessBoradY,this.chessBoradWidth,this.chessBoradHeight);
		
		//因为要画一些特殊效果,所以要用Graphics2D
		Graphics2D g2D = (Graphics2D)g;

		//开始画棋盘(五子棋盘由15条横线与15条竖线交叉形成,共225个点)
		//String[] tip = {" 0"," 1"," 2"," 3"," 4"," 5"," 6"," 7"," 8"," 9","10","11","12","13","14"};	//横竖线的坐标,有利于编程是查看定位
		g2D.setColor(Color.BLACK);
		g.setFont(new Font("微软雅黑",Font.PLAIN,14));
		for(int i=0;i<this.chessBoradXGrids;i++)
		{
			g2D.drawLine(this.chessBoradX,this.chessBoradY + i * this.spaceSize,this.chessBoradX + this.chessBoradWidth,this.chessBoradY + i * this.spaceSize);
			g2D.drawLine(this.chessBoradX + i * this.spaceSize,this.chessBoradY,this.chessBoradX + i * this.spaceSize,this.chessBoradY + this.chessBoradHeight);
			//g2D.drawString(tip[i],this.chessBoradX - 20,this.chessBoradY + 4 + i * this.spaceSize);
			//g2D.drawString(tip[i],this.chessBoradX - 2 + i * this.spaceSize,this.chessBoradY - 10);
		}

		//画5个定位点
		g2D.fillArc(this.chessBoradX + 3 * this.spaceSize - 4,this.chessBoradY + 3 * this.spaceSize - 4,8,8,0,360);
		g2D.fillArc(this.chessBoradX + 11 * this.spaceSize - 4,this.chessBoradY + 3 * this.spaceSize - 4,8,8,0,360);
		g2D.fillArc(this.chessBoradX + 7 * this.spaceSize - 4,this.chessBoradY + 7 * this.spaceSize - 4,8,8,0,360);
		g2D.fillArc(this.chessBoradX + 3 * this.spaceSize - 4,this.chessBoradY + 11 * this.spaceSize - 4,8,8,0,360);
		g2D.fillArc(this.chessBoradX + 11 * this.spaceSize - 4,this.chessBoradY + 11 * this.spaceSize - 4,8,8,0,360);
		
		//画落子指示器
		if(this.mapPointer.get("show") == 1)
		{
			g2D.setColor(Color.RED);
			g2D.setStroke(new BasicStroke(2.5f));
			//先以交叉点为中心取到指示器周围的4个角坐标
			//中心点坐标
			int x = this.chessBoradX + this.mapPointer.get("x") * this.spaceSize;
			int y = this.chessBoradY + this.mapPointer.get("y") * this.spaceSize;
			//左上角坐标,并向下向右画线
			int x1 = x - this.chessSize / 2;
			int y1 = y - this.chessSize / 2;
			g2D.drawLine(x1,y1,x1,y1 + this.chessSize / 4);
			g2D.drawLine(x1,y1,x1 + this.chessSize / 4,y1);
			//右上角坐标,并向下向左画线
			x1 = x + this.chessSize / 2;
			y1 = y - this.chessSize / 2;
			g2D.drawLine(x1,y1,x1,y1 + this.chessSize / 4);
			g2D.drawLine(x1,y1,x1 - this.chessSize / 4,y1);
			//左下角坐标,并向上向右画线
			x1 = x - this.chessSize / 2;
			y1 = y + this.chessSize / 2;
			g2D.drawLine(x1,y1,x1,y1 - this.chessSize / 4);
			g2D.drawLine(x1,y1,x1 + this.chessSize / 4,y1);
			//右下角坐标,并向上向左画线
			x1 = x + this.chessSize / 2;
			y1 = y + this.chessSize / 2;
			g2D.drawLine(x1,y1,x1,y1 - this.chessSize / 4);
			g2D.drawLine(x1,y1,x1 - this.chessSize / 4,y1);
			//System.out.println("("+this.mapPointer.get("x")+","+this.mapPointer.get("y")+")");
		}

		//画棋子(就是一个黑色的圆,里面在接近圆心的位置上画一个由白到黑的渐变内圆)
		for(int i=0;i<this.listChess.size();i++)
		{
			Map<String,Integer> map = this.listChess.get(i);
        	int lineX = map.get("x");
        	int lineY = map.get("y");
        	int flag = map.get("flag");
        	//将垂直与水平线的数目转化为像素
        	int x = this.chessBoradX + lineX * this.spaceSize;
        	int y = this.chessBoradY + lineY  * this.spaceSize;
    		//做一个由白到黑渐变的圆绘画
        	RadialGradientPaint paint = null;
        	if(flag == this.WHITECHESS)
        	{
        		paint = new RadialGradientPaint(x + 5,y + 5,90, new float[]{0f,1f},new Color[]{Color.WHITE,Color.BLACK});
        	}
        	else
        	{
        		paint = new RadialGradientPaint(x + 3,y + 3,10, new float[]{0f,1f},new Color[]{Color.WHITE,Color.BLACK});
        	}
    		g2D.setPaint(paint);
    		//着色微调
    		g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);	//消除画图锯齿
    		g2D.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT);		//追求速度或质量
    		//画圆,里面套一个白到黑渐变的圆
    		Ellipse2D e = new Ellipse2D.Float(x - this.chessSize/2,y - this.chessSize/2,this.chessSize,this.chessSize);
    		g2D.fill(e);
    		//标记最后一个棋子的红矩形框
    		if(i == this.listChess.size() - 1)
    		{
    			g2D.setColor(Color.RED);
    			g2D.setStroke(new BasicStroke(2.5f));
    			g2D.drawRect(x - 5,y - 5,10,10);
    		}
		}
		
		//画五子成线
		if(this.listChessWin.size() > 4)
		{
			g2D.setColor(Color.RED);
			g2D.setStroke(new BasicStroke(2.5f));
			int x1 = 0;
			int y1 = 0;
			for(int i=0;i<this.listChessWin.size();i++)
			{
				Map<String,Integer> map = this.listChessWin.get(i);
				if(i == 0)	//先得到第一个点
				{
					x1 = map.get("x");
					y1 = map.get("y");
				}
				else	//再用第一个点与其他的点连线
				{
					g2D.drawLine(this.chessBoradX + x1 * this.spaceSize,this.chessBoradY + y1 * this.spaceSize,this.chessBoradX + map.get("x") * this.spaceSize,this.chessBoradY +map.get("y") * this.spaceSize);
				}
			}
		}
		
	}
	
	/**
	 * 功能:开始新游戏<br>
	 */
	public void newGame()
	{
		//初始化游戏
		this.initGame();
		//设置控件状态
		this.setComponentState(true);
		//设置游戏结束标识
		this.isGameOver = false;
		//电脑先手
		if(this.fightType == 0 && this.playFirst == 1)
		{
			this.gameLogic.computerPlay();
		}
		
	}
	
	/**
	 * 功能:悔棋<br>
	 */
	public void undo()
	{
		if(this.gameLogic.undo()){this.repaint();}
	}

	/**
	 * 功能:投降<br>
	 */
	public void surrender()
	{
		if(this.isGameOver){return;}
		JOptionPane.showMessageDialog(null,"啥,认输了,还能再有点出息不!");
		this.isGameOver = true;
		this.setComponentState(false);
		this.jlb_blackStateText.setText("已结束");
		this.jlb_whiteStateText.setText("已结束");
	}
	
	/**
	 * 功能:鼠标移动监听<br>
	 */
	@Override
	public void mouseMoved(MouseEvent e)
	{
		this.gameLogic.mouseMoved(e);
	}
	
	/**
	 * 功能:鼠标单击监听<br>
	 */
	@Override
	public void mouseClicked(MouseEvent e) 
	{
		this.gameLogic.mouseClicked(e);
	}
	
	/**
	 * 功能:功能监听<br>
	 */
	@Override
	public void actionPerformed(ActionEvent e)
	{
		String command = e.getActionCommand();
		
		if("newGame".equals(command))
		{
			this.newGame();
		}
		else if("undo".equals(command))
		{
			this.undo();
		}
		else if("surrender".equals(command))
		{
			this.surrender();
		}
		
	}

	@Override
	public void mousePressed(MouseEvent e) {}

	@Override
	public void mouseReleased(MouseEvent e) {}

	@Override
	public void mouseEntered(MouseEvent e) {}

	@Override
	public void mouseExited(MouseEvent e) {}

	@Override
	public void mouseDragged(MouseEvent e) {}

}

        4、GameLogic.java 游戏逻辑类。

package com.game.gobang;

import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.awt.event.MouseEvent;
import javax.swing.JOptionPane;

/**
 * 功能:游戏逻辑<br>
 * 作者:我是小木鱼(Lag)<br>
 */
public class GameLogic 
{
	/** 游戏面板 */
	private GamePanel gamePanel;
	
	/**
	 * 功能:构造函数<br>
	 */
	public GameLogic(GamePanel _gamePanel)
	{
		this.gamePanel = _gamePanel;
	}
	
	/**
	 * 功能:判断下一步是白棋下还是黑棋下<br>
	 */
	private int getNextChessColor()
	{
		int chessColor = -1;
		
		//得到上一步信息
		if(this.gamePanel.listChess.size() > 0)
		{
			Map<String,Integer> mapLast = this.gamePanel.listChess.get(this.gamePanel.listChess.size() - 1);
			if(mapLast.get("flag") == this.gamePanel.BLACKCHESS)
			{
				chessColor = this.gamePanel.WHITECHESS;
			}
			else
			{
				chessColor = this.gamePanel.BLACKCHESS;
			}
		}
		else
		{
			if(this.gamePanel.fightType == 0)	//人机对战
			{
				if(this.gamePanel.playFirst == 0)	//玩家先手
				{
					if(this.gamePanel.chessColor == 0)
					{
						chessColor = this.gamePanel.BLACKCHESS;
					}
					else
					{
						chessColor = this.gamePanel.WHITECHESS;
					}
				}
				else	//电脑先手(这是不想赢啊)
				{
					if(this.gamePanel.chessColor == 0)
					{
						chessColor = this.gamePanel.WHITECHESS;
					}
					else
					{
						chessColor = this.gamePanel.BLACKCHESS;
					}
				}
			}
			else	//人人对战
			{
				if(this.gamePanel.chessColor == 0)
				{
					chessColor = this.gamePanel.BLACKCHESS;
				}
				else
				{
					chessColor = this.gamePanel.WHITECHESS;
				}
			}
		}
		
		return chessColor;
	}
	
	/**
	 * 功能:得到X像素所对应的竖线下标<br>
	 */
	private int getLineX(int x)
	{
		//先判断靠哪条竖线近些
		int lineX = (x - this.gamePanel.chessBoradX + this.gamePanel.spaceSize / 2) / this.gamePanel.spaceSize;
		//再判断是否在有效范围内
		int posX = this.gamePanel.chessBoradX + lineX * this.gamePanel.spaceSize;
		if(x > (posX - this.gamePanel.chessSize / 2) && x < (posX + this.gamePanel.chessSize / 2)){}
		else
		{
			lineX = -1;
		}
		 
		return lineX;
	}
	
	/**
	 * 功能:得到Y像素所对应的横线下标<br>
	 */
	private int getLineY(int y)
	{
		//先判断靠哪条竖线近些
		int lineY = (y - this.gamePanel.chessBoradY + this.gamePanel.spaceSize / 2) / this.gamePanel.spaceSize;
		//再判断是否在有效范围内
		int posY = this.gamePanel.chessBoradY + lineY * this.gamePanel.spaceSize;
		if(y > (posY - this.gamePanel.chessSize / 2) && y < (posY + this.gamePanel.chessSize / 2)){}
		else
		{
			lineY = -1;
		}
		 
		return lineY;
	}
	
	/**
	 * 功能:对五元组进行评分<br>
	 */
	private int getTupleScore(int _computerChessNum,int _playerChessNum)
	{
		//1、该五元组中既有电脑的棋子又有玩家的棋子,大家一起完蛋,得0分。
		if(_computerChessNum > 0 && _playerChessNum > 0){return 0;}

		//2、该五元组为空,没有棋子,得7分。
		if(_computerChessNum == 0 && _playerChessNum == 0){return 7;}

		//3、该五元组中只有1个机器的棋子,其他为空,得35分。(电脑才下一个棋子,可以先看看。【优先级第七】)
		if(_computerChessNum == 1){return 35;}
		
		//4、该五元组中只有2个机器的棋子,其他为空,得800分。(电脑下两个棋子了。【优先级第五】)
		if(_computerChessNum == 2){return 800;}

		//5、该五元组中只有3个机器的棋子,其他为空,得15000分。(电脑看到赢的希望了,可以下这个点上,进攻进攻。【优先级第三】)
		if(_computerChessNum == 3){return 15000;}

		//6、该五元组中只有4个机器的棋子,其他为空,得800000分。(电脑马上就要赢了,无论如何也必须下这个点上,进攻进攻再进攻。【优先级第一】)
		if(_computerChessNum == 4){return 800000;}

		//7、该五元组中只有1个玩家的棋子,其他为空,得15分。(玩家才下一个棋子,别理他。【没优先级】)
		if(_playerChessNum == 1){return 15;}
		
		//8、该五元组中只有2个玩家的棋子,其他为空,得400分。(玩家下两个棋子了。【优先级第六】)
		if(_playerChessNum == 2){return 800;}

		//9、该五元组中只有3个玩家的棋子,其他为空,得1800分。(玩家看到赢的希望了,如果电脑没有类似的情况就得堵住这个点,防守防守。【优先级第四】)
		if(_playerChessNum == 3){return 1800;}

		//10、该五元组中只有4个玩家的棋子,其他为空,得100000分。(玩家马上就要赢了,如果电脑要是不能立刻赢的话就必须下在这个点上,快防守啊,黑山老妖要来了。【优先级第二】)
		if(_playerChessNum == 4){return 100000;}
		
		return 0;
	}
	
	/**
	 * 功能:得到电脑要下棋的位置<br>
	 */
	private Map<String,Integer> getComputerLocation()
	{
		//= = = = = = = = = = = = = = = = = = = = 原理 = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =//
		//五子棋要赢,必然要有五个棋子在一起成线,那么我们就把这五格相连的线称之为五元组。                                 		//
		//一般情况下棋盘是15×15的,那么应该共有572个五元组。                                                                	//
		//同时,针对五元组中黑子和白子的数量(可以不考虑相对位置)的不同,给每个五元组评不同的分(每组中的5个点都是同样分数)。    //
		//然后每一个位置的得分就是包含这个位置的所有五元组的得分之和。                                                    		//      
		//理论上每个落子点最多被包含在20个五元组中,最少被包含在3个五元组中。然后我们循环整个棋盘,找到评分最多且空的那个点,		//
		//就是电脑要落子的那个点。该点可能用于进攻,也可能用于防守。当然以进攻为主,进攻的评分能更高些。							//
		//在本函数中我要对15×15这225个点进行循环,以这个点为龙头,向右、下、45度斜下、135度斜下共4个方向寻找4个五元组				//
		//(边角的点可能在某些方向不构成五元组),并将这些五元组的评分累计到每个五元组中的5个点里。								//
		//由于只是以这个点为龙头去寻找五元组,因此这个点的累计评分不是最终评分,当再以其他点为龙头时可能会包含这个点,会再给这个	//
		//点累计加分,这样全部循环后该点的评分就准了。再循环整个棋盘,找到评分最高且处于空位的那个点就是电脑要下的点。							//
		//问:一共不是有8个方向吗,为什么只找4个方向就行了?																	//
		//答:因为那4个方向是重复计算了。比如说当你以A点为龙头向右寻找五元组时是(A,A+1,A+2,A+3,A+4)这样的五元组。				//
		//	  但当你以A+4这个点位龙头向左寻找五元组时是(A+4,A+3,A+2,A+1,A)这样的五元组,这不就是重复了嘛。						//
		//	  因此我们总结出寻找规律,向右找就别向左找,向下找就别向上找...。													//
		//= = = = = = = = = = = = = = = = = = = = 结束 = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =	//
		
		Map<String,Integer> mapComputer = new HashMap<String,Integer>();
		int computerChessNum;		//五元组中电脑棋子数目累计
		int playerChessNum ;		//五元组中玩家棋子数目累计
		int tupleScore;				//五元组评分值
		int[][] score = new int[this.gamePanel.chessBoradXGrids][this.gamePanel.chessBoradYGrids];	//棋盘中每个落子交叉点的评分数组
		int[][] chess = new int[this.gamePanel.chessBoradXGrids][this.gamePanel.chessBoradYGrids];	//棋盘中每个落子交叉点的棋子数组

		//初始化评分与棋子数组
		for(int i=0;i<this.gamePanel.chessBoradXGrids;i++)
		{
			for(int j=0;j<this.gamePanel.chessBoradYGrids;j++)
			{
				score[i][j] = 0;
				chess[i][j] = 0;
			}
		}
		//为棋子数组赋值,有利于计算且观察。
		for(int i=0;i<this.gamePanel.listChess.size();i++)
		{
			Map<String,Integer> map = this.gamePanel.listChess.get(i);
			chess[ map.get("x")][ map.get("y")] =  map.get("flag");
		}
		
		//开始循环
		for(int i=0;i<this.gamePanel.chessBoradXGrids;i++)
		{
			for(int j=0;j<this.gamePanel.chessBoradYGrids;j++)
			{
				//1、以该点为龙头向右寻找五元组
				if(i + 4 <= 14)	//这个五元组真的有
				{
					//初始化变量
					computerChessNum = 0;
					playerChessNum = 0;
					tupleScore = 0;
					//得到该五元组中电脑与玩家的棋子数目
					for(int k=0;k<5;k++)
					{
						if(chess[i+k][j] == this.gamePanel.computerChess){computerChessNum++;}
						if(chess[i+k][j] == this.gamePanel.playerChess){playerChessNum++;}
					}
					//得到该五元组的评分
					tupleScore = this.getTupleScore(computerChessNum,playerChessNum);
					//将该评分赋值给五元组中的5个点
					for(int k=0;k<5;k++)
					{
						score[i+k][j] = score[i+k][j] + tupleScore;
					}
				}
				
				//2、以该点为龙头向下寻找五元组
				if(j + 4 <= 14)	//这个五元组真的有
				{
					//初始化变量
					computerChessNum = 0;
					playerChessNum = 0;
					tupleScore = 0;
					//得到该五元组中电脑与玩家的棋子数目
					for(int k=0;k<5;k++)
					{
						if(chess[i][j+k] == this.gamePanel.computerChess){computerChessNum++;}
						if(chess[i][j+k] == this.gamePanel.playerChess){playerChessNum++;}
					}
					//得到该五元组的评分
					tupleScore = this.getTupleScore(computerChessNum,playerChessNum);
					//将该评分赋值给五元组中的5个点
					for(int k=0;k<5;k++)
					{
						score[i][j+k] = score[i][j+k] + tupleScore;
					}
				}
				
				//3、以该点为龙头135度斜下寻找五元组
				if(i + 4 <= 14 && j + 4 <= 14)	//这个五元组真的有
				{
					//初始化变量
					computerChessNum = 0;
					playerChessNum = 0;
					tupleScore = 0;
					//得到该五元组中电脑与玩家的棋子数目
					for(int k=0;k<5;k++)
					{
						if(chess[i+k][j+k] == this.gamePanel.computerChess){computerChessNum++;}
						if(chess[i+k][j+k] == this.gamePanel.playerChess){playerChessNum++;}
					}
					//得到该五元组的评分
					tupleScore = this.getTupleScore(computerChessNum,playerChessNum);
					//将该评分赋值给五元组中的5个点
					for(int k=0;k<5;k++)
					{
						score[i+k][j+k] = score[i+k][j+k] + tupleScore;
					}
				}
				
				//4、以该点为龙头45度斜下寻找五元组
				if(i - 4 >= 0 && j + 4 <= 14)	//这个五元组真的有
				{
					//初始化变量
					computerChessNum = 0;
					playerChessNum = 0;
					tupleScore = 0;
					//得到该五元组中电脑与玩家的棋子数目
					for(int k=0;k<5;k++)
					{
						if(chess[i-k][j+k] == this.gamePanel.computerChess){computerChessNum++;}
						if(chess[i-k][j+k] == this.gamePanel.playerChess){playerChessNum++;}
					}
					//得到该五元组的评分
					tupleScore = this.getTupleScore(computerChessNum,playerChessNum);
					//将该评分赋值给五元组中的5个点
					for(int k=0;k<5;k++)
					{
						score[i-k][j+k] = score[i-k][j+k] + tupleScore;
					}
				}
			}
		}
		
		//从空位置中找到得分最大的位置
		int maxScore = 0;
		int maxX = -1;
		int maxY = -1;
		for(int i=0;i<this.gamePanel.chessBoradXGrids;i++)
		{
			for(int j=0;j<this.gamePanel.chessBoradYGrids;j++)
			{
				if(chess[i][j] == 0)
				{
					if(maxScore < score[i][j])
					{
						maxScore = score[i][j];
						maxX = i;
						maxY = j;
					}
				}
			}
		}

		mapComputer.put("x",maxX);
		mapComputer.put("y",maxY);

		return mapComputer;
	}

	/**
	 * 功能:轮到电脑下棋了br>
	 */
	public void computerPlay()
	{
		Map<String,Integer> mapComputer = this.getComputerLocation();
		mapComputer.put("flag",this.gamePanel.computerChess);
		//棋盘下满了,电脑无棋可下了
		if(mapComputer.get("x") == -1 || mapComputer.get("y") == -1)
		{
			JOptionPane.showMessageDialog(null,"牛批,你们竟然打平了!");
			this.gamePanel.isGameOver = true;
			this.gamePanel.initGame();
			return;
		}
		if(this.gamePanel.computerChess == this.gamePanel.WHITECHESS)
		{
			this.gamePanel.listChessWhite.add(mapComputer);
		}
		else
		{
			this.gamePanel.listChessBlack.add(mapComputer);
		}
		this.gamePanel.listChess.add(mapComputer);
		//延时一会再刷新,要不显得电脑太厉害了。
		try 
		{
			Thread.sleep(50);
		} 
		catch(Exception e1)
		{
			e1.printStackTrace();
		}
		this.gamePanel.repaint();
	}
	
	/**
	 * 功能:判断游戏是否结束<br>
	 */
	private boolean gameOver()
	{
		int hCount = 0;							//水平计数
		int vCount = 0;							//垂直计数
		int a45Count = 0;						//斜45度计数
		int a135Count = 0;						//斜135度计数
		boolean isFind = false;					//是否找到
		List<Map<String,Integer>> hChessWin = new ArrayList<Map<String,Integer>>();		//记录水平方向上的5个点连成线
		List<Map<String,Integer>> vChessWin = new ArrayList<Map<String,Integer>>();		//记录垂直方向上的5个点连成线
		List<Map<String,Integer>> a45ChessWin = new ArrayList<Map<String,Integer>>();	//记录斜45度方向上的5个点连成线
		List<Map<String,Integer>> a135ChessWin = new ArrayList<Map<String,Integer>>();	//记录斜135度方向上的5个点连成线
		
		if(this.gamePanel.listChess.size() < 1){return false;}

		//得到最后一步下棋信息
		Map<String,Integer> mapLast = this.gamePanel.listChess.get(this.gamePanel.listChess.size() - 1);
		int x = mapLast.get("x");
		int y = mapLast.get("y");
		int flag = mapLast.get("flag");
		List<Map<String,Integer>> listTmp ;
		if(flag == this.gamePanel.WHITECHESS)
		{
			listTmp = this.gamePanel.listChessWhite;
		}
		else
		{
			listTmp = this.gamePanel.listChessBlack;
		}
		
		//水平(先向右数4个)
		for(int i=1;i<5;i++)
		{
			isFind = false;
			for(int j=0;j<listTmp.size();j++)
			{
				Map<String,Integer> map = listTmp.get(j);
				if(map.get("x") == (x + i) && map.get("y") == y)
				{
					hChessWin.add(map);
					isFind = true;
				}
			}
			if(isFind)
			{
				hCount++;
			}
			else
			{
				break;
			}
		}
		//水平(向左数4个)
		for(int i=1;i<5;i++)
		{
			isFind = false;
			for(int j=0;j<listTmp.size();j++)
			{
				Map<String,Integer> map = listTmp.get(j);
				if(map.get("x") == (x - i) && map.get("y") == y)
				{
					hChessWin.add(map);
					isFind = true;
				}
			}
			if(isFind)
			{
				hCount++;
			}
			else
			{
				break;
			}
		}

		//垂直(向上数4个)
		for(int i=1;i<5;i++)
		{
			isFind = false;
			for(int j=0;j<listTmp.size();j++)
			{
				Map<String,Integer> map = listTmp.get(j);
				if(map.get("x") == x && map.get("y") == (y - i))
				{
					vChessWin.add(map);
					isFind = true;
				}
			}
			if(isFind)
			{
				vCount++;
			}
			else
			{
				break;
			}
		}
		//垂直(向下数4个)
		for(int i=1;i<5;i++)
		{
			isFind = false;
			for(int j=0;j<listTmp.size();j++)
			{
				Map<String,Integer> map = listTmp.get(j);
				if(map.get("x") == x && map.get("y") == (y + i))
				{
					vChessWin.add(map);
					isFind = true;
				}
			}
			if(isFind)
			{
				vCount++;
			}
			else
			{
				break;
			}
		}

		//45度斜线(向右上方数4个)
		for(int i=1;i<5;i++)
		{
			isFind = false;
			for(int j=0;j<listTmp.size();j++)
			{
				Map<String,Integer> map = listTmp.get(j);
				if(map.get("x") == (x + i) && map.get("y") == (y - i))
				{
					a45ChessWin.add(map);
					isFind = true;
				}
			}
			if(isFind)
			{
				a45Count++;
			}
			else
			{
				break;
			}
		}
		//45度斜线(向左下方数4个)
		for(int i=1;i<5;i++)
		{
			isFind = false;
			for(int j=0;j<listTmp.size();j++)
			{
				Map<String,Integer> map = listTmp.get(j);
				if(map.get("x") == (x - i) && map.get("y") == (y + i))
				{
					a45ChessWin.add(map);
					isFind = true;
				}
			}
			if(isFind)
			{
				a45Count++;
			}
			else
			{
				break;
			}
		}

		//135度斜线(向左上方数4个)
		for(int i=1;i<5;i++)
		{
			isFind = false;
			for(int j=0;j<listTmp.size();j++)
			{
				Map<String,Integer> map = listTmp.get(j);
				if(map.get("x") == (x - i) && map.get("y") == (y - i))
				{
					a135ChessWin.add(map);
					isFind = true;
				}
			}
			if(isFind)
			{
				a135Count++;
			}
			else
			{
				break;
			}
		}
		//135度斜线(向右下方数4个)
		for(int i=1;i<5;i++)
		{
			isFind = false;
			for(int j=0;j<listTmp.size();j++)
			{
				Map<String,Integer> map = listTmp.get(j);
				if(map.get("x") == (x + i) && map.get("y") == (y + i))
				{
					a135ChessWin.add(map);
					isFind = true;
				}
			}
			if(isFind)
			{
				a135Count++;
			}
			else
			{
				break;
			}
		}
		
		//开始判断
		if(hCount >= 4 || vCount >= 4 || a45Count >= 4 || a135Count >= 4)
		{
			//记录五子连线
			if(hChessWin.size() == 4)
			{
				hChessWin.add(mapLast);
				this.gamePanel.listChessWin = hChessWin;
			}
			else if(vChessWin.size() == 4)
			{
				vChessWin.add(mapLast);
				this.gamePanel.listChessWin = vChessWin;
			}
			else if(a45ChessWin.size() == 4)
			{
				a45ChessWin.add(mapLast);
				this.gamePanel.listChessWin = a45ChessWin;
			}
			else if(a135ChessWin.size() == 4)
			{
				a135ChessWin.add(mapLast);
				this.gamePanel.listChessWin = a135ChessWin;
			}
			
			if(this.gamePanel.fightType == 0)	//人机对战
			{
				if(flag == this.gamePanel.computerChess)
				{
					JOptionPane.showMessageDialog(null,"我去,你怎么连电脑都输啊!","提示",JOptionPane.ERROR_MESSAGE);
				}
				else
				{
					JOptionPane.showMessageDialog(null,"恭喜,你终于赢电脑一把了!");
				}
				return true;
			}
			else	//人人对战
			{
				if(flag == this.gamePanel.WHITECHESS)
				{
					JOptionPane.showMessageDialog(null,"恭喜,白棋赢了!");
				}
				else
				{
					JOptionPane.showMessageDialog(null,"恭喜,黑棋赢了!");
				}
				return true;
			}
		}
		
		return false;
	}
	
	/**
	 * 功能:悔棋<br>
	 */
	public boolean undo()
	{
		if(this.gamePanel.isGameOver){return false;}
		if(this.gamePanel.listChess.size() < 1){return false;}

		//得到最后一步棋信息
		Map<String,Integer> mapLast = this.gamePanel.listChess.get(this.gamePanel.listChess.size() - 1);
		int flag = mapLast.get("flag");
		if(this.gamePanel.fightType == 0)	//人机对战(只有玩家才会悔棋,电脑才不会这么耍赖)
		{
			if(this.gamePanel.chessColor == 0)
			{
				if(this.gamePanel.blackUndoNum == 0)
				{
					JOptionPane.showMessageDialog(null,"悔棋次数已经全部用完了!","提示",JOptionPane.INFORMATION_MESSAGE);
					return false;
				}
				this.gamePanel.listChessBlack.remove(this.gamePanel.listChessBlack.size() - 1);
				this.gamePanel.listChess.remove(this.gamePanel.listChess.size() - 1);
				this.gamePanel.listChess.remove(this.gamePanel.listChess.size() - 1);
				this.gamePanel.blackUndoNum--;
			}
			else
			{
				if(this.gamePanel.whiteUndoNum == 0)
				{
					JOptionPane.showMessageDialog(null,"悔棋次数已经全部用完了!","提示",JOptionPane.INFORMATION_MESSAGE);
					return false;
				}
				this.gamePanel.listChessWhite.remove(this.gamePanel.listChessWhite.size() - 1);
				this.gamePanel.listChess.remove(this.gamePanel.listChess.size() - 1);
				this.gamePanel.listChess.remove(this.gamePanel.listChess.size() - 1);
				this.gamePanel.whiteUndoNum--;
			}
		}
		else
		{
			if(flag == this.gamePanel.WHITECHESS)
			{
				if(this.gamePanel.whiteUndoNum == 0)
				{
					JOptionPane.showMessageDialog(null,"白棋的悔棋次数已经全部用完了!","提示",JOptionPane.INFORMATION_MESSAGE);
					return false;
				}
				this.gamePanel.listChessWhite.remove(this.gamePanel.listChessWhite.size() - 1);
				this.gamePanel.listChess.remove(this.gamePanel.listChess.size() - 1);
				this.gamePanel.whiteUndoNum--;
			}
			else
			{
				if(this.gamePanel.blackUndoNum == 0)
				{
					JOptionPane.showMessageDialog(null,"黑棋的悔棋次数已经全部用完了!","提示",JOptionPane.INFORMATION_MESSAGE);
					return false;
				}
				this.gamePanel.listChessBlack.remove(this.gamePanel.listChessBlack.size() - 1);
				this.gamePanel.listChess.remove(this.gamePanel.listChess.size() - 1);
				this.gamePanel.blackUndoNum--;
			}
		}
		
		this.gamePanel.jlb_blackUndoText.setText("剩"+gamePanel.blackUndoNum+"次");
		this.gamePanel.jlb_whiteUndoText.setText("剩"+gamePanel.whiteUndoNum+"次");
		
		return true;
	}

	/**
	 * 功能:鼠标移动事件<br>
	 */
	public void mouseMoved(MouseEvent e)
	{
		//判断鼠标位置是否在棋盘内
		int x = e.getX();
		int y = e.getY();
		if(x > (this.gamePanel.chessBoradX - this.gamePanel.spaceSize / 2) && x < (this.gamePanel.chessBoradX + this.gamePanel.chessBoradWidth + this.gamePanel.spaceSize/2) && y > (this.gamePanel.chessBoradY - this.gamePanel.spaceSize / 2) && y < (this.gamePanel.chessBoradY + this.gamePanel.chessBoradHeight + this.gamePanel.spaceSize / 2))
		{
			if(this.gamePanel.isGameOver){return;}
			//清除落子指示器(先不显示)
			this.gamePanel.mapPointer.put("show",0);
			//将x,y由像素改为相应的水平与垂直线的数目(0~14)
			int lineX = this.getLineX(x);
			int lineY = this.getLineY(y);
			if(lineX >= 0 && lineX < 15 && lineY >= 0 && lineY < 15)
			{
				//判断该位置是否有棋子
				boolean isChess = false;
				for(int i=0;i<this.gamePanel.listChess.size();i++)
				{
					Map<String,Integer> map = this.gamePanel.listChess.get(i);
					if(map.get("x") == lineX && map.get("y") == lineY)
					{
						isChess = true;
						break;
					}
				}
				if(!isChess)	//可以显示了
				{
					this.gamePanel.mapPointer.put("x",lineX);
					this.gamePanel.mapPointer.put("y",lineY);
					this.gamePanel.mapPointer.put("show",1);
				}
			}
			this.gamePanel.repaint();
		}
		else
		{
			if(this.gamePanel.mapPointer.get("show") == 1)
			{
				this.gamePanel.mapPointer.put("show",0);
				this.gamePanel.repaint();
			}
		}
	}	
	
	/**
	 * 功能:鼠标单击事件<br>
	 */
	public void mouseClicked(MouseEvent e) 
	{
		if(e.getButton() == MouseEvent.BUTTON1)		//鼠标左键点击
		{
			//判断鼠标位置是否在棋盘内
			int x = e.getX();
			int y = e.getY();
			if(x > (this.gamePanel.chessBoradX - this.gamePanel.spaceSize / 2) && x < (this.gamePanel.chessBoradX + this.gamePanel.chessBoradWidth + this.gamePanel.spaceSize/2) && y > (this.gamePanel.chessBoradY - this.gamePanel.spaceSize / 2) && y < (this.gamePanel.chessBoradY + this.gamePanel.chessBoradHeight + this.gamePanel.spaceSize / 2))
			{
				if(this.gamePanel.isGameOver){return;}
				//将x,y由像素改为相应的水平与垂直线的数目(0~14)
				int lineX = this.getLineX(x);
				int lineY = this.getLineY(y);
				if(lineX >= 0 && lineX < 15 && lineY >= 0 && lineY < 15)
				{
					//判断该位置是否有棋子
					boolean isChess = false;
					for(int i=0;i<this.gamePanel.listChess.size();i++)
					{
						Map<String,Integer> map = this.gamePanel.listChess.get(i);
						if(map.get("x") == lineX && map.get("y") == lineY)
						{
							isChess = true;
							break;
						}
					}
					if(!isChess)	//玩家可以下棋了
					{
						//清除落子指示器
						this.gamePanel.mapPointer.put("show",0);
						//得到下一步是白棋下还是黑棋
						int chessColor = this.getNextChessColor();
						//记录玩家下棋
						Map<String,Integer> mapMan = new HashMap<String,Integer>();
						mapMan.put("x",lineX);
						mapMan.put("y",lineY);
						mapMan.put("flag",chessColor);
						if(chessColor == this.gamePanel.WHITECHESS)
						{
							this.gamePanel.listChessWhite.add(mapMan);
							this.gamePanel.jlb_whiteStateText.setText("已下完");
							this.gamePanel.jlb_blackStateText.setText("思考中");
						}
						else
						{
							this.gamePanel.listChessBlack.add(mapMan);
							this.gamePanel.jlb_blackStateText.setText("已下完");
							this.gamePanel.jlb_whiteStateText.setText("思考中");
						}
						this.gamePanel.listChess.add(mapMan);
						this.gamePanel.repaint();
						//判断游戏是否结束
						if(this.gameOver())
						{
							this.gamePanel.isGameOver = true;
							this.gamePanel.setComponentState(false);
							this.gamePanel.jlb_blackStateText.setText("已结束");
							this.gamePanel.jlb_whiteStateText.setText("已结束");
							return;
						}
						//判断双方是否战平(棋盘下满了)
						if(this.gamePanel.listChess.size() >= 225)
						{
							JOptionPane.showMessageDialog(null,"牛屁,你们竟然打平了!");
							this.gamePanel.isGameOver = true;
							this.gamePanel.initGame();
							return;
						}
						//如果是人机对战,机器要回应啊
						if(this.gamePanel.fightType == 0)	//人机对战
						{
							this.computerPlay();
							
							if(this.gamePanel.computerChess == this.gamePanel.BLACKCHESS)
							{
								this.gamePanel.jlb_blackStateText.setText("已下完");
								this.gamePanel.jlb_whiteStateText.setText("思考中");
							}
							else
							{
								this.gamePanel.jlb_whiteStateText.setText("已下完");
								this.gamePanel.jlb_blackStateText.setText("思考中");
							}
							//判断游戏是否结束
							if(this.gameOver())
							{
								this.gamePanel.isGameOver = true;
								this.gamePanel.setComponentState(false);
								this.gamePanel.jlb_blackStateText.setText("已结束");
								this.gamePanel.jlb_whiteStateText.setText("已结束");
								return;
							}
						}
					}
				}
			}
		}
		
	}
	
}

详解: 

待续...

运行: 

        做一个DOS批处理文件,gobang.bat,内容如下:

@echo off
start javaw com.game.gobang.Gobang

 下载: 

        百度网盘链接:https://pan.baidu.com/s/1jMU7es839gLtW6XXVFNMqw 提取码:ibkq

感言: 

待续...

猜你喜欢

转载自blog.csdn.net/lag_csdn/article/details/121950297