Java学习笔记(九)五子棋的实现,亦即Java学习的第一个项目

前段时间忙于考试,一直没时间写Java学习笔记。现在继续踏上Java学习的路程。前面学了界面、监听、继承等等知识,现在就用这些知识来实现自己的第一个Java项目。

五子棋的一些要求如下:

(1)点击开始新游戏的时候才能在棋盘上下棋;

(2)游戏结束后棋盘不能下棋;

(3)实现悔棋功能;

(4)实现认输功能;

(5)对战模式选择;

首先来思考几个问题:

1.实现五子棋所需的API类要哪些?
JFrame
BorderLayout          //这是一个布置容器的边框布局,它可以对容器组件进行安排,并调整其大小,使其符合下列五个区 域:北、南、东、西、中。每个区域最多只能包含一个组件,并通过相应的常量进行标识:NORTHSOUTHEASTWESTCENTER。当使用边框布局将一个组件添加到容器中时,要使用这五个常量之一。
JPanel 面板容器组件类
MouseAdapter | MouseListener
MouseEvent
Graphics | Graphics2D
RenderingHints //设置那个抗锯齿的,不然棋子看起来很糙,设置这个可以让棋子看起来更光滑。
Color
数组

2.界面实现
(1).重绘   //棋盘始终要显示在界面上,跟之前重绘的道理一样。
(2).继承
(3).swing界面


3.下棋子
(1).事件监听机制

(2).画图

(3).重绘

以上就是简单废话一下,下面我会具体说明如何实现。

一、棋盘界面实现:

玩过五子棋的都应该知道这个界面就是网格线,也就是画线呗。那么划线需要一个起点和终点。

那么确定一下棋盘应该有的属性:

(1)棋盘的大小,就是行ROW,和列COL;

(2)网格线的宽度SIZE,这样能让棋盘更好看些;

(3)棋子半径的大小

(4)第一个画线的起点坐标(X0,Y0)

为了方便修改我们的棋盘,我们把这些属性定义成一个接口,可供修改。

贴下代码:

public interface Config {
	
	public static final int X0 = 70;
	public static final int Y0 =50;
	public static final int ROWS = 12;
	public static final int COLUMS = 12;
      public static final int CHESS_SIZE =40;
      public static final int  SIZE = 50;

}

interface是关键字。

下面开始将棋盘的界面完善,用到JFrame,设置一下这个窗体的属性:大小、组件布局、窗体名字、添加面板、在面板里面添加按钮组件和下拉框组件。定义一个棋盘界面的类,让它继承JPanel类,或者JFrame,但这里继承JPanel好一些,因为我们主要用到的是JPanel。

public void Chessinit()
	{
		JFrame frame = new JFrame("五子棋");
		
		frame.setSize(800, 700);	
		frame.setLayout(new BorderLayout());
	}

这样就初始化了一个棋盘界面了。

然后添加JPanel组件:

JPanel eastPane = new JPanel();
eastPane.setPreferredSize(new Dimension(150,0));

为啥不用设置高度,因为选用了BorderLayout布局,不需要设置高度了。

然后就是添加一些按钮,比如开始新游戏、悔棋、认输等等,然后就是对战模式的选择。

添加按钮:

                JButton JBstart = new JButton("开始新游戏");
		JBstart.setPreferredSize(new Dimension(100,100));
		eastPane.add(JBstart);
		JButton JBback = new JButton("悔棋");
		JBback.setPreferredSize(new Dimension(100,100));
		eastPane.add(JBback);
		JButton JBgiveup = new JButton("认输");
		JBgiveup.setPreferredSize(new Dimension(100,100));
		eastPane.add(JBgiveup);
		String []type ={"人人对战","人机对战"};
		JComboBox<String>cItem  = new JComboBox<>(type);
		cItem.setPreferredSize(new Dimension(100,50));
		eastPane.add(cItem);

下拉框那个要用到JComboBox,type是一个String数组,存储了你给的选项,这样写可以直接添加整个数组,而不用一项一项的添加。

完事之后就把面板添加到窗体去吧。

代码就一句:frame.add(eastPane, BorderLayout.EAST);

第二个参数表示面板放置在东边,也就是棋盘的右侧。

下面开始重绘棋盘,重写下paint方法或者自己定义一个方法都可以。

代码如下:

public void paint(Graphics g)
	{
		super.paint(g);
		Graphics2D G = (Graphics2D)g;//g本身就是一个对象了。
		G.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
			RenderingHints.VALUE_ANTIALIAS_ON);
		
		for(int i=0;i<Config.ROWS;i++)
		{
			g.drawLine(Config.X0, Config.Y0+Config.SIZE*i, Config.X0+(Config.COLUMS-1)*Config.SIZE, Config.Y0+Config.SIZE*i);
		}
		for(int j=0;j<Config.COLUMS;j++)
		{
			g.drawLine(Config.X0+Config.SIZE*j, Config.Y0, Config.X0+Config.SIZE*j, Config.Y0+(Config.ROWS-1)*Config.SIZE);
			
		}
                //棋子重绘:
                	for(int i=0;i<Chess.length;i++)
		{
			for(int j=0;j<Chess.length;j++)
			{
				int x = Config.X0 + Config.SIZE*i;
				int y = Config.Y0 + Config.SIZE*j;
				
				if(Chess[i][j]==1)
				{
					
						g.setColor(Color.black);//
						
						Chess[i][j]=1;
						g.fillOval(x-Config.CHESS_SIZE/2,y-Config.CHESS_SIZE/2,Config.CHESS_SIZE,Config.CHESS_SIZE);
				}
				else if(Chess[i][j]==-1)
					{
						g.setColor(Color.white);
						
						Chess[i][j]=-1;
						g.fillOval(x-Config.CHESS_SIZE/2,y-Config.CHESS_SIZE/2,Config.CHESS_SIZE,Config.CHESS_SIZE);
					}
				
			}
		}

G.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);是设置那个抗锯齿,让棋子看起来更光滑。

二、添加监听

首先要创建一个监听器类,当你拿到动作信息后该干什么。想一下,当鼠标点击的时候是不是要在棋盘上画一个棋子呢?所以就要用到鼠标器适配类(这个包含了所有监听鼠标动作的方法),然后就是按钮动作信息捕捉,ActionListener提供了方法,所以还要继承接口。注意这里哦,前面那个是类,后面那个是接口,继承关键字分别为:extends、implements。继承接口后务必记得重写它的方法,不然会报错的。

1.先写鼠标点击后,在点击位置画棋子:

画棋子我们需要拿到画笔类,画笔在哪呢?窗体上啊!所以我们可以传一个窗体过来再取,或者在界面类那边传一个画笔类对象过来。你需要用到的东西需要定义属性来接受。怎么接受?用构造方法呗。我们还需要用到棋盘,因为要判断哪个位置是否下棋。

代码如下:

public class ChessListener extends MouseAdapter implements ActionListener {

	private ChessUI gm;
	private Graphics2D g;
        private int chess[][] = new int[Config.ROWS][Config.COLUMS]; 
        public ChessListener(ChessUI G, int[][] chess) {
		this.gm = G;
		this.chess = chess;
	}    }

拿到需要的东西后,就开始画棋子啦。

你可以选择在鼠标被按下或者释放后画,看自己。

如何让棋子在线的交叉点处画出来呢?先get到交叉点的坐标,然后以它为中心,一定的半径画出。

for (int j = 0; j < Config.ROWS; j++) {
			for (int i = 0; i < Config.COLUMS; i++) { //遍历整个棋盘,寻找可以画棋子的位置
				int x = Config.X0 + Config.SIZE * i;//对每个点都进行一个放大处理
				int y = Config.Y0 + Config.SIZE * j;
				if (x1 > x - Config.SIZE / 3 && x1 < x + Config.SIZE / 3 && y1 > y - Config.SIZE / 3
						&& y1 < y + Config.SIZE / 3) {//x1,y1是当前鼠标点击位置的坐标:x1=e.getX()....
					if (chess[i][j] == 0) { //0表示当前位置没有棋子

						if (count == 0) {//count=0表示画白棋子,1画黑棋子
						

							g.setColor(Color.white);// 设置画棋子的颜色
							g.fillOval(x - Config.CHESS_SIZE / 2, y - Config.CHESS_SIZE / 2, Config.CHESS_SIZE,
									Config.CHESS_SIZE);
							Point ch = new Point(i,j,count);//这先不管,悔棋用到的。
							chessList[chessCount++]=ch;//这也是悔棋用到的
							count = 1;//设置为1,表示下一次画的是黑棋
							chess[i][j] = -1;//该位置设置为-1,表示该位置画了白棋,设置为1表示画了黑棋。
							
							if (Judge(i, j)) {//这是判断输赢的,每下一个棋子都要判断一次,也先不管。
								// System.out.println("黑棋赢了!");
								String msg = String.format("恭喜,%s赢啦~", "白棋 win!");//弹出框
								JOptionPane.showMessageDialog(gm, msg);
								gameover = 1;//游戏是否接受的标志
							}
						} else if (count==1){//画黑棋,跟白棋一样的。
							

							g.setColor(Color.black);
							g.fillOval(x - Config.CHESS_SIZE / 2, y - Config.CHESS_SIZE / 2, Config.CHESS_SIZE,
									Config.CHESS_SIZE);
							Point ch = new Point(i,j,count);
							chessList[chessCount++]=ch;
							count = 0;
							chess[i][j] = 1;
							
							if (Judge(i, j)) {
								// System.out.println("白棋赢了!");
								String msg = String.format("恭喜,%s赢啦~", "黑棋 win!");
								JOptionPane.showMessageDialog(gm, msg);
								gameover = 1;

							}
						}

						return;
					}
				}
			}
		}
	}

下棋的写完了。该写下监听了。

2.给按钮添加监听:

重写监听方法:

当点击按钮的时候该干嘛:这里也顺带把三个功能如何实现一并说了。

public void actionPerformed(ActionEvent e) {
		if (e.getSource() instanceof JComboBox) {instanceof关键字主要功能是判断这个事件源是不是它的
			JComboBox<String> comboBox = (JComboBox) e.getSource();// 拿到对象
			fontName = comboBox.getSelectedItem().toString();// 拿到下拉菜单被选择的内容,因为我们要确定它选择了哪种对战模式
		}
		if (e.getActionCommand() == "开始新游戏") {//开始新游戏的话把棋盘数组重置一下,系统重绘的时候会扫一遍这个数组,都为0,系统就不会重绘棋子了。
			for (int i = 0; i < chess.length; i++) {
				for (int j = 0; j < chess.length; j++) {
					chess[i][j] = 0;
				}
			}
			gameover = 0;//要把状态都恢复到初始
		//	System.out.println("okok  " + gameover);
			gm.repaint();//系统重绘棋盘
			count = 1;//第一步先画黑棋(就是黑棋先行)
		} else if (e.getActionCommand() == "悔棋") {
			
			this.GoBack();//Goback函数的就是定义一个类专门去保存你画的棋子的信息:坐标、颜色。具体代码在最尾部贴出,当点击悔棋的时候就取 
			上一次保存的棋子的位置取出来还原为未下棋子的状态,然后再重绘一下棋盘即可。
			
		} else if (e.getActionCommand() == "认输") {//通过判断当前是谁刚下完棋,点击认输后就是它赢,比如当前白棋刚下完,到黑棋下,但它认输,所以是白棋赢;
			if (count == 0) {
				String msg = String.format("恭喜,%s赢啦~", "黑棋 win!");
				JOptionPane.showMessageDialog(gm, msg);
			} else if (count == 1) {
				String msg = String.format("恭喜,%s赢啦~", "白棋 win!");
				JOptionPane.showMessageDialog(gm, msg);
				
			}
		}
	}

写完后就添加监听到按钮去吧,这些组件都共用一个监听:

在你的棋盘界面添加如下代码:

ChessListener L = new ChessListener(this,Chess);//共用一个监听即可。
		JBstart.addActionListener(L);
		JBback.addActionListener(L);
		JBgiveup.addActionListener(L);
		cItem.addActionListener(L);
		
		frame.setLocationRelativeTo(null);
		frame.setDefaultCloseOperation(3);
		frame.setResizable(false);
		
		frame.add(this);
		frame.setVisible(true);
		
		this.addMouseListener(L);

然后完整的棋盘界面代码如下:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.event.AncestorListener;

public class ChessUI extends JPanel{
	
	public static void main(String args[])
	{
		ChessUI ch = new ChessUI();
		ch.Chessinit();
	}
	private int Chess[][] = new int[Config.ROWS][Config.COLUMS];
	public void Chessinit()
	{
		JFrame frame = new JFrame("五子棋");
		
		frame.setSize(800, 700);	
		frame.setLayout(new BorderLayout());
		
		JPanel eastPane = new JPanel();
		/*添加一系列按钮并设置他们的属性*/
		
		eastPane.setPreferredSize(new Dimension(150,0));
		JButton JBstart = new JButton("开始新游戏");
		JBstart.setPreferredSize(new Dimension(100,100));
		eastPane.add(JBstart);
		JButton JBback = new JButton("悔棋");
		JBback.setPreferredSize(new Dimension(100,100));
		eastPane.add(JBback);
		JButton JBgiveup = new JButton("认输");
		JBgiveup.setPreferredSize(new Dimension(100,100));
		eastPane.add(JBgiveup);
		String []type ={"人人对战","人机对战"};
		JComboBox<String>cItem  = new JComboBox<>(type);
		cItem.setPreferredSize(new Dimension(100,50));
		eastPane.add(cItem);
		eastPane.setBackground(Color.orange);
		/*棋盘的监听*/

		ChessListener L = new ChessListener(this,Chess);//共用一个监听即可。
		JBstart.addActionListener(L);
		JBback.addActionListener(L);
		JBgiveup.addActionListener(L);
		cItem.addActionListener(L);
		
		
		
		frame.add(eastPane, BorderLayout.EAST);//添加面板
		frame.setBackground(Color.orange);
		frame.setLocationRelativeTo(null);
		frame.setDefaultCloseOperation(3);
		frame.setResizable(false);
		
		frame.add(this);
		frame.setVisible(true);
		
		this.addMouseListener(L);
	}
	/*重绘棋盘*/
	
	public void paint(Graphics g)
	{
		super.paint(g);
		Graphics2D G = (Graphics2D)g;//g本身就是一个对象了。
		G.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
			RenderingHints.VALUE_ANTIALIAS_ON);
		
		for(int i=0;i<Config.ROWS;i++)
		{
			g.drawLine(Config.X0, Config.Y0+Config.SIZE*i, Config.X0+(Config.COLUMS-1)*Config.SIZE, Config.Y0+Config.SIZE*i);
		}
		for(int j=0;j<Config.COLUMS;j++)
		{
			g.drawLine(Config.X0+Config.SIZE*j, Config.Y0, Config.X0+Config.SIZE*j, Config.Y0+(Config.ROWS-1)*Config.SIZE);
			
		}
		/*棋子重绘*/
		
		for(int i=0;i<Chess.length;i++)
		{
			for(int j=0;j<Chess.length;j++)
			{
				int x = Config.X0 + Config.SIZE*i;
				int y = Config.Y0 + Config.SIZE*j;
				
				if(Chess[i][j]==1)
				{
					
						g.setColor(Color.black);//设置下一次画棋子的颜色
						
						Chess[i][j]=1;
						g.fillOval(x-Config.CHESS_SIZE/2,y-Config.CHESS_SIZE/2,Config.CHESS_SIZE,Config.CHESS_SIZE);
				}
				else if(Chess[i][j]==-1)
					{
						g.setColor(Color.white);
						
						Chess[i][j]=-1;
						g.fillOval(x-Config.CHESS_SIZE/2,y-Config.CHESS_SIZE/2,Config.CHESS_SIZE,Config.CHESS_SIZE);
					}
				
			}
		}
	}
  }

这里就得到一个完整的棋盘界面了。

3.判断输赢:

思路就是每个方向都统计一下同色的棋子是否够五个。比较简单的方法就是循环遍历了。

private boolean Judge(int xx, int yy) {
		int count = 1;
		for (int i = xx - 1; i >= 0; i--)// 横向向左找
		{
			if (chess[i][yy] == chess[xx][yy]) {
				count++;
				// System.out.println("(Left)Count:"+count);
			} else
				break;
		}

		for (int i = xx + 1; i < chess.length; i++)// 横向向右找
		{
			if (chess[i][yy] == chess[xx][yy]) {
				count++;
				// System.out.println("Count:"+count);
			} else
				break;
		}
		if (count >= 5) {
			return true;
		} else {
			count = 1;
		}
		for (int j = yy - 1; j >= 0; j--)// 纵向向上
		{
			if (chess[xx][j] == chess[xx][yy]) {
				count++;
				// System.out.println("(UP)Count:"+count);
			} else
				break;
		}
		for (int j = yy + 1; j < chess.length; j++)// 纵向向下
		{
			if (chess[xx][j] == chess[xx][yy]) {
				count++;

			} else
				break;
		}
		if (count >= 5) {
			return true;
		} else {
			count = 1;
		}
		for (int i = xx + 1, j = yy - 1; j >= 0 && i < chess.length; i++, j--)// 右下
		{
			if (chess[i][j] == chess[xx][yy]) {
				count++;
			} else
				break;
		}
		for (int i = xx - 1, j = yy + 1; i >= 0 && j < chess.length; i--, j++)// 左上
		{
			if (chess[i][j] == chess[xx][yy]) {
				count++;
			} else
				break;
		}
		if (count >= 5) {
			return true;
		} else {
			count = 1;
		}
		for (int i = xx + 1, j = yy + 1; j < chess.length && i < chess.length; i++, j++)// 右上
		{
			if (chess[i][j] == chess[xx][yy]) {
				count++;
			} else
				break;
		}
		for (int i = xx - 1, j = yy - 1; i >= 0 && j >= 0; i--, j--)// 左下
		{
			if (chess[i][j] == chess[xx][yy]) {
				count++;
			} else
				break;
		}
		if (count >= 5) {
			return true;
		} else {
			count = 1;
		}
		// System.out.println("Count:"+count);
		return false;

	}

4.悔棋:

思路我在前面说了一下,就是像画板重绘那样,保存你画的每一个棋子即可。

Point类:

public class Point {
	
		private int x;//索引x
		private int y;
		private int count=0;//表示当前棋子的颜色
		public Point(int x,int y,int count)
		{
			this.x=x;
			this.y=y;
			this.count=count;
		}
		public int getx()
		{
			return x;
		}
		public int gety()
		{
			return y;
		}
}

监听类中实现GoBack()函数:

public void GoBack()
	{
		if(chessCount==0)//chessCount用来记录当前下的棋子个数
			return ;
		if(chessCount>0){
			xIndex=chessList[chessCount-1].getx();
			yIndex=chessList[chessCount-1].gety();
			chess[xIndex][yIndex]=0;
		}
		chessList[chessCount-1]=null;
		chessCount--;	
		gm.repaint();//重绘棋盘

	}

三、接下来是实现人人对战和人机对战。

1.人人对战:

人人对战比较简单,将上面我贴出来画旗子的那个代码封装成一个pvp方法,在mousePressed里面调用就可以了。

2.人机对战(我的人机有点蠢,后期找时间优化一下)

电脑下棋可以用很多种方法实现,比如权值法、博弈树、机器学习。

但只是简单入门,就用一下权值法。

先来科普一下棋盘可能的情况:

活连:当你下完某课棋子的时候,从它的左或右看过去,没有被异色的棋子挡住就是活连,比如连续的三个黑棋,左右两边都还能下黑棋。

如图:


对于黑棋来说,它目前是活三连,白棋是活二连,最多只可能是活四连。

然后是眠连,眠连跟活连的区别就是眠连有一边被异色棋子堵住了。

如图:


当前黑棋是眠四连。

眠连和活连都是最大只有四。那么给他们定义一下权值,权值大的位置优先被选择下棋。

活一连:10             眠一连:1

活二连:80             眠二连:50

活三连:100           眠三连:100

活四连:3000         眠四连:2500

为什么最后两个权值设那么大?为了保证其它情况的权值总和加起来不大于四连,否则四连就没有意义了。权值如何设置看自己,但要保证满足我说的这个条件即可。

如何将棋子的情况跟它的权值映射起来呢?可以考虑选用map这个数据结构,我下面列出了一些可能的情况,0表示空位,1表示黑棋,-1表示白棋。要想你的AI更智能,就尽可能的考虑更多的情况。

代码如下:

private static HashMap<String,Integer> map = new HashMap<String,Integer>();
	static{
		
		map.put("010",10);//活一连(黑)
		map.put("0-10", 10);//活一连(白)
		map.put("01010", 80);//活二连(黑)
		map.put("0110", 80);//活二连(黑)
		map.put("0-10-10", 80);//活二连(白)
		map.put("0-1-10", 80);//活二连(白)
		map.put("01110", 100);//活三连(黑)
		map.put("0-1-1-10", 100);//活三连(白)
		map.put("011110", 3000);//活四连(黑)
		map.put("0-1-1-1-10", 3000);//活四连(白)
		map.put("1-1", 1);//眠一连(黑)
		map.put("-11", 1);//眠一连(白)
		map.put("011-1", 50);//眠二连(黑)
		map.put("-1110", 50);//眠二连(黑)
		map.put("0-1-11", 50);//眠二连(白)
		map.put("1-1-10", 50);//眠二连(白)
		map.put("0111-1", 100);//眠三连(黑)
		map.put("-11110", 100);//眠三连(黑)
		map.put("0-1-1-11", 100);//眠三连(白)
		map.put("1-1-1-10", 100);//眠三连(白)
		map.put("01111-1", 250);//眠四连(黑)
		map.put("-111110", 250);//眠四连(黑)
		map.put("1-1-1-1-10", 2500);//眠四连(白)
		map.put("0-1-1-1-11", 2500);//眠四连(白)
	
	}

由于我的棋盘是人先行,所以计算权值就不用考虑那么多了。计算权值就是当人下完一颗棋子后,这个方法就要开始计算当前棋盘棋子的情况有哪些,比如活一连啊活二连的情况有多少,然后计算活一连的权值总和并存储到数组里面去,计算权值的时候会对每一个空位都进行计算。如何统计当前棋盘有哪些连,跟判断输赢类似,也是分方向,每个方向都去找,找完了就计算一次那个方向的权值。代码如下:(hin长!),希望有大佬帮我优化一下,记得考虑边界,不然会发生越界的哦。

public void Search()
	{
		for(int r=0;r<chess.length;r++)
		{
			for(int c=0;c<chess.length;c++)//遍历整个棋盘
			{
				if(chess[r][c]==0)//该位置没有棋子
				{
					int num=0;//空位出现的次数
					String code="0";//棋子相连的情况
					int chesscount=0;//记录当前出现的棋子
					for(int c1=c-1;c1>=0;c1--)//向左
					{
						if(chess[r][c1]==0)//空位
						{
							if(c==c1+1) break;
							
							else if(num==0)
							{
								code+=chess[r][c1];
								num++;
							}
							else if(num==1)
							{
								if(chess[r][c1]==chess[r][c1+1]) break;
								code+=chess[r][c1];
								num++;
							}
							else if(num==3)
							{
								if(chess[r][c1]==chess[r][c1+1]) break;
							}
							
						}
						else//有棋子
						{
							if(chesscount==0)//第一次出现棋子
							{
								chesscount=chess[r][c1];
								code+=chess[r][c1];
							}
							else if(chess[r][c1]==chesscount)
							{
								code+=chess[r][c1];
							}
							else
							{
								code+=chess[r][c1];
								break;
							}
						}
						
					}
					Integer value = map.get(code);
					if(value!=null){//判断value是否不为null
					weightArray[r][c]+=value;//在对应空位累加权值
				}
				/*----------------------------------------------*/
				//向右
					for(int c1=c+1;c1<chess.length-1;c1++)
					{
						if(chess[r][c1]==0)
						{
							if(c==c1-1) break;
							
							else if(num==0)
							{
								code+=chess[r][c1];
								num++;
							}
							else if(num==1)
							{
								if(chess[r][c1]==chess[r][c1+1]) break;
								code+=chess[r][c1];
								num++;
							}
							else if(num==3)
							{
								if(chess[r][c1]==chess[r][c1+1]) break;
							}
							
						}
						else//有棋子
						{
							if(chesscount==0)//第一次出现棋子
							{
								chesscount=chess[r][c1];
								code+=chess[r][c1];
							}
							else if(chess[r][c1]==chesscount)
							{
								code+=chess[r][c1];
							}
							else
							{
								code+=chess[r][c1];
								break;
							}
						}
						
					}
					 value = map.get(code);
					if(value!=null){//判断value是否不为null
					weightArray[r][c]+=value;//在对应空位累加权值
				}
				/*----------------------------------------------*/
				//up
					
					for(int r1=r-1;r1>=0;r1--)
					{
						if(chess[r1][c]==0)
						{
							if(r==r1+1) break;
							
							else if(num==0)
							{
								code+=chess[r1][c];
								num++;
							}
							else if(num==1)
							{
								if(chess[r1][c]==chess[r1+1][c]) break;
								code+=chess[r1][c];
								num++;
							}
							else if(num==3)
							{
								if(chess[r1][c]==chess[r1+1][c]) break;
							}
							
						}
						else//有棋子
						{
							if(chesscount==0)//第一次出现棋子
							{
								chesscount=chess[r1][c];
								code+=chess[r1][c];
							}
							else if(chess[r1][c]==chesscount)
							{
								code+=chess[r1][c];
							}
							else
							{
								code+=chess[r1][c];
								break;
							}
						}
						
					}
					
					 value = map.get(code);
					if(value!=null){//判断value是否不为null
					weightArray[r][c]+=value;//在对应空位累加权值
				}
				/*----------------------------------------------*/
				//down

					for(int r1=r+1;r1<chess.length-1;r1++)
					{
						if(chess[r1][c]==0)
						{
							if(r==r1-1) break;
							
							else if(num==0)
							{
								code+=chess[r1][c];
								num++;
							}
							else if(num==1)
							{
								if(chess[r1][c]==chess[r1+1][c]) break;
								code+=chess[r1][c];
								num++;
							}
							else if(num==3)
							{
								if(chess[r1][c]==chess[r1+1][c]) break;
							}
							
						}
						else//有棋子
						{
							if(chesscount==0)//第一次出现棋子
							{
								chesscount=chess[r1][c];
								code+=chess[r1][c];
							}
							else if(chess[r1][c]==chesscount)
							{
								code+=chess[r1][c];
							}
							else
							{
								code+=chess[r1][c];
								break;
							}
						}
						
					}
					 value = map.get(code);
					if(value!=null){//判断value是否不为null
					weightArray[r][c]+=value;//在对应空位累加权值
				}
					
					/*------for (int i = xx + 1, j = yy - 1; j >= 0 && i < chess.length; i++, j--)// 右下----------------------------------------*/
					//右下
					for(int i=r+1,j=c-1;j>=0&&i<chess.length-1;i++,j--)
					{
						if(chess[i][j]==0)
						{
							if(r==i-1 && c==j+1) break;
							else if(num==0)
							{
								code+=chess[i][j];
								num++;
							}
							else if(num==1)
							{
								if(chess[i][j]==chess[i+1][j+1]) break;
								code+=chess[i][j];
								num++;
							}
							else if(num==3)
							{
								if(chess[i][j]==chess[i+1][j+1]) break;
							}
							
						}
						else//有棋子
						{
							if(chesscount==0)//第一次出现棋子
							{
								chesscount=chess[i][j];
								code+=chess[i][j];
							}
							else if(chess[i][j]==chesscount)
							{
								code+=chess[i][j];
							}
							else
							{
								code+=chess[i][j];
								break;
							}
						
						}
					}
					value = map.get(code);
					if(value!=null){//判断value是否不为null
					weightArray[r][c]+=value;//在对应空位累加权值
					}
					 /*------------------------------------*/
					/*左上*/
					for(int i=r-1,j=c+1;i>=0&&j<chess.length-1;j++,i--)
					{
						if(chess[i][j]==0)
						{
							if(r==i+1 && c==j-1) break;
							else if(num==0)
							{
								code+=chess[i][j];
								num++;
							}
							else if(num==1)
							{
								if(chess[i][j]==chess[i+1][j+1]) break;
								code+=chess[i][j];
								num++;
							}
							else if(num==3)
							{
								if(chess[i][j]==chess[i+1][j+1]) break;
							}
							
						}
						else//有棋子
						{
							if(chesscount==0)//第一次出现棋子
							{
								chesscount=chess[i][j];
								code+=chess[i][j];
							}
							else if(chess[i][j]==chesscount)
							{
								code+=chess[i][j];
							}
							else
							{
								code+=chess[i][j];
								break;
							}
						
						}
					}
					value = map.get(code);
					if(value!=null){//判断value是否不为null
					weightArray[r][c]+=value;//在对应空位累加权值
					}
					 /*------------------------------------*/
					/*右上*/
					for(int i=r+1,j=c+1;i<chess.length-1&&j<chess.length-1;j++,i++)
					{
						if(chess[i][j]==0)
						{
							if(r==i-1 && c==j-1) break;
							else if(num==0)
							{
								code+=chess[i][j];
								num++;
							}
							else if(num==1)
							{
								if(chess[i][j]==chess[i+1][j+1]) break;
								code+=chess[i][j];
								num++;
							}
							else if(num==3)
							{
								if(chess[i][j]==chess[i+1][j+1]) break;
							}
							
						}
						else//有棋子
						{
							if(chesscount==0)//第一次出现棋子
							{
								chesscount=chess[i][j];
								code+=chess[i][j];
							}
							else if(chess[i][j]==chesscount)
							{
								code+=chess[i][j];
							}
							else
							{
								code+=chess[i][j];
								break;
							}
						
						}
					}
					 value = map.get(code);
					if(value!=null){//判断value是否不为null
					weightArray[r][c]+=value;//在对应空位累加权值
				}
					 /*------------------------------------*/
					/*左下*/
					for(int i=r-1,j=c-1;i>=0&&j>=0;j--,i--)
					{
						if(chess[i][j]==0)
						{
							if(r==i+1 && c==j+1) break;
							else if(num==0)
							{
								code+=chess[i][j];
								num++;
							}
							else if(num==1)
							{
								if(chess[i][j]==chess[i+1][j+1]) break;
								code+=chess[i][j];
								num++;
							}
							else if(num==3)
							{
								if(chess[i][j]==chess[i+1][j+1]) break;
							}
							
						}
						else//有棋子
						{
							if(chesscount==0)//第一次出现棋子
							{
								chesscount=chess[i][j];
								code+=chess[i][j];
							}
							else if(chess[i][j]==chesscount)
							{
								code+=chess[i][j];
							}
							else
							{
								code+=chess[i][j];
								break;
							}
						
						}
					}	
					//计算weight
					value = map.get(code);
					if(value!=null){//判断value是否不为null
					weightArray[r][c]+=value;//在对应空位累加权值
					}
				}/*---if---*/		
			}/*第一个for*/
		}/*第二个for*/
	}

电脑画棋子的代码补一下吧:

public void pve_draw()
	{
		this.Search();
		int max=-1;
		int xIndex=0;
		int yIndex=0;
		for(int i=0;i<weightArray.length;i++)
		{
			for(int j=0;j<weightArray.length;j++)
			{	
				if(weightArray[i][j]>max)//找到第一个最大的
				{
					max=weightArray[i][j];
					xIndex=i;
					yIndex=j;
				}
			}
		}
		
		
		/*-------------TEST--------------*/
		for(int i=0;i<weightArray.length;i++)
		{
			for(int j=0;j<weightArray.length;j++)
			{	
				System.out.print(weightArray[i][j]+" ");
				
			}
			System.out.println();
			
		}
		System.out.println("所选最大权值位置为:"+xIndex+" "+yIndex+"最大权值:"+max);
            
              /*-------------TEST--------------*/
if(chess[xIndex][yIndex]==0){g = (Graphics2D) gm.getGraphics();g.setColor(Color.white);g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);g.fillOval(Config.X0+xIndex*Config.SIZE- Config.CHESS_SIZE / 2, Config.Y0+yIndex*Config.SIZE - Config.CHESS_SIZE / 2, Config.CHESS_SIZE,Config.CHESS_SIZE);Point ch = new Point(xIndex,yIndex,count);//保存电脑画的棋子,悔棋要用的chessList[chessCount++]=ch;chess[xIndex][yIndex] = -1;weightArray[xIndex][yIndex]=0;//用了这个点清空if (Judge(xIndex, yIndex)) {String msg = String.format("恭喜,%s赢啦~", "白棋 win!");JOptionPane.showMessageDialog(gm, msg);gameover = 1;}}}

核心的东西都已经写完了,把人人对战和人机对战封装成两个方法,根据选择的对战模式进行相应的调用即可。

下面附一个完整的代码:https://paste.ubuntu.com/p/dTJx6MQ49y/

运行方法:新建一个Java工程,分别建四个类,把对应的代码放入,运行即可。

声明:emmm这五子棋有个小小的bug,就是电脑有的时候会下少一次棋子,应该是计算权值的时候出错了,希望有大神能解决这个bug。我本人也在努力的解决这个buging。有机会会回来完善这个博客的。如有不懂的欢迎下方留言,我们一起讨论。

贴个图:


猜你喜欢

转载自blog.csdn.net/weixin_42294984/article/details/80859031
今日推荐