AI算法实现五子棋(java)

 更新时间:2018年09月28日 15:35:39   作者:胡豫南  
这篇文章主要为大家详细介绍了AI算法实现五子棋,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了AI算法实现五子棋的具体代码,供大家参考,具体内容如下

首先,实现一个五子棋要有一个棋盘,然后在这个棋盘上我们再来画出图画,五子棋棋盘有固定的行数和列数,再加上界面的大小和菜单栏,这些数据可能很多个类都需要用到,我们可以先考虑自己写一个接口用来存储这些数据:

public interface Config {
 public static final int SIZE=703;
 //面板大小
 public static final int X0=SIZE/19*2-8;
 public static final int Y0=X0-15;
 //棋盘网格起始点
 public static final int WID=SIZE/19;
 //行宽
 public static final int LINE=15;
 //行数
 public static final int CHESS=WID;
 //五子棋棋子大小
 
}

这个时候我们来考虑写一个五子棋界面,除了常用的界面写法之外,考虑到五子棋的悔棋和重新开始,我们需要重写paint方法,在需要的时候调用来达到更新棋盘的作用。

import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
 
import javax.swing.JPanel;
 
 
public class Fivebord extends JPanel implements Config{
 private static final long serialVersionUID = 1L;
 private int point[][]=new int [SIZE][SIZE];
 
 public static void main(String[] args) {
 Fivebord fb = new Fivebord();
 fb.showFivebord();
 }
 
 public void showFivebord() {
 //一下是关于界面的常规设置
 javax.swing.JFrame jf = new javax.swing.JFrame();
 jf.setTitle("FIVEBORD");
 jf.setSize(SIZE+100, SIZE);
 jf.setDefaultCloseOperation(3);
 jf.setLocationRelativeTo(null);
 jf.setLayout(new BorderLayout()); 
 
 JPanel jp1=new JPanel();
 jp1.setBackground(Color.ORANGE);
 jp1.setPreferredSize(new Dimension(100, SIZE));
 jf.add(jp1,BorderLayout.EAST); 
 
 javax.swing.JButton jbu1 = new javax.swing.JButton("悔棋");
 jp1.add(jbu1); 
 
 javax.swing.JButton jbu2 = new javax.swing.JButton("人机");
 jp1.add(jbu2);
 
 javax.swing.JButton jbu3 = new javax.swing.JButton("人人");
 jp1.add(jbu3);
 
 this.setBackground(Color.YELLOW);
 jf.add(this,BorderLayout.CENTER);
 
 jf.setVisible(true); 
 
 //以下给界面添加监听器,包括画板和按钮
  DrawMouse mouse=new DrawMouse(this);
  jbu1.addActionListener(mouse);
  jbu2.addActionListener(mouse);
  jbu3.addActionListener(mouse);
  this.addMouseListener(mouse);
  //监听器中需要考虑当前棋盘上的棋子和位置
  mouse.setpoint(point);
    
 
 }
 public void paint(Graphics g) {
 super.paint(g); 
 //super.paint 
 //由于paint函数是界面自带的函数且在某些时候会自动调用
 //super.paint(g)表示屏蔽父类的函数内容,换做自己接下来改写的内容
 Graphics2D gr = (Graphics2D)g; 
 gr.setStroke(new BasicStroke(1));
 //2D画笔变粗度为1
 for(int i=X0;i<=X0+LINE*WID;i+=WID){
 for(int j=Y0;j<=Y0+LINE*WID;j+=WID){
 g.drawLine(X0, j, X0+LINE*WID, j);
 g.drawLine(i, Y0, i,Y0+LINE*WID);
 }
 } 
 //画内部16格
 gr.setStroke(new BasicStroke(2));
 //画笔粗度变为2
 g.drawLine(X0-WID, Y0-WID, X0-WID, Y0+(LINE+1)*WID);
 g.drawLine(X0-WID, Y0-WID, X0+(LINE+1)*WID, Y0-WID);
 g.drawLine(X0+(LINE+1)*WID, Y0-WID, X0+(LINE+1)*WID, Y0+(LINE+1)*WID);
 g.drawLine(X0-WID, Y0+(LINE+1)*WID, X0+(LINE+1)*WID, Y0+(LINE+1)*WID);
 //画四周较粗的边框(美观起见,没有实际意义)
 for(int i=X0;i<=X0+(WID*(LINE+1));i+=WID){
   for(int j=Y0;j<=Y0+(LINE+1)*WID;j+=WID){
   if(point[i][j]==1){
   //画黑棋
   g.setColor(Color.BLACK);
   g.fillOval(i-WID/2, j-WID/2, WID, WID);
   }
   else if(point[i][j]==2){
   //画白棋
   g.setColor(Color.WHITE);
   g.fillOval(i-WID/2, j-WID/2, WID, WID);
   }
   }
  }
 //根据point的内容画出相应的点(即棋子)
 } 
 
}

最最重要的就是监听器部分了,除了具有相应的监听功能,还要在每次人下棋之后智能判断出机器所需要下的位置,于此同时,每下一个棋子,都要判断是否已经有五子连成线进而提示输赢。

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.HashMap;
 
import javax.swing.JOptionPane;
 
public class DrawMouse extends MouseAdapter implements Config,ActionListener{
 //添加动作监听器(监听按钮)和鼠标监听器(鼠标所点位置画棋子)
 private Graphics g;
 private int x,y,CO=1,index=0;
 private int point[][];
 private int pointweight[][]=new int [X0+(LINE+1)*WID][Y0+(LINE+1)*WID];
 private int orderx[]=new int [X0+(LINE+1)*WID],ordery[]=new int [Y0+(LINE+1)*WID];
 private Fivebord fb;
 private int pc=0;
 public HashMap <String,Integer> hm = new HashMap <String,Integer>();
 //哈希表用来存放不同棋子布局下的不同权值
 
 
 DrawMouse(Fivebord fb) {
 this.g = fb.getGraphics();
 this.fb=fb;
 sethashmap();
 }
 //传棋子数组
 public void setpoint(int point[][]){
  this.point=point;
 }
 public void sethashmap(){
 hm.put("1", 1);
 //某一方向线上只有一个黑棋
 hm.put("12", 5);
 //某一方向线上紧接着一个黑棋有一个白棋
 hm.put("11", 10);
 hm.put("112", 15);
 //某一方向线上紧接着两个相邻的黑棋后有一个白棋(以此类推)
 hm.put("111", 100);
 hm.put("1112", 105);
 hm.put("1111", 1000);
 
 hm.put("2", 1);
 hm.put("21", 5);
 hm.put("22", 10);
 hm.put("221", 15);
 hm.put("222", 100);
 hm.put("2221", 105);
 hm.put("2222", 1000);
 }
 
 public void actionPerformed(ActionEvent e){
 //悔棋操作,将棋子数目减一,然后重绘界面即可
 if("悔棋".equals(e.getActionCommand())&&index>0){
 System.out.println("悔棋");
 index--;
 point[orderx[index]][ordery[index]]=0;
 fb.paint(g);
 }
 //人机模式一旦点击,界面所有棋子清零,开始人机对战(pc=1)
 if("人机".equals(e.getActionCommand())){
 System.out.println("人机");
  pc=1;
  index=0;
  for(int i=X0;i<=X0+WID*LINE;i+=WID){
  for(int j=Y0;j<=Y0+WID*LINE;j+=WID){
  point[i][j]=0; 
  }
  }
  fb.paint(g);
 }
 //人人对战,也是点击按钮棋子清零,开始人人对战(pc=0)
 if("人人".equals(e.getActionCommand())){
 System.out.println("人机");
  pc=0;
  index=0;
  for(int i=X0;i<=X0+WID*LINE;i+=WID){
  for(int j=Y0;j<=Y0+WID*LINE;j+=WID){
  point[i][j]=0; 
  }
  }
  fb.paint(g);
 }
 }
 
 public void mouseClicked(MouseEvent e) {
 x=e.getX();
 y=e.getY();
 //得到点击的点
 if((x-X0)%WID>=WID/2){
 x=x-(x-X0)%WID+WID;
 }
 else{
 x=x-(x-X0)%WID;
 }
 if((y-Y0)%WID>=WID/2){
 y=y-(y-Y0)%WID+WID;
 }
 else{
 y=y-(y-Y0)%WID;
 }
 //对点的位置进行修正(保证每次点击都正好下在网格交汇处)
 if(point[x][y]==0&&x>=X0&&x<=X0+WID*LINE&&y>=Y0&&y<=Y0+WID*LINE){
 //人人对战:直接用鼠标检测,依次变换颜色黑或白
 if(pc==0){
 if(g.getColor()==Color.black){
  g.setColor(Color.WHITE);
  CO=2;
 }
 else{
  g.setColor(Color.BLACK);
  CO=1;
 }
 }
 //人机对战,每次人下过棋子之后,计算机根据现有棋盘布局对棋局分析和总和并判断机器需要下的位置
 else if(pc==1){
 g.setColor(Color.BLACK);
 CO=1;
 }
 g.fillOval(x-WID/2, y-WID/2, WID, WID);
  point[x][y]=CO;
  System.out.println(index+ " "+ x+" "+y);
  orderx[index]=x;
  ordery[index]=y;
  index++;
  if(exam()==0){
  //自己敲代码过程中的验证、、、、、、可以不用在意这类输出。
  System.out.println("hahahahhhaahhahah");
  if(pc==1){
  System.out.println("HEHEHEHEHEHEHEHEHEHEHE");
  g.setColor(Color.WHITE);
  CO=2;
  AI();
  exam();
  }
  }
 }
 
 }
 //检测是否有一方获胜,跳出提示框提示某一方获胜
 public int exam(){
 int w=0;
 for(int i=X0-WID;i<=X0+WID*(LINE+1);i+=WID){
 for(int j=Y0-WID;j<=Y0+WID*(LINE+1);j+=WID){
 if(point[i][j]!=0){
  int exam1=0,exam2=0,exam3=0,exam4=0;
  //水平、竖直、左斜、右斜四个方向上同色棋子相连最多的个数
  for(int t=WID;t<5*WID;t+=WID){
  if(i+t<=X0+WID*(LINE+1)&&point[i+t][j]==point[i][j]){
  exam1++;
  }
  if(j+t<=Y0+WID*(LINE+1)&&point[i][j+t]==point[i][j]){
  exam2++;
  }
  if(i+t<=X0+WID*(LINE+1)&&j+t<=Y0+WID*(LINE+1)&&point[i+t][j+t]==point[i][j]){
  exam3++;
  }
  if(i+t<=X0+WID*(LINE+1)&&j>=t&&point[i+t][j-t]==point[i][j]){
  exam4++;
  }
  }
  System.out.println(exam1+" "+exam2+" " +exam3+" "+exam4);
  if(exam1==4||exam2==4||exam3==4||exam4==4){//某一方向上同色5子相连,一方获胜
  if(point[i][j]==1){
  w=1;
  //弹出提示框
  JOptionPane.showMessageDialog(null, "黑子胜");
  }
  else{
  w=2;
  JOptionPane.showMessageDialog(null, "白子胜");  
  }
  i=X0+WID*(LINE+1)+1;
  break;
  }
 }
 }
 }
 return w;
 }
 //AI算法
 //分别向左、香油、左下、、、、、等8个方向检测棋子布局情况并累加在该点的权值上
 //再找出图片上没有棋子并且权值最大的点下棋子
 //记得每次下棋将各个空位置的权值归0,以便下一次计算权值累加
 public void AI(){
 for(int i=X0;i<X0+WID*(LINE+1);i+=WID){
  for(int j=Y0;j<Y0+WID*(LINE+1);j+=WID){
 if(point[i][j]==0){
  //像右寻找
  //System.out.print("pointweight["+(i-X0)/WID+"]["+(j-Y0)/WID+"]:");
  int color=0;
  String code="";
  for(int k=i+WID;k<=X0+WID*LINE;k+=WID){
  if(point[k][j]!=0){
  if(color==0){
  color=point[k][j];
  code+=point[k][j];
  }
  else{
  if(point[k][j]==color){
   code+=point[k][j];
  }
  else{
   code+=point[k][j];
   break;
  }
  }
  }
  else{
  break;
  }
  }
  Integer value=hm.get(code);
  if(value != null){
  pointweight[i][j] += value;
  }
  //向下寻找
//  System.out.print(pointweight[i][j]+" ");
  code="";
  color=0;
  for(int k=j+WID;k<=X0+WID*LINE;k+=WID){
  if(point[i][k]!=0){
  if(color==0){
  color=point[i][k];
  code+=point[i][k];
  }
  else{
  if(point[i][k]==color){
   code+=point[i][k];
  }
  else{
   code+=point[i][k];
   break;
  }
  }
  }
  else{
  break;
  }
  }
  value=hm.get(code);
  if(value != null){
  pointweight[i][j] += value;
  }
  //向左
//  System.out.print(pointweight[i][j]+" ");
  code="";
  color=0;
  for(int k=i-WID;k>=X0;k-=WID){
  if(point[k][j]!=0){
  if(color==0){
  color=point[k][j];
  code+=point[k][j];
  }
  else{
  if(point[k][j]==color){
   code+=point[k][j];
  }
  else{
   code+=point[k][j];
   break;
  }
  }
  }
  else{
  break;
  }
  }
  value=hm.get(code);
  if(value != null){
  pointweight[i][j] += value;
  }
  //向上
//  System.out.print(pointweight[i][j]+" ");
  code="";
  color=0;
  for(int k=j-WID;k>=Y0;k-=WID){
  if(point[i][k]!=0){
  if(color==0){
  color=point[i][k];
  code+=point[i][k];
  }
  else{
  if(point[i][k]==color){
   code+=point[i][k];
  }
  else{
   code+=point[i][k];
   break;
  }
  }
  }
  else{
  break;
  }
  }
  value=hm.get(code);
  if(value != null){
  pointweight[i][j] += value;
  }
  //向右上寻找
//  System.out.print(pointweight[i][j]+" ");
  code="";
  color=0;
  for(int k=i+WID,w=j+WID;k<=X0+WID*LINE&&w<=Y0+WID*LINE;k+=WID,w+=WID){
  if(point[k][w]!=0){
  if(color==0){
  color=point[k][w];
  code+=point[k][w];
  }
  else{
  if(point[k][w]==color){
   code+=point[k][w];
  }
  else{
   code+=point[k][w];
   break;
  }
  }
  }
  else{
  break;
  }
  }
  value=hm.get(code);
  if(value != null){
  pointweight[i][j] += value;
  }
//  System.out.print(pointweight[i][j]+" ");
  code="";
  color=0;
  for(int k=i-WID,w=j-WID;k>=X0&&w>=Y0;k-=WID,w-=WID){
  if(point[k][w]!=0){
  if(color==0){
  color=point[k][w];
  code+=point[k][w];
  }
  else{
  if(point[k][w]==color){
   code+=point[k][w];
  }
  else{
   code+=point[k][w];
   break;
  }
  }
  }
  else{
  break;
  }
  }
  value=hm.get(code);
  if(value != null){
  pointweight[i][j] += value;
  }
//  System.out.print(pointweight[i][j]+" ");
  code="";
  color=0;
  for(int k=i+WID,w=j-WID;k<=X0+LINE*WID&&w>=Y0;k+=WID,w-=WID){
  if(point[k][w]!=0){
  if(color==0){
  color=point[k][w];
  code+=point[k][w];
  }
  else{
  if(point[k][w]==color){
   code+=point[k][w];
  }
  else{
   code+=point[k][w];
   break;
  }
  }
  }
  else{
  break;
  }
  }
  value=hm.get(code);
  if(value != null){
  pointweight[i][j] += value;
  }
//  System.out.print(pointweight[i][j]+" ");
  code="";
  color=0;
  for(int k=i-WID,w=j+WID;k>=X0&&w<=Y0+LINE*WID;k-=WID,w+=WID){
  if(point[k][w]!=0){
  if(color==0){
  color=point[k][w];
  code+=point[k][w];
  }
  else{
  if(point[k][w]==color){
   code+=point[k][w];
  }
  else{
   code+=point[k][w];
   break;
  }
  }
  }
  else{
  break;
  }
  }
  value=hm.get(code);
  if(value != null){
  pointweight[i][j] += value;
  }
//  System.out.println(pointweight[i][j]);
 } 
 }
 }
 //寻找最大权值的点并画棋子
 int maxx=X0,maxy=Y0;
  for(int i=X0;i<=X0+WID*LINE;i+=WID){
  for(int j=Y0;j<=Y0+WID*LINE;j+=WID){
  System.out.print(pointweight[i][j]+" ");
  if(pointweight[i][j]>pointweight[maxx][maxy]){
  maxx=i;
  maxy=j;
  }
  
  }
  System.out.println();
  }
  g.fillOval(maxx-WID/2, maxy-WID/2, WID, WID); 
  point[maxx][maxy]=CO;
  System.out.println(index+ " "+ maxx+" "+maxy);
  orderx[index]=maxx;
  ordery[index]=maxy;
  index++;
  //全部权值归零方便下次使用
  for(int i=X0;i<=X0+WID*LINE;i+=WID){
  for(int j=Y0;j<=Y0+WID*LINE;j+=WID){
  pointweight[i][j]=0; 
  }
  }
 }
 
}

大概就是这个样子了,权值那里设置的还是需要调整一下。运行结果截图如下:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • 教你怎么用Springboot自定义Banner图案

    教你怎么用Springboot自定义Banner图案

    今天给大家带来的是Java的相关知识,文章围绕着怎么用Springboot自定义Banner图案展开,文中有非常详细的介绍及代码示例,需要的朋友可以参考下
    2021-06-06
  • javax.servlet不存在的解决办法

    javax.servlet不存在的解决办法

    今天在关于servlet的编译中出现了一下小小的错误,发现javax.servlet不存在,本文就介绍一下解决方法,感兴趣的可以了解一下
    2021-07-07
  • Java虚拟机GC日志分析

    Java虚拟机GC日志分析

    这篇文章主要介绍了Java虚拟机GC日志分析,分享了相关代码示例,小编觉得还是挺不错的,具有一定借鉴价值,需要的朋友可以参考下
    2018-02-02
  • Maven导入依赖时爆红的几种解决方法

    Maven导入依赖时爆红的几种解决方法

    使用idea建立maven项目,maven导入依赖报红,本文主要介绍了Maven导入依赖时爆红的几种解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-04-04
  • Java C++实现相同MD5加密算法的方式

    Java C++实现相同MD5加密算法的方式

    这篇文章主要介绍了Java与C++实现相同MD5加密算法的方法,需要的朋友可以参考下面文章内容
    2021-09-09
  • restTemplate发送get与post请求并且带参数问题

    restTemplate发送get与post请求并且带参数问题

    这篇文章主要介绍了restTemplate发送get与post请求并且带参数问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-07-07
  • 用命令行编译java并生成可执行的jar包方法

    用命令行编译java并生成可执行的jar包方法

    下面小编就为大家分享一篇用命令行编译java并生成可执行的jar包方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2017-12-12
  • Java超详细教你写一个学籍管理系统案例

    Java超详细教你写一个学籍管理系统案例

    这篇文章主要介绍了怎么用Java来写一个学籍管理系统,学籍管理主要涉及到学生信息的增删查改,本篇将详细的实现,感兴趣的朋友跟随文章往下看看吧
    2022-03-03
  • Java中logback 自动刷新不生效的问题解决

    Java中logback 自动刷新不生效的问题解决

    本文主要介绍了Java中logback 自动刷新不生效的问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-05-05
  • mybatis多层嵌套resultMap及返回自定义参数详解

    mybatis多层嵌套resultMap及返回自定义参数详解

    这篇文章主要介绍了mybatis多层嵌套resultMap及返回自定义参数详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12

最新评论