java用swing与awt图形库贪心算法实现机器与人博弈五子棋

java用swing与awt图形库贪心算法实现机器与人博弈五子棋

  • 作者:Geticsen
  • 时间:2019-10-13
  • 52人已阅读
简介 这是大二写的java语言用swing与awt图形库贪心算法实现机器博弈五子棋,实现了机器与人的博弈,当然这个版本比较低级主要还是用于激起大家的思考

大二写的五子棋人机对战游戏

image.png

主要的实现步骤如下:

1用 一个 int 类型 15*15的数组存储棋盘 chess[15][15],初始化全为零,1代表我方棋子(黑色)2代表电脑(红色)

2用两个 15*15*4的三维数组cumputer[][][]=new int [15][15][4]; user[][][]=new int [15][15][4];存储计算我的棋盘的权值

3下棋人下棋

4从四个方向上扫描当前位置的相邻5个位置有我方或者敌方棋子,我若方棋子则user当前数组当前扫描方向权值加一

5从(0,0)开始到(14,14)重复3过程

6从cumputer 与user选取最大值即为当前一步的最优解,机器落子为这个点

7重复3-7判断若有五颗棋子连成一条线进入8

8游戏结束根据棋子属性判断赢棋的者

具体的代码如下:

package wuziqi;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class Main_frame extends JFrame implements MouseListener{
	Mypan  pan;
	int width=450;
	int height=450;
	int using=1;
	public static void main(String []args) {
		Main_frame my=new Main_frame();
	}
	public Main_frame() {
		pan=new Mypan(width,height);
		pan.addMouseListener(this);
		this.add(pan);
		this.setTitle("五子棋");
		this.setSize(width+47, height+69);
		this.setVisible(true);
		this.setLocation(200, 200);
		this.setResizable(false);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}
	@Override
	public void mouseClicked(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void mouseEntered(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void mouseExited(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void mousePressed(MouseEvent arg0){
		// TODO Auto-generated method stub
		System.out.println(arg0.getX()+"  "+arg0.getY()+"");
		//获得坐标后转换维数组坐标
		int x=(arg0.getX()+14)/30-1;
		int y=(arg0.getY()+14)/30-1;
		System.out.println(x+"  "+y);
		if(0<=x&&x<=14&&0<=y&&y<=14){
			if(pan.chess[y][x]==0){
				if(using==1){
					pan.chess[y][x]=1;
					pan.repaint();
					//判断是否五颗一条线
					if(pan.judge(x, y,1)){
						//System.out.println("5555555555555555555555555555555555555555555555");
						JOptionPane.showMessageDialog(this, "已经五子"+1+"胜出");
						using=1;
						pan.clearChess();
						
					}else {
						using=2;
					}
					
				}
				if(using==2){
					//自动完成自动落子
					pan.randomChess();
					pan.repaint();
					//判断是否五颗一条线
					if(pan.judge(pan.x, pan.y,2)){
						
						//System.out.println("5555555555555555555555555555555555555555555555");
						JOptionPane.showMessageDialog(this, "已经五子"+2+"胜出");
						using=1;
						pan.clearChess();
						
					}else {
						using=1;
					}
					
				}
			    pan.repaint();
				
			}
			
		}
	}
	@Override
	public void mouseReleased(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}

}

class Mypan extends JPanel{
	
	int width;
	int height;
	int x,y;
	//冲二冲三冲四
	int er=4,san=8,si=7;
	int chess[][]=new int[15][15];
	
	public  Mypan(int width,int height){
		this.height=height;
		this.width=width;
		this.setBackground(Color.white);
		this.setSize(width+17,height+139);
		this.setVisible(true);
	}
	
	public void paint(Graphics g){
		super.paint(g);
		g.setColor(Color.black);
		//画出横
		for(int i=0;i<15;i++) {
			if(i==0||i==14) {
				g.setColor(Color.red);
			}else {
				g.setColor(Color.BLACK);
			}
			g.drawString(String.valueOf(i+1), 15, i*30+30);
		    g.drawLine(30, i*30+30, this.width, i*30+30);
		}
		//画出竖
        for(int i=0;i<15;i++){
        	if(i==0||i==14) {
				g.setColor(Color.red);
			}else {
				g.setColor(Color.BLACK);
			}
         g.drawString(String.valueOf(i+1), i*30+15,30);
         g.drawLine(i*30+30, 30,  i*30+30,this.height);
		}
        //画出棋子
       
        for(int i=0;i<15;i++) {
        	for(int j=0;j<15;j++) {
        		//System.out.print(chess[i][j]+" ");
        		if(chess[j][i]!=0) {
        			//正数自己的棋子
        			if(chess[j][i]==1) {
        			    g.setColor(Color.BLACK);
        			   	g.fillOval((i+1)*30-13, (j+1)*30-13, 26, 26);
        			}else if(chess[j][i]==2) {
        				//别人的棋子
        			    g.setColor(Color.RED);
        				g.fillOval((i+1)*30-13, (j+1)*30-13, 26, 26);
        			}
        		}
        	}
        	//System.out.println();
        }
        System.out.println();
	}
	public boolean judge(int x,int y,int type){
		boolean count=false;
		for(int i=0;i<4;i++) {
			if(find(x,y,i,type)>=5){
				count=true;
				break;
			}
		}
		return count;
	}
	//找到连接的棋子数
	public int find(int x,int y,int dir,int type){
		int sum1=0,sum2=0;
		int y1=y,x1=x;
		switch(dir) 
		{
		case 0:
			//两半查找    横  左右
			for(int i=0;i<5;i++) {
				if(--x1<0) {
					break;
				}
				if(chess[y][x1]!=type) {
					break;
				}else {
					sum1++;
				}
			}
	        for(int i=0;i<5;i++) {
	        	if(++x>14) {
					break;
				}
				if(chess[y][x]!=type) {
					break;
				}else {
					sum2++;
				}
			}
			break;
		case 1:
			//两半查找   竖 上下
			for(int i=0;i<5;i++) {
				if(++y1>14){
					break;
				}
				if(chess[y1][x]!=type) {
					break;
				}else{
					sum1++;
				}
			}
	        for(int i=0;i<5;i++) {
	        	if(--y<0) {
					break;
				}
				if(chess[y][x]!=type) {
					break;
				}else{
					sum2++;
				}
			}
			break;
		case 2:
			//两半查找   撇  
			for(int i=0;i<5;i++) 
			{
				if(++x1>14||++y1>14) {
					break;
				}
				if(chess[y1][x1]!=type) {
					break;
				}else {
					sum1++;
				}
			}
	        for(int i=0;i<5;i++) {
	        	if(--x<0||--y<0) {
					break;
				}
				if(chess[y][x]!=type) {
					break;
				}else {
					sum2++;
				}
			}
			break;
		case 3: 
			//两半查找   捺
			for(int i=0;i<5;i++) 
			{
				if(++x1>14||--y1<0) {
					break;
				}
				if(chess[y1][x1]!=type) {
					break;
				}else {
					sum1++;
				}
			}
	        for(int i=0;i<5;i++) {
	        	if(--x<0||++y>14) {
					break;
				}
				if(chess[y][x]!=type) {
					break;
				}else {
					sum2++;
				}
			}
			
			break;
	     }
		return sum1+sum2+1;
		
	}
	//电脑自由下棋
	public void randomChess(){
		
		int cumputer[][][]=new int [15][15][4];
		int user[][][]=new int [15][15][4];
		int max1=0,max2=0;
		int location[][]=new int [2][2];
		for(int i=0;i<15;i++) {
			for(int j=0;j<15;j++) {
				if(this.chess[j][i]==0)
				{   
					int sum=0;
					for(int k=0;k<4;k++){
						cumputer[j][i][k]=this.find(i, j, k, 2);
						if(cumputer[j][i][k]==3) {
							sum+=this.er+(int)Math.random()*2;
						}else if(cumputer[j][i][k]==4) {
							sum+=this.san+10+(int)Math.random()*3;
						}else if(cumputer[j][i][k]==5){
							sum+=this.si+15+(int)Math.random()*4;
						}else {
							sum+=cumputer[j][i][k];
						}
						
					}
					if(max1<sum) {
						max1=sum;
						location[0][0]=j;
						location[0][1]=i;
					}
				}
				
			}
		}
		
		for(int i=0;i<15;i++) {
			for(int j=0;j<15;j++) {
				if(this.chess[j][i]==0)
				{
					int sum=0;
					for(int k=0;k<4;k++) {
						user[j][i][k]=this.find(i, j, k, 1);
						if(user[j][i][k]==3) {
							sum+=this.er+(int)Math.random()*2;
						}else if(user[j][i][k]==4) {
							sum+=this.san+10+(int)Math.random()*3;
						}else if(user[j][i][k]==5){
							sum+=this.si+7+(int)Math.random()*4;
						}else{
							sum+=user[j][i][k];
						}
						
					}
					if(max2<sum) {
						max2=sum;
						location[1][0]=j;
						location[1][1]=i;
					}
				}
				
			}
		}
		//贪心决策
		if(max1>=max2) {
			chess[location[0][0]][location[0][1]]=2;
			x=location[0][1];
			y=location[0][0];
		}else{
			chess[location[1][0]][location[1][1]]=2;
			x=location[1][1];
			y=location[1][0];
		}
		//都为零自动下子
		if(max1==max2&&max1==0) {
			int x=(int)Math.random()*15;
			int y=(int)Math.random()*15;
			chess[y][x]=1;
			this.x=x;
			this.y=y;
		}
		
	}
	public void clearChess() {
		for(int i=0;i<15;i++) {
			for(int j=0;j<15;j++) {
				this.chess[i][j]=0;
			}
		}
		
	}
}

讲解:

假如我的黑子下棋子位置如图所示则计算机的计算权值棋盘为如下,经过化简的棋盘只是为了方便解释(人先走棋则 计算机的走子棋局权值没必要计算因为计算了也全部是零):

image.png

那很容易得到计算机下一个位置就是从权值最大的一点落子(空白格的权值为0所以没有写出来,最大全部都是1所以任意一点权值为1都可以落子,其实这里不应该让他落子靠边处,这个可以以后优化)

接着假设机器落子在权值为1的第一个位置,继续人走子(假设我下的位置为(2,1)):

image.png


以上就是两个棋局的权值图,两个权值中取最大值得到的结果就是要去拦截user的棋子(这时候(2,0)与(2,3)位置都可以落子),假设计算机落子在(2,3),得到如下棋局。

image.png

然后由user下棋了,假设人走子为(3,2),计算机通过贪心计算得到如下棋局

image.png

很显然机器要下棋的下一个地址为权值为三的点(权值最大)来防止人得到对人来说更优的棋局,下面就不再画啦到这里大部分人都因该可以理解了,全部的代码就是以上给出的理解也不是特别难。


文章评论

Top