当前位置:首页 » 《资源分享》 » 正文

实现五子棋的简单人人对战和人机对战的万字详细教程_yuanrunze的博客

10 人参与  2021年03月15日 17:43  分类 : 《资源分享》  评论

点击全文阅读


创建一个窗体来承载五子棋

如何创建一个窗体,以及如何在窗体上添加必要的按钮组件等操作,可以查看我的第一篇文章,里面有详细的讲解,这里就不在重新累述。具体的代码如下:

public class DrawUI{
      public void ShowUI(){
      MyFrame jf=new MyFrame();//这里原本应该是使用JFrame但,后续重绘中创建了子类MyFrame继承父类JFrame,这里就换成了MyFrame
  //设置窗体属性
      jf.setSize(500,500);
      jf.setLocationRelativeTo(null);
      jf.setTitle("五子棋");
      jf.setResizable(true);
      jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      FlowLayout fl=new FlowLayout();//设置窗体格式
      jf.setLayout(fl);
      JButton jb=new JButton("人人对战");//添加按钮
      JButton jb1=new JButton("悔棋");
      JButton jb2=new JButton("清空棋盘");
      JButton jb3=new JButton("人机对战");
      jf.add(jb);
      jf.add(jb1);
      jf.add(jb2);
      jf.add(jb3);
      jf.setVisible(true);
      Graphics g=jf.getGraphics();//给窗体添加画笔
      UIListener ul=new UIListener();
      jb.addActionListener(ul);//给按钮添加监听器
      jb1.addActionListener(ul);
      jb2.addActionListener(ul);
      jb3.addActionListener(ul);
      jf.addMouseListener(ul);//给窗体添加监听器
      ul.gr=g;//将画笔倒给UIlistener中的gr
      jf.ul=ul;//为了在Myframe中使用ChessArray,将UIistener中的ul倒给Myframe中的ul
      ul.jb11=jb;//将按钮jb倒给ul中的jb11,方便其使用jb
      ul.mf=jf;//为了在UIlistener中重绘,将jf倒给其中的mf
  }
}

五子棋基本程序编写

绘制棋盘

第一步肯定是要在创建好的窗体上绘制出五子棋的棋盘。思路也很简单,就是画出横竖两条线,然后设置一个固定间隔,不断循环,绘制出一个棋盘。

这里注意,因为如果只是在窗体中绘制出棋盘,那么每次窗体被拖动,刷新后,窗体中的绘制好的棋盘就会被刷新掉,所以需要重绘,确保棋盘永久存在,所以在这里,我们就直接将棋盘绘制在窗体重绘方法中。

public class MyFrame extends JFrame{//MyFrame子类继承JFrame父类
	public void paint(Graphics g) {//重绘棋盘,确保刷新网页时候,棋盘还在
		super.paint(g);
		int x1,x2,y1,y2;
		int X1,X2,Y1,Y2;
		x1=50;x2=450;y1=70;y2=470;
		X1=50;X2=450;Y1=70;Y2=470;
		for(int i=0; i<21; i++) {
		       g.drawLine(x1,y1,x2,y1);
		       y1=y1+20;
		       
		}
		for(int i=0; i<21; i++) {
			  g.drawLine(X1,Y1,X1,Y2);
			  X1=X1+20;
		}
	}
}

这里也需要注意:因为重绘方法是需要写在MyFrame类中的,由于后续还会有需要重绘的东西,所以后续会在这部分继续扩充需要重绘的内容代码。

绘制棋子(人人对战中棋子黑白交替出现,人机对战中玩家下黑子,电脑下白子)

绘制棋子时候,我们应该能清楚思路。

首先,鼠标点击的位置,这个位置不一定正好是在棋盘的网格交汇处的节点上,我们就要将这个鼠标点击的坐标优化至附近的交汇节点上。原理也很简单,将鼠标点击获取的坐标,计算转化成其在哪两个焦点之间,然后将两个节点之间一分为二,如果坐标在前部分,则优化到前面的节点上,如果在后半部分,则优化到后面的节点上。

其次,将鼠标点击的坐标优化到棋盘网格节点上后,则需要在这个网格节点上绘制棋子即可,但这里我们会发现,程序中绘制的圆形图形的时候,输入的绘制坐标点是绘制出来圆形的外切长方形的左上角的坐标,并非是圆形的圆心坐标。这时同样需要优化,将坐标分别减去它的半径,就能优化在鼠标点击转化过来的网格点上。

最后,我们需要存储已经下过的棋子的信息,方便后续判定输赢,已经棋子重绘时使用。这里为了存储棋子信息,我们就可以设立一个二维数组,二维数组正好对应横竖棋盘的网格,我们可以将黑棋的数组值定为1,白棋的数组值定为2。那么没有棋子的地方的数组值就为默认的0.

具体来看代码:

public class UIListener implements MouseListener ,ActionListener{//监听器是接口
//后续可能会用到的一些变量
	Graphics gr;
	int[][] ChessArray=new int[22][22];//黑白棋子数组
	int[][] ChessValue=new int[22][22];//AI人机中权值数组
	JButton jb11;
	int nb=0;
	int count=0;
	int a,b,x,y,X,Y;
	JFrame mf;
	HashMap<String,Integer> hm=new HashMap<String,Integer>();//设置AI人机中权值量表
	public void mouseClicked(MouseEvent e) {
		int z=50,c=20;
		Color c1=new Color(0,0,0);
		Color c2=new Color(255,255,255);
	    a=e.getX();b=e.getY();//获得鼠标点击坐标
	    if(nb==1) {//确定是否可以下棋
	    if((a-z)%c>c/2) {//帮助x轴上点击点优化到坐标格子上
	    	x=(a-z)/c+1;
	    }else {
	    	x=(a-z)/c;
	    }
	    if((b-z)%c>c/2) {//帮助y轴上点击点优化到坐标格子上
	    	y=(b-z)/c+1;
	    }else {
	    	y=(b-z)/c;
	    }
	    if(ChessArray[x][y]==0) {//确保棋子只能下在没有棋子的地方
	    		if(zifu.equals("人机对战")) {
	    			gr.setColor(c1);
	    	    	gr.fillOval(x*c+z-10, y*c+z-10, 20, 20);
	    	    	ChessArray[x][y]=1;
	    	    	gr.setColor(c2);
	    	    	AI();
	    		}else if(zifu.equals("人人对战")) {
	    			if(count==0) {
	    	    	gr.setColor(c1);
	    	    	count++;
	    	    	gr.fillOval(x*c+z-10, y*c+z-10, 20, 20);
	    	    	ChessArray[x][y]=1;//黑子数组值为1,方便重绘使用
	    	        }else if(count==1) {
	    	    	gr.setColor(c2);
	    	    	count--;
	    	    	gr.fillOval(x*c+z-10, y*c+z-10, 20, 20);
	    	    	ChessArray[x][y]=2;//白子数组值为21,方便重绘使用
	    	        }
	    		}
	    }else{
	    	System.out.println("该位置已有棋子");
	    }
	 }else {
		 System.out.println("请选择对战类型");
	 }
}

重绘棋子

在绘制出棋子后,我们同样需要去意识到,拖动窗体或者任何会让窗体刷新的操作后,已经下好的棋子都会消失,那么我们就需要在重绘方法中,同样加入棋子的重绘,也就是正在绘制棋盘这个标题下的代码行中加入重绘棋子的代码。

原理则是,因为我们设置了数组保存棋子,黑棋都赋值了1,白棋都赋值了2,那么我就遍历整个棋盘上上的所有数组,然后把数组等于1和2的都重绘出来即可。

加入了棋子重绘的代码后,整个重绘部分的代码就如下:

public class MyFrame extends JFrame{//MyFrame子类继承JFrame父类
	public UIListener ul;
//	int[][] ChessArray;
	int z=50,c=20;
	public void paint(Graphics g) {//重绘棋盘,确保刷新网页时候,棋盘还在
		super.paint(g);
		int x1,x2,y1,y2;
		int X1,X2,Y1,Y2;
		x1=50;x2=450;y1=70;y2=470;
		X1=50;X2=450;Y1=70;Y2=470;
		for(int i=0; i<21; i++) {
		       g.drawLine(x1,y1,x2,y1);
		       y1=y1+20;
		       
		}
		for(int i=0; i<21; i++) {
			  g.drawLine(X1,Y1,X1,Y2);
			  X1=X1+20;
		}

		int[][] ChessArray = ul.ChessArray;
		for(int i=0;i<ChessArray.length;i++) {//重绘棋子,网页刷新后,之前下过的棋子还在
			for(int j=0;j<ChessArray.length;j++) {
				if(ChessArray[i][j]==1) {
					g.setColor(Color.black);
					g.fillOval(i*c+z-10, j*c+z-10, 20, 20);
				}
				if(ChessArray[i][j]==2) {
					g.setColor(Color.white);
					g.fillOval(i*c+z-10, j*c+z-10, 20, 20);
				}
			}
		}
	}

}

判定输赢

当棋子都下好了之后,我们就需要在每下一颗棋子后进行输赢的判定。五子棋中,有五颗棋子连在一起即为获胜。因此我们就需要对横竖斜四个大方向上的棋子,进行查找判定。

原理则是因为黑棋的数组值都为1,白棋都为2,那么就在每一次所下棋子的地方为起点,向各个方向查找,每有一个相连的棋子是同色,设置一个变量count,count就加1,当count变为5时候,就证明有五个同色棋子相连,游戏就结束,如果所下棋子是黑棋,黑棋就获胜,如果所下棋子是白棋,白棋就获胜。

下列代码是判定寻找各个方向的同色棋子的方法:

public int Win1(int xx,int yy) {//判定横向棋子是否有相连的
		int count1=0;
		for(int i=xx-1;i>=0;i--) {
			if(ChessArray[i][yy]==ChessArray[xx][yy]) {
				count1++;
			}else break;
		}
		for(int j=xx;j<ChessArray.length;j++) {
			if(ChessArray[j][yy]==ChessArray[xx][yy]) {
				count1++;
			}else break;
		}
		return count1;
	}
	
	public int Win2(int xx,int yy) {//判定纵向棋子是否有相连的
			int count2=0;
		for(int n=yy-1;n>=0;n--) {
			if(ChessArray[xx][n]==ChessArray[xx][yy]) {
				count2++;
			}else break;
		}
		for(int m=yy;m<ChessArray.length;m++) {
			if(ChessArray[xx][m]==ChessArray[xx][yy]) {
				count2++;
			}else break;
		}
		return count2;
	}
	
	public int Win3(int xx,int yy) {//判定左下右上棋子是否有相连的
		int count3=0;
		for(int o=xx-1,p=yy+1;o>=0&&p<ChessArray.length;o--,p++) {
			if(ChessArray[o][p]==ChessArray[xx][yy]) {
				count3++;
			}else break;
		}
		for(int o=xx,p=yy;o<ChessArray.length&&p>=0;o++,p--) {
			if(ChessArray[o][p]==ChessArray[xx][yy]) {
				count3++;
			}else break;
		}
		return count3;
	}
	
	public int Win4(int xx,int yy) {//判定左上右下棋子是否有相连的
		int count4=0;
		for(int o=xx-1,p=yy-1;o>=0&&p>=0;o--,p--) {
			if(ChessArray[o][p]==ChessArray[xx][yy]) {
				count4++;
			}else break;
		}
		for(int o=xx,p=yy;o<ChessArray.length&&p<ChessArray.length;o++,p++) {
			if(ChessArray[o][p]==ChessArray[xx][yy]) {
				count4++;
			}else break;
		}
		return count4;
	}

之后,在写完判定胜负方法后,我们需要在每次下棋后,去调用这些方法,判定是否获胜。也就是在绘制棋子这部分的代码片中,继续加上调用判定的方法代码。加上后,这部分的代码如下所示:

public class UIListener implements MouseListener ,ActionListener{//监听器是接口
	Graphics gr;
	int[][] ChessArray=new int[22][22];
	int[][] ChessValue=new int[22][22];
	JButton jb11;
	int nb=0;
	int count=0;
	int a,b,x,y,X,Y;
	JFrame mf;
	HashMap<String,Integer> hm=new HashMap<String,Integer>();
	public void mouseClicked(MouseEvent e) {
//		int a,b,x,y,X,Y;
		int z=50,c=20;
		Color c1=new Color(0,0,0);
		Color c2=new Color(255,255,255);
	    a=e.getX();b=e.getY();//获得鼠标点击坐标
	    if(nb==1) {//确定是否可以下棋
	    if((a-z)%c>c/2) {//帮助x轴上点击点优化到坐标格子上
	    	x=(a-z)/c+1;
	    }else {
	    	x=(a-z)/c;
	    }
	    if((b-z)%c>c/2) {//帮助y轴上点击点优化到坐标格子上
	    	y=(b-z)/c+1;
	    }else {
	    	y=(b-z)/c;
	    }
	    if(ChessArray[x][y]==0) {//确保棋子只能下在没有棋子的地方
	    		if(zifu.equals("人机对战")) {
	    			gr.setColor(c1);
	    	    	gr.fillOval(x*c+z-10, y*c+z-10, 20, 20);
	    	    	ChessArray[x][y]=1;
	    	    	gr.setColor(c2);
	    	    	AI();
	    		}else if(zifu.equals("人人对战")) {
	    			if(count==0) {
	    	    	gr.setColor(c1);
	    	    	count++;
	    	    	gr.fillOval(x*c+z-10, y*c+z-10, 20, 20);
	    	    	ChessArray[x][y]=1;//黑子数组值为1,方便重绘使用
	    	        }else if(count==1) {
	    	    	gr.setColor(c2);
	    	    	count--;
	    	    	gr.fillOval(x*c+z-10, y*c+z-10, 20, 20);
	    	    	ChessArray[x][y]=2;//白子数组值为21,方便重绘使用
	    	        }
	    		}
	    }else{
	    	System.out.println("该位置已有棋子");
	    }
	 }else {
		 System.out.println("请选择对战类型");
	 }

		if(Win1(x,y)==5||Win2(x,y)==5||Win3(x,y)==5||Win4(x,y)==5) {//确定获胜标准
			if(ChessArray[x][y]==1) {
				nb=0;
				JOptionPane.showMessageDialog(null, "黑棋胜利");
			}else if(ChessArray[x][y]==2) {
				nb=0;
				JOptionPane.showMessageDialog(null, "白棋胜利");
			}
		}

当然这里要注意,这里判定的方法只能判定人人对战中的黑白棋子,以及人机对战中的玩家所下的黑色棋子,因为导入其中的x,y坐标是鼠标点击优化过来的,所以人机对战中电脑所下的白子不会调用这个方法,所以人机对战中的电脑白棋获胜判定我们会在电脑下棋方法AI中单独写一个。

人机方法

这里的电脑人机方法我们选择使用一种简单的方法,利用HashMap建立一个权值表,赋予不同棋盘情况不同的权值,然后让电脑选择在权值最大的地方下棋即可实现。

因为之前数组中我们将黑白棋分别赋值1,2,那么就可以根据此情况来设置权值表,可以如下图所示:

 //创建权值表
		hm.put("1", 10);
        hm.put("11", 100);
        hm.put("111", 5000);
        hm.put("1111", 8000);
 
        hm.put("12", 5);
        hm.put("112", 80);
        hm.put("1112", 3000);
        hm.put("11112", 10000);
 
        hm.put("21", 11);
        hm.put("211", 110);
        hm.put("2111", 1100);
        hm.put("21111", 11000);
 
        hm.put("2", 20);
        hm.put("22", 200);
        hm.put("222", 4500);
        hm.put("2222", 10000);
 
        hm.put("221", 100);
        hm.put("2221", 3000);
        hm.put("22221", 12000);
        hm.put("122", 5);
        hm.put("1222", 500);
        hm.put("12222", 10000);

之后,就同样是遍历棋盘,找到每一个空位置,然后以这个空位置为起点,去看每个方向上棋盘的情况,然后设置一个ChessValue[][]数组来存储每一个空位置的最终各个方向上棋盘情况的权值总和,那么权值最大的地方,就是电脑需要下棋的地方。

在电脑下棋之后,同样要调用我们之前写过的判定胜负的方法来进行判定,确保电脑和玩家每下一次棋子就可以进行一次判定。

完整的电脑下棋AI方法的代码如下:

	public void AI() {//人机对战,电脑怎么下棋判定
	    //创建权值表
		hm.put("1", 10);
        hm.put("11", 100);
        hm.put("111", 5000);
        hm.put("1111", 8000);
 
        hm.put("12", 5);
        hm.put("112", 80);
        hm.put("1112", 3000);
        hm.put("11112", 10000);
 
        hm.put("21", 11);
        hm.put("211", 110);
        hm.put("2111", 1100);
        hm.put("21111", 11000);
 
        hm.put("2", 20);
        hm.put("22", 200);
        hm.put("222", 4500);
        hm.put("2222", 10000);
 
        hm.put("221", 100);
        hm.put("2221", 3000);
        hm.put("22221", 12000);
        hm.put("122", 5);
        hm.put("1222", 500);
        hm.put("12222", 10000);
	    
	    for(int i=0;i<ChessArray.length;i++) {
	    	for(int j=0;j<ChessArray[i].length;j++) {
	    		if(ChessArray[i][j]==0) {//判断是否有棋子
	    			String code="";
	    			int color=0;
	    			for(int k=i+1;k<ChessArray.length;k++) {//向右开始时遍历
	    				if(ChessArray[k][j]==0) {
	    					break;
	    				}else {
	    					if(color==0) {
	    						color=ChessArray[k][j];
	    						code+=ChessArray[k][j];
	    					}else if(color==ChessArray[k][j]) {
	    						code+=ChessArray[k][j];
	    					}else {
	    						code+=ChessArray[k][j];
	    						break;
	    					}
	    				}
	    				
	    			}
	    			Integer value=hm.get(code);
	    			if(value != null) {
	    				ChessValue[i][j]+=value;
	    			}
	    			code="";
	    			color=0;
	    			value=null;
	    			for(int k=i-1;k>0;k--) {//向左开始时遍历
	    				if(ChessArray[k][j]==0) {
	    					break;
	    				}else {
	    					if(color==0) {
	    						color=ChessArray[k][j];
	    						code+=ChessArray[k][j];
	    					}else if(color==ChessArray[k][j]) {
	    						code+=ChessArray[k][j];
	    					}else {
	    						code+=ChessArray[k][j];
	    						break;
	    					}
	    				}
	    				
	    			}
	    			value=hm.get(code);
	    			if(value != null) {
	    				ChessValue[i][j]+=value;
	    			}
	    			code="";
	    			color=0;
	    			value=null;
	    			for(int k=j-1;k>0;k--) {//向上开始时遍历
	    				if(ChessArray[i][k]==0) {
	    					break;
	    				}else {
	    					if(color==0) {
	    						color=ChessArray[i][k];
	    						code+=ChessArray[i][k];
	    					}else if(color==ChessArray[i][k]) {
	    						code+=ChessArray[i][k];
	    					}else {
	    						code+=ChessArray[i][k];
	    						break;
	    					}
	    				}
	    				
	    			}
	    			value=hm.get(code);
	    			if(value != null) {
	    				ChessValue[i][j]+=value;
	    			}
	    			code="";
	    			color=0;
	    			value=null;
	    			for(int k=j+1;k<ChessArray.length;k++) {//向下开始时遍历
	    				if(ChessArray[i][k]==0) {
	    					break;
	    				}else {
	    					if(color==0) {
	    						color=ChessArray[i][k];
	    						code+=ChessArray[i][k];
	    					}else if(color==ChessArray[i][k]) {
	    						code+=ChessArray[i][k];
	    					}else {
	    						code+=ChessArray[i][k];
	    						break;
	    					}
	    				}
	    				
	    			}
	    			value=hm.get(code);
	    			if(value != null) {
	    				ChessValue[i][j]+=value;
	    			}
	    			code="";
	    			color=0;
	    			value=null;
	    			for(int o=i-1,k=j-1;k>0&&o>0;k--,o--) {//向左上开始时遍历
	    				if(ChessArray[o][k]==0) {
	    					break;
	    				}else {
	    					if(color==0) {
	    						color=ChessArray[o][k];
	    						code+=ChessArray[o][k];
	    					}else if(color==ChessArray[o][k]) {
	    						code+=ChessArray[o][k];
	    					}else {
	    						code+=ChessArray[o][k];
	    						break;
	    					}
	    				}
	    				
	    			}
	    			value=hm.get(code);
	    			if(value != null) {
	    				ChessValue[i][j]+=value;
	    			}
	    			code="";
	    			color=0;
	    			value=null;
	    			for(int o=i+1,k=j-1;k>0&&o<ChessArray.length;k--,o++) {//向右上开始时遍历
	    				if(ChessArray[o][k]==0) {
	    					break;
	    				}else {
	    					if(color==0) {
	    						color=ChessArray[o][k];
	    						code+=ChessArray[o][k];
	    					}else if(color==ChessArray[o][k]) {
	    						code+=ChessArray[o][k];
	    					}else {
	    						code+=ChessArray[o][k];
	    						break;
	    					}
	    				}
	    				
	    			}
	    			value=hm.get(code);
	    			if(value != null) {
	    				ChessValue[i][j]+=value;
	    			}
	    			code="";
	    			color=0;
	    			value=null;
	    			for(int o=i+1,k=j+1;k<ChessArray.length&&o<ChessArray.length;k++,o++) {//向右下开始时遍历
	    				if(ChessArray[o][k]==0) {
	    					break;
	    				}else {
	    					if(color==0) {
	    						color=ChessArray[o][k];
	    						code+=ChessArray[o][k];
	    					}else if(color==ChessArray[o][k]) {
	    						code+=ChessArray[o][k];
	    					}else {
	    						code+=ChessArray[o][k];
	    						break;
	    					}
	    				}
	    				
	    			}
	    			value=hm.get(code);
	    			if(value != null) {
	    				ChessValue[i][j]+=value;
	    			}
	    			code="";
	    			color=0;
	    			value=null;
	    			for(int o=i-1,k=j+1;k<ChessArray.length&&o>0;k++,o--) {//向左下开始时遍历
	    				if(ChessArray[o][k]==0) {
	    					break;
	    				}else {
	    					if(color==0) {
	    						color=ChessArray[o][k];
	    						code+=ChessArray[o][k];
	    					}else if(color==ChessArray[o][k]) {
	    						code+=ChessArray[o][k];
	    					}else {
	    						code+=ChessArray[o][k];
	    						break;
	    					}
	    				}
	    				
	    			}
	    			value=hm.get(code);
	    			if(value != null) {
	    				ChessValue[i][j]+=value;
	    			}
	    		}
	    	}
	    }
	    //找到ChessValue中的最大值点让电脑下棋
	    int max=0;
	    int goalx = 0,goaly = 0;
	    for(int i=0;i<ChessArray.length;i++) {
	    	for(int j=0;j<ChessArray.length;j++) {
	    		if(ChessValue[i][j]>max) {
	    			max=ChessValue[i][j];
	    			goalx=i;
	    			goaly=j;
	    		}
	    	}
	    }
	    if(max !=0) {
	    	gr.fillOval(goalx*20+50-10, goaly*20+50-10, 20, 20);
	    	ChessArray[goalx][goaly]=2;
		    if(Win1(goalx,goaly)==5||Win2(goalx,goaly)==5||Win3(goalx,goaly)==5||Win4(goalx,goaly)==5) {//确定获胜标准
				 {  nb=0;
					JOptionPane.showMessageDialog(null, "白棋胜利");
				}
			}
	    }
	    //清空权值
	    for(int i=0;i<ChessArray.length;i++) {
	    	for(int j=0;j<ChessArray.length;j++) {
	    		ChessValue[i][j]=0;
	    	}
	    }
	}

完整代码,以及悔棋、清空棋盘功能

这样基本就完成了一个简单的五子棋创作,当然其中还包含着一些悔棋功能,清空棋盘功能,这些功能也基本上都是利用重绘来实现的,具体的操作就不在讲述,完整代码中有写,自行理解即可。

整个五子棋分为三个大类,分别是窗体DrawUI类,监听器UIListener类,以及MyFrame类,每个类完整的代码如下所示:

DrawUI:

public class DrawUI
{
	
	public static void main(String args[]) {
		DrawUI drawui=new DrawUI();//设置对象
		drawui.ShowUI();//让对象运行创建窗体的方法
	}
	public void ShowUI() {
		MyFrame jf=new MyFrame();//创建窗体
		jf.setSize(500,500);
		jf.setLocationRelativeTo(null);
		//设置窗体属性
		jf.setTitle("五子棋");
		jf.setResizable(true);
		jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		FlowLayout fl=new FlowLayout();//设置窗体格式
		jf.setLayout(fl);
		JButton jb=new JButton("人人对战");//添加按钮
		JButton jb1=new JButton("悔棋");
		JButton jb2=new JButton("清空棋盘");
		JButton jb3=new JButton("人机对战");
		jf.add(jb);
		jf.add(jb1);
		jf.add(jb2);
		jf.add(jb3);
		
		jf.setVisible(true);
		
		Graphics g=jf.getGraphics();//给窗体添加画笔
		UIListener ul=new UIListener();
		jb.addActionListener(ul);//给按钮添加监听器
		jb1.addActionListener(ul);
		jb2.addActionListener(ul);
		jb3.addActionListener(ul);
		jf.addMouseListener(ul);//给窗体添加监听器
		ul.gr=g;//将画笔倒给UIlistener中的gr
//		jf.ChessArray = ul.ChessArray;
		jf.ul=ul;//为了在Myframe中使用ChessArray,将UIistener中的ul倒给Myframe中的ul
		ul.jb11=jb;//将按钮jb倒给ul中的jb11,方便其使用jb
		ul.mf=jf;//为了在UIlistener中重绘,将jf倒给其中的mf
	}
}

UIListener:

public class UIListener implements MouseListener ,ActionListener{//监听器是接口
	Graphics gr;
	int[][] ChessArray=new int[22][22];
	int[][] ChessValue=new int[22][22];
	JButton jb11;
	int nb=0;
	int count=0;
	int a,b,x,y,X,Y;
	JFrame mf;
	String zifu;
	HashMap<String,Integer> hm=new HashMap<String,Integer>();
	public void mouseClicked(MouseEvent e) {
//		int a,b,x,y,X,Y;
		int z=50,c=20;
		Color c1=new Color(0,0,0);
		Color c2=new Color(255,255,255);
	    a=e.getX();b=e.getY();//获得鼠标点击坐标
	    if(nb==1) {//确定是否可以下棋
	    if((a-z)%c>c/2) {//帮助x轴上点击点优化到坐标格子上
	    	x=(a-z)/c+1;
	    }else {
	    	x=(a-z)/c;
	    }
	    if((b-z)%c>c/2) {//帮助y轴上点击点优化到坐标格子上
	    	y=(b-z)/c+1;
	    }else {
	    	y=(b-z)/c;
	    }
	    if(ChessArray[x][y]==0) {//确保棋子只能下在没有棋子的地方
	    		if(zifu.equals("人机对战")) {
	    			gr.setColor(c1);
	    	    	gr.fillOval(x*c+z-10, y*c+z-10, 20, 20);
	    	    	ChessArray[x][y]=1;
	    	    	gr.setColor(c2);
	    	    	AI();
	    		}else if(zifu.equals("人人对战")) {
	    			if(count==0) {
	    	    	gr.setColor(c1);
	    	    	count++;
	    	    	gr.fillOval(x*c+z-10, y*c+z-10, 20, 20);
	    	    	ChessArray[x][y]=1;//黑子数组值为1,方便重绘使用
	    	        }else if(count==1) {
	    	    	gr.setColor(c2);
	    	    	count--;
	    	    	gr.fillOval(x*c+z-10, y*c+z-10, 20, 20);
	    	    	ChessArray[x][y]=2;//白子数组值为21,方便重绘使用
	    	        }
	    		}
	    }else{
	    	System.out.println("该位置已有棋子");
	    }
	 }else {
		 System.out.println("请选择对战类型");
	 }

		if(Win1(x,y)==5||Win2(x,y)==5||Win3(x,y)==5||Win4(x,y)==5) {//确定获胜标准
			if(ChessArray[x][y]==1) {
				nb=0;
				JOptionPane.showMessageDialog(null, "黑棋胜利");
			}else if(ChessArray[x][y]==2) {
				nb=0;
				JOptionPane.showMessageDialog(null, "白棋胜利");
			}
		}
	}
	public void AI() {//人机对战,电脑怎么下棋判定
	    //创建权值表
		hm.put("1", 10);
        hm.put("11", 100);
        hm.put("111", 5000);
        hm.put("1111", 8000);
 
        hm.put("12", 5);
        hm.put("112", 80);
        hm.put("1112", 3000);
        hm.put("11112", 10000);
 
        hm.put("21", 11);
        hm.put("211", 110);
        hm.put("2111", 1100);
        hm.put("21111", 11000);
 
        hm.put("2", 20);
        hm.put("22", 200);
        hm.put("222", 4500);
        hm.put("2222", 10000);
 
        hm.put("221", 100);
        hm.put("2221", 3000);
        hm.put("22221", 12000);
        hm.put("122", 5);
        hm.put("1222", 500);
        hm.put("12222", 10000);
	    
	    for(int i=0;i<ChessArray.length;i++) {
	    	for(int j=0;j<ChessArray[i].length;j++) {
	    		if(ChessArray[i][j]==0) {//判断是否有棋子
	    			String code="";
	    			int color=0;
	    			for(int k=i+1;k<ChessArray.length;k++) {//向右开始时遍历
	    				if(ChessArray[k][j]==0) {
	    					break;
	    				}else {
	    					if(color==0) {
	    						color=ChessArray[k][j];
	    						code+=ChessArray[k][j];
	    					}else if(color==ChessArray[k][j]) {
	    						code+=ChessArray[k][j];
	    					}else {
	    						code+=ChessArray[k][j];
	    						break;
	    					}
	    				}
	    				
	    			}
	    			Integer value=hm.get(code);
	    			if(value != null) {
	    				ChessValue[i][j]+=value;
	    			}
	    			code="";
	    			color=0;
	    			value=null;
	    			for(int k=i-1;k>0;k--) {//向左开始时遍历
	    				if(ChessArray[k][j]==0) {
	    					break;
	    				}else {
	    					if(color==0) {
	    						color=ChessArray[k][j];
	    						code+=ChessArray[k][j];
	    					}else if(color==ChessArray[k][j]) {
	    						code+=ChessArray[k][j];
	    					}else {
	    						code+=ChessArray[k][j];
	    						break;
	    					}
	    				}
	    				
	    			}
	    			value=hm.get(code);
	    			if(value != null) {
	    				ChessValue[i][j]+=value;
	    			}
	    			code="";
	    			color=0;
	    			value=null;
	    			for(int k=j-1;k>0;k--) {//向上开始时遍历
	    				if(ChessArray[i][k]==0) {
	    					break;
	    				}else {
	    					if(color==0) {
	    						color=ChessArray[i][k];
	    						code+=ChessArray[i][k];
	    					}else if(color==ChessArray[i][k]) {
	    						code+=ChessArray[i][k];
	    					}else {
	    						code+=ChessArray[i][k];
	    						break;
	    					}
	    				}
	    				
	    			}
	    			value=hm.get(code);
	    			if(value != null) {
	    				ChessValue[i][j]+=value;
	    			}
	    			code="";
	    			color=0;
	    			value=null;
	    			for(int k=j+1;k<ChessArray.length;k++) {//向下开始时遍历
	    				if(ChessArray[i][k]==0) {
	    					break;
	    				}else {
	    					if(color==0) {
	    						color=ChessArray[i][k];
	    						code+=ChessArray[i][k];
	    					}else if(color==ChessArray[i][k]) {
	    						code+=ChessArray[i][k];
	    					}else {
	    						code+=ChessArray[i][k];
	    						break;
	    					}
	    				}
	    				
	    			}
	    			value=hm.get(code);
	    			if(value != null) {
	    				ChessValue[i][j]+=value;
	    			}
	    			code="";
	    			color=0;
	    			value=null;
	    			for(int o=i-1,k=j-1;k>0&&o>0;k--,o--) {//向左上开始时遍历
	    				if(ChessArray[o][k]==0) {
	    					break;
	    				}else {
	    					if(color==0) {
	    						color=ChessArray[o][k];
	    						code+=ChessArray[o][k];
	    					}else if(color==ChessArray[o][k]) {
	    						code+=ChessArray[o][k];
	    					}else {
	    						code+=ChessArray[o][k];
	    						break;
	    					}
	    				}
	    				
	    			}
	    			value=hm.get(code);
	    			if(value != null) {
	    				ChessValue[i][j]+=value;
	    			}
	    			code="";
	    			color=0;
	    			value=null;
	    			for(int o=i+1,k=j-1;k>0&&o<ChessArray.length;k--,o++) {//向右上开始时遍历
	    				if(ChessArray[o][k]==0) {
	    					break;
	    				}else {
	    					if(color==0) {
	    						color=ChessArray[o][k];
	    						code+=ChessArray[o][k];
	    					}else if(color==ChessArray[o][k]) {
	    						code+=ChessArray[o][k];
	    					}else {
	    						code+=ChessArray[o][k];
	    						break;
	    					}
	    				}
	    				
	    			}
	    			value=hm.get(code);
	    			if(value != null) {
	    				ChessValue[i][j]+=value;
	    			}
	    			code="";
	    			color=0;
	    			value=null;
	    			for(int o=i+1,k=j+1;k<ChessArray.length&&o<ChessArray.length;k++,o++) {//向右下开始时遍历
	    				if(ChessArray[o][k]==0) {
	    					break;
	    				}else {
	    					if(color==0) {
	    						color=ChessArray[o][k];
	    						code+=ChessArray[o][k];
	    					}else if(color==ChessArray[o][k]) {
	    						code+=ChessArray[o][k];
	    					}else {
	    						code+=ChessArray[o][k];
	    						break;
	    					}
	    				}
	    				
	    			}
	    			value=hm.get(code);
	    			if(value != null) {
	    				ChessValue[i][j]+=value;
	    			}
	    			code="";
	    			color=0;
	    			value=null;
	    			for(int o=i-1,k=j+1;k<ChessArray.length&&o>0;k++,o--) {//向左下开始时遍历
	    				if(ChessArray[o][k]==0) {
	    					break;
	    				}else {
	    					if(color==0) {
	    						color=ChessArray[o][k];
	    						code+=ChessArray[o][k];
	    					}else if(color==ChessArray[o][k]) {
	    						code+=ChessArray[o][k];
	    					}else {
	    						code+=ChessArray[o][k];
	    						break;
	    					}
	    				}
	    				
	    			}
	    			value=hm.get(code);
	    			if(value != null) {
	    				ChessValue[i][j]+=value;
	    			}
	    		}
	    	}
	    }
	    //找到ChessValue中的最大值点让电脑下棋
	    int max=0;
	    int goalx = 0,goaly = 0;
	    for(int i=0;i<ChessArray.length;i++) {
	    	for(int j=0;j<ChessArray.length;j++) {
	    		if(ChessValue[i][j]>max) {
	    			max=ChessValue[i][j];
	    			goalx=i;
	    			goaly=j;
	    		}
	    	}
	    }
	    if(max !=0) {
	    	gr.fillOval(goalx*20+50-10, goaly*20+50-10, 20, 20);
	    	ChessArray[goalx][goaly]=2;
		    if(Win1(goalx,goaly)==5||Win2(goalx,goaly)==5||Win3(goalx,goaly)==5||Win4(goalx,goaly)==5) {//确定获胜标准
				 {  nb=0;
					JOptionPane.showMessageDialog(null, "白棋胜利");
				}
			}
	    }
    }
	    //清空权值
	    for(int i=0;i<ChessArray.length;i++) {
	    	for(int j=0;j<ChessArray.length;j++) {
	    		ChessValue[i][j]=0;
	    	}
	    }
	}
	
	//判定获胜的方法
	public int Win1(int xx,int yy) {//判定横向棋子是否有相连的
		int count1=0;
		for(int i=xx-1;i>=0;i--) {
			if(ChessArray[i][yy]==ChessArray[xx][yy]) {
				count1++;
			}else break;
		}
		for(int j=xx;j<ChessArray.length;j++) {
			if(ChessArray[j][yy]==ChessArray[xx][yy]) {
				count1++;
			}else break;
		}
		return count1;
	}
	
	public int Win2(int xx,int yy) {//判定纵向棋子是否有相连的
			int count2=0;
		for(int n=yy-1;n>=0;n--) {
			if(ChessArray[xx][n]==ChessArray[xx][yy]) {
				count2++;
			}else break;
		}
		for(int m=yy;m<ChessArray.length;m++) {
			if(ChessArray[xx][m]==ChessArray[xx][yy]) {
				count2++;
			}else break;
		}
		return count2;
	}
	
	public int Win3(int xx,int yy) {//判定左下右上棋子是否有相连的
		int count3=0;
		for(int o=xx-1,p=yy+1;o>=0&&p<ChessArray.length;o--,p++) {
			if(ChessArray[o][p]==ChessArray[xx][yy]) {
				count3++;
			}else break;
		}
		for(int o=xx,p=yy;o<ChessArray.length&&p>=0;o++,p--) {
			if(ChessArray[o][p]==ChessArray[xx][yy]) {
				count3++;
			}else break;
		}
		return count3;
	}
	
	public int Win4(int xx,int yy) {//判定左上右下棋子是否有相连的
		int count4=0;
		for(int o=xx-1,p=yy-1;o>=0&&p>=0;o--,p--) {
			if(ChessArray[o][p]==ChessArray[xx][yy]) {
				count4++;
			}else break;
		}
		for(int o=xx,p=yy;o<ChessArray.length&&p<ChessArray.length;o++,p++) {
			if(ChessArray[o][p]==ChessArray[xx][yy]) {
				count4++;
			}else break;
		}
		return count4;
	}
	
	public void Restart() {//重绘,删除之前的棋子,只保留棋盘
			for(int i=0;i<ChessArray.length;i++) {
				for(int j=0;j<ChessArray.length;j++) {
					if(ChessArray[i][j]==1||ChessArray[i][j]==2) {
						ChessArray[i][j]=0;
					}
				}
			}
		mf.repaint();
	}
	
	public void Hq() {//悔棋
		ChessArray[x][y]=0; 
		mf.paint(gr);
	}

	
    public void mousePressed(MouseEvent e) {
    	
    	
    }
    public void mouseReleased(MouseEvent e) {
    	
    }
    public void mouseEntered(MouseEvent e){
    	
    }
    public void mouseExited(MouseEvent e) {
    	
    }
    public void actionPerformed(ActionEvent e) {//按钮监听器执行一些操作
    	if(jb11==e.getSource()) {
    		nb=1;
    	}
    	zifu=e.getActionCommand();
    	if(zifu.equals("清空棋盘")) {
    		Restart();
    	}
    	if(zifu.equals("悔棋")) {
    		Hq();
    	}
    	if(zifu.equals("人机对战")) {
    		nb=1;
    	}
    }
}

MyFrame:

public class MyFrame extends JFrame{//MyFrame子类继承JFrame父类
	public UIListener ul;
//	int[][] ChessArray;
	int z=50,c=20;
	public void paint(Graphics g) {//重绘棋盘,确保刷新网页时候,棋盘还在
		super.paint(g);
		int x1,x2,y1,y2;
		int X1,X2,Y1,Y2;
		x1=50;x2=450;y1=70;y2=470;
		X1=50;X2=450;Y1=70;Y2=470;
		for(int i=0; i<21; i++) {
		       g.drawLine(x1,y1,x2,y1);
		       y1=y1+20;
		       
		}
		for(int i=0; i<21; i++) {
			  g.drawLine(X1,Y1,X1,Y2);
			  X1=X1+20;
		}

		int[][] ChessArray = ul.ChessArray;
		for(int i=0;i<ChessArray.length;i++) {//重绘棋子,网页刷新后,之前下过的棋子还在
			for(int j=0;j<ChessArray.length;j++) {
				if(ChessArray[i][j]==1) {
					g.setColor(Color.black);
					g.fillOval(i*c+z-10, j*c+z-10, 20, 20);
				}
				if(ChessArray[i][j]==2) {
					g.setColor(Color.white);
					g.fillOval(i*c+z-10, j*c+z-10, 20, 20);
				}
			}
		}
	}

}

收获理解

五子棋这个小项目,在最开始的写的时候会遇到各种各样的问题,但随着不断学习钻研,很多东西都可以慢慢去掌握,例如:如何重绘,如何找最大值,如何设置棋子,如何在不同的类中去调用其他类的方法或者属性。能让自己更好的理解类与对象,属性,变量等一些基础知识,


点击全文阅读


本文链接:http://zhangshiyu.com/post/16303.html

棋子  棋盘  判定  
<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

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

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1