java swing实现的人机对战五子棋

这个小程序是我1年多前自己写着玩的,当时不懂这么多,两个个文件就搞定了,写的也不规范。图片神马的都是从别人demo弄来的。

ai不是很智能,只是会搜索当前局面的最优解,评分规则是我从网上找的一个。大概介绍一下这个规则:

  • 能成死二(当前位置下子后,可以有两颗子连在一起,但是一端有对方的一颗子或者边界阻挡),20分;
  • 能成活二(当前位置下子后,可以有两颗子连在一起,两端没有对方棋子或者边界),80分;
  • 能成死三,180分;
  • 能成活三,800分;
  • 能成死四,1200分;
  • 能成活四,2000分;
  • 能成五连,10000分;

程序遍历所有空白点,算出4个方向(横、竖、左斜、右斜)的分数和,算每个点的分数,然后选择所有节点中分数最高的一个落子。当时参考了一个别人的程序,他在程序中设定只搜索8x8的空间,怕电脑承受不了,我自己实现后并没有发现这个问题。
开始的时候还想着设置一下ai的难度,搜索几层什么的,实在水平有限,也不懂怎么弄,就成了这样子,搜索当前局面的最优解。



附上程序部分源码:
package jsj.lgl;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class CBoardPanel extends JPanel implements MouseListener
{
	private static final int START_X=20;
	private static final int START_Y=20;
	private static final int STEP=35;
	private static final int ROW=15;
	private static final int COL=15;
	
	public static final int BLANK=1;
	public static final int WHITE=-1;
	public static final int NONE=0;
	
	public static final int AI_FIRST=1;
	public static final int HUMAN_FIRST=2;
	
	public static final int EASY=2;
	public static final int HARD=4;	
	
	private BufferedImage chessBoardImage=null,whiteImage=null,blankImage=null;//图片
	private int[][] chesses=new int[ROW][COL];//棋盘情况
	private int aiColor,humColor;//电脑和人的棋子颜色
	private int level;//当前难度
	private ChessBoard cb;//主类的引用
	private boolean isHumTurn=false;//是不是轮到人下的布尔值,true代表轮到人下
	private int currRow,currCol;//当前棋子的行和列
	private int winner=NONE;//表示赢家的颜色,初始为空
	private ArrayList<Point> chessProcess=new ArrayList<Point>();//表示每一个棋子下的先后顺序,用于悔棋
	
	private static final int FIVE = 10000;//能成五连
	private static final int L_FOUR =2000;//能成活四
	private static final int D_FOUR = 1200;//能成死四
	private static final int L_THREE = 800;//能成活三
	private static final int D_THREE = 180;//能成死三
	private static final int L_TWO = 80;//能成活二
	private static final int D_TWO = 20;//能成死二
	
	private static final int HENG=1;
	private static final int SHU=2;
	private static final int XIE45=3;
	private static final int XIE135=4;
	
	public CBoardPanel(int whoFirst,int level,ChessBoard cb)//构造器
	{
		this.cb=cb;
		this.level=level;
		chesses=new int[ROW][COL];
		winner=NONE;
		if(whoFirst==HUMAN_FIRST)
		{
			isHumTurn=true;
			humColor=BLANK;
			aiColor=WHITE;
		}
		else
		{
			humColor=WHITE;
			aiColor=BLANK;
			isHumTurn=false;
			//电脑走一步棋
			aiGoOneStep();
		}						
		try
		{
			chessBoardImage=ImageIO.read(new File("image/chessboard.jpg"));
			blankImage = ImageIO.read(new File("image/b.jpg"));
			whiteImage = ImageIO.read(new File("image/w.jpg"));
		} catch (IOException e)
		{
			e.printStackTrace();
		}
		this.addMouseListener(this);
	}
	
	public void restart(int whoFirst,int level,ChessBoard cb)//重新开始的方法
	{
		this.level=level;
		chesses=new int[ROW][COL];
		winner=NONE;
		chessProcess.clear();
		if(whoFirst==HUMAN_FIRST)
		{
			isHumTurn=true;
			humColor=BLANK;
			aiColor=WHITE;
		}
		else
		{
			humColor=WHITE;
			aiColor=BLANK;
			isHumTurn=false;
			//电脑走一步棋
			aiGoOneStep();
		}
		this.repaint();
	}
	
	public void paintComponent(Graphics g)//重写的paintComponent方法
	{
		super.paintComponents(g);
		
		g.drawImage(chessBoardImage,0,0,this);
		for(int i=0;i<ROW;i++)
		{
			for(int j=0;j<COL;j++)
			{
				if(chesses[i][j]==BLANK)
				{
					drawImageInRowCol(i,j,blankImage,g);
				}
				else if(chesses[i][j]==WHITE)
				{
					drawImageInRowCol(i,j,whiteImage,g);
				}
			}
		}
		g.setColor(Color.RED);
		if(chessProcess.size()>0)
		{
			g.drawRect(currCol*STEP+2, currRow*STEP+2, STEP, STEP);
		}
	}
	
	public void back()//退一步棋
	{
		if(!isHumTurn||chessProcess.size()<2)
		{
			return;
		}
		winner=NONE;
		Point p=chessProcess.get(chessProcess.size()-1);
		chesses[p.x][p.y]=NONE;
		chessProcess.remove(chessProcess.size()-1);
		
		p=chessProcess.get(chessProcess.size()-1);
		chesses[p.x][p.y]=NONE;
		chessProcess.remove(chessProcess.size()-1);
		if(chessProcess.size()>0)
		{
			p=chessProcess.get(chessProcess.size()-1);
			currRow=p.x;currCol=p.y;
		}
		
		this.repaint();
	}
	
	public void setLevel(int level)//设置难易程度
	{
		this.level=level;
	}
	
	private void drawImageInRowCol(int row,int col,BufferedImage image,Graphics g)//在指定行和列画棋子
	{
		int x=col*STEP+3;
		int y=row*STEP+3;
		g.drawImage(image,x,y,this);
	}
	
	private Point pressWhere(MouseEvent e)//判断鼠标的点击位置,转换为行和列
	{
		int x=e.getPoint().x;
		int y=e.getPoint().y;
		int row=(y-START_Y+STEP/2)/STEP;
		int col=(x-START_X+STEP/2)/STEP;
		return new Point(row,col);
	}
	
	private void goOneStep(int row,int col,int color)//生成一步棋,并判断是否有玩家胜出
	{
		chesses[row][col]=color;
		chessProcess.add(new Point(row,col));
		currRow=row;currCol=col;
		this.repaint();
		boolean flag=isWin(currRow,currCol,color);		
		if(flag)
		{
			winner=color;
			String msg;
			if(winner==BLANK)
			{
				msg="黑方胜啦!";
			}
			else
			{
				msg="白方胜啦!";
			}
			JOptionPane.showMessageDialog(cb,msg,"游戏结束",JOptionPane.INFORMATION_MESSAGE);
		}
		if(color==humColor&&winner==NONE)
		{
			aiGoOneStep();
		}
	}
	
	private int score(int row,int col,int dir,int color)//判断当前点指定方向的棋形
	{
		if(row<0||row>=ROW||col<0||col>=COL||chesses[row][col]!=NONE)
		{
			return 0;
		}
		int x=0,y=0;
		boolean lflag=false,rflag=false;//左右标志位
		int qx=1;
		int ltemp=0,rtemp=0;
		switch(dir)
		{
		case HENG:x=1;y=0;
			break;
		case SHU:x=0;y=1;
			break;
		case XIE45:x=1;y=1;
			break;
		case XIE135:x=1;y=-1;
			break;
		}
		int currRow=row,currCol=col;
		for(int i=1;i<=5;i++)//往左看
		{
			currRow=row-i*y;
			currCol=col-i*x;
			if(currRow<0||currRow>=ROW||currCol<0||currCol>=COL)
			{
				lflag=true;
				break;
			}
			if(chesses[currRow][currCol]==color)
			{
				qx+=1;
			}
			else if(chesses[currRow][currCol]==-color)
			{
				lflag=true;
				break;
			}
			else if(chesses[currRow][currCol]==NONE)
			{
				for(int j=1;j<5;j++)
				{
					currRow=row-i*y;
					currCol=col-i*x;
					if(chesses[currRow][currCol]==color)
					{
						ltemp++;
					}
					else if(chesses[currRow][currCol]==-color)
					{
						lflag=true;
						break;
					}
					else
					{
						break;
					}
				}
				break;
			}
		}
		for(int i=1;i<=5;i++)//往右看
		{
			currRow=row+i*y;
			currCol=col+i*x;
			if(currRow<0||currRow>=ROW||currCol<0||currCol>=COL)
			{
				rflag=true;
				break;
			}
			if(chesses[currRow][currCol]==color)
			{
				qx+=1;
			}
			else if(chesses[currRow][currCol]==-color)
			{
				rflag=true;
				break;
			}
			else if(chesses[currRow][currCol]==NONE)
			{
				for(int j=1;j<5;j++)
				{
					currRow=row+i*y;
					currCol=col+i*x;
					if(chesses[currRow][currCol]==color)
					{
						rtemp++;
					}
					else if(chesses[currRow][currCol]==-color)
					{
						rflag=true;
						break;
					}
					else
					{
						break;
					}
				}
				break;
			}
		}
		int temp=Math.max(ltemp, rtemp);
//System.out.println("qx="+qx);
		if(qx>=5)
		{
			return FIVE;
		}
		else if(lflag&&rflag)
		{
			return 0;
		}
		else
		{
			qx+=temp;
			if(lflag||rflag)
			{
				switch(qx)
				{
				case 1:return 0;
				case 2:return D_TWO;
				case 3:return D_THREE;
				case 4:return D_FOUR;
				}
			}
			else
			{
				if(temp>0)
				{
					switch(qx)
					{
					case 1:return 0;
					case 2:return D_TWO;
					case 3:return D_THREE;
					case 4:return D_FOUR;
					}
				}
				else
				{
					switch(qx)
					{
					case 1:return 0;
					case 2:return L_TWO;
					case 3:return L_THREE;
					case 4:return L_FOUR;
					}				
				}
			}
		}
		return 0;
	}
	
	private int getScore(int row,int col,int color)
	{
		int result=0;
		int heng=score(row,col,HENG,color);int hengl=score(row,col,HENG,-color);
		int shu=score(row,col,SHU,color);int shul=score(row,col,SHU,-color);
		int xie45=score(row,col,XIE45,color);int xie45l=score(row,col,XIE45,-color);
		int xie135=score(row,col,XIE135,color);int xie135l=score(row,col,XIE135,-color);
		/*int[] temp=new int[8];
		temp[heng]++;
		temp[shu]++;
		temp[xie45]++;
		temp[xie135]++;
		if()*/
		result=heng+shu+xie45+xie135+hengl+shul+xie45l+xie135l;
		
		return result;
	}
	
	private boolean isWin(int row,int col,int color)//判断当前点是否有五连的情况
	{
		int max=0;
		int temp=0;
		//判断横向
		for(int i=0;i<COL;i++)
		{
			if(chesses[row][i]==color)
			{
				temp++;
				if(max<temp)
				{
					max=temp;
				}
			}
			else
			{				
				temp=0;
			}
		}
		if(max>=5)
		{
			return true;
		}
		//判断纵向
		temp=0;max=0;
		for(int i=0;i<ROW;i++)
		{
			if(chesses[i][col]==color)
			{
				temp++;
				if(max<temp)
				{
					max=temp;
				}
			}
			else
			{
				temp=0;
			}
		}
		if(max>=5)
		{
			return true;
		}
		//判断右下方向
		int x=row,y=col;
		max=0;
		while(x>=0&&x<ROW&&y>=0&&y<COL&&chesses[x][y]==color)
		{
			x--;
			y--;
		}
		x++;y++;
		while(x>=0&&x<ROW&&y>=0&&y<COL&&chesses[x][y]==color)
		{
			max++;
			x++;
			y++;
		}
		if(max>=5)
		{
			return true;
		}
		//判断右上方向
		x=row;y=col;
		max=0;
		while(x>=0&&x<ROW&&y>=0&&y<COL&&chesses[x][y]==color)
		{
			x--;
			y++;
		}
		x++;y--;
		while(x>=0&&x<ROW&&y>=0&&y<COL&&chesses[x][y]==color)
		{
			max++;
			x++;
			y--;
		}
		if(max>=5)
		{
			return true;
		}
		return false;
	}
	
	private class AI extends Thread//电脑走棋的线程
	{
		@Override
		public void run()
		{
			isHumTurn=false;
			int row=(int)(Math.random()*ROW);
			int col=(int)(Math.random()*COL);
			while(chesses[row][col]!=0)
			{
				row=(int)(Math.random()*ROW);
				col=(int)(Math.random()*COL);
			}
			
			int score=0;
			for(int i=0;i<ROW;i++)
			{
				for(int j=0;j<COL;j++)
				{
					if(chesses[i][j]!=0)
					{
						//System.out.print(i+","+j+">"+chesses[i][j]+" ");
						continue;
					}
					int temp=getScore(i,j,aiColor);
					//System.out.print(i+","+j+"="+temp+" ");
					if(score<temp)
					{
						row=i;
						col=j;
						score=temp;
					}
				}
				//System.out.println();
			}
			goOneStep(row,col,aiColor);
			isHumTurn=true;
		}
	}
	
	private void aiGoOneStep()//电脑走一步棋的方法
	{
		/*AI ai=new AI();
		ai.start();*/
		
		isHumTurn=false;
		int row=0;
		int col=0;
		if(chessProcess.size()==0)
		{
			row=7;col=7;
			goOneStep(row,col,aiColor);
			isHumTurn=true;
			return;
		}
		
		int score=0;
		//System.out.println(aiColor);
		for(int i=0;i<ROW;i++)
		{
			for(int j=0;j<COL;j++)
			{
				if(chesses[i][j]!=0)
				{
					//System.out.print(i+","+j+">"+chesses[i][j]+" ");
					continue;
				}
				int temp=getScore(i,j,aiColor);
				//System.out.print(i+","+j+"="+temp+" ");
				if(score<temp)
				{
					row=i;
					col=j;
					score=temp;
				}
			}
			//System.out.println();
		}
		goOneStep(row,col,aiColor);
		isHumTurn=true;
	}
	//重写鼠标监听事件
	@Override
	public void mouseClicked(MouseEvent e)
	{
		
	}

	@Override
	public void mouseEntered(MouseEvent e)
	{
		
	}

	@Override
	public void mouseExited(MouseEvent e)
	{
		
	}

	@Override
	public void mousePressed(MouseEvent e)
	{
		
	}

	@Override
	public void mouseReleased(MouseEvent e)//当鼠标抬起时触发,玩家在指定位置走一步棋
	{
		if(!isHumTurn||winner!=NONE)
		{
			return;
		}
		Point p=pressWhere(e);
		if(chesses[p.x][p.y]!=0)
		{
			return;
		}
		isHumTurn=false;
		goOneStep(p.x,p.y,humColor);		
	}
	
	public void dianNaoJianQi()
	{
		if(!isHumTurn||winner!=NONE)
		{
			return;
		}
		int row=(int)(Math.random()*ROW);
		int col=(int)(Math.random()*COL);
		while(chesses[row][col]!=0)
		{
			row=(int)(Math.random()*ROW);
			col=(int)(Math.random()*COL);
		}
		
		int score=0;
		//System.out.println(aiColor);
		for(int i=0;i<ROW;i++)
		{
			for(int j=0;j<COL;j++)
			{
				if(chesses[i][j]!=0)
				{
					//System.out.print(i+","+j+">"+chesses[i][j]+" ");
					continue;
				}
				int temp=getScore(i,j,humColor);
				//System.out.print(i+","+j+"="+temp+" ");
				if(score<temp)
				{
					row=i;
					col=j;
					score=temp;
				}
			}
			//System.out.println();
		}
		goOneStep(row,col,humColor);
	}
}

最后是源码下载链接:http://download.csdn.net/detail/lgl1170860350/7161707,设置了一点下载积分。

  • 5
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值