Java实现五子棋AI算法

五子棋AI算法 也算是一个典型的游戏AI算法,一些棋类的AI算法都可以参考实现,下面是Java实现代码

棋盘抽象接口

import java.util.List; 

public interface IChessboard {
  //取得棋盘最大横坐标
  public int getMaxX();
  //最大纵坐标
  public int getMaxY();
  //取得当前所有空白点,这些点才可以下棋
  public List<Point> getFreePoints();
}

棋子类实现

//棋子类
public class Point {
  // 这了性能,设成公有
  public int x;
  public int y; 

  public int getX() {
    return x;
  } 

  public Point setX(int x) {
    this.x = x;
    return this;
  } 

  public int getY() {
    return y;
  } 

  public Point setY(int y) {
    this.y = y;
    return this;
  } 

  public Point(int x, int y) {
    this.x = x;
    this.y = y;
  } 

  @Override
  public int hashCode() {
    return x + y;
  } 

  @Override
  public boolean equals(Object obj) {
    if (this == obj)
      return true;
    Point other = (Point) obj;
    if (x != other.x)
      return false;
    if (y != other.y)
      return false;
    return true;
  } 

}

玩家抽象接口

import java.util.List; 

public interface IPlayer {
  //下一步棋子,传入对手已经下的棋子集合
  public void run(List<Point> enemyPoints, Point point); 

  public boolean hasWin(); 

  public void setChessboard(IChessboard chessboard); 

  public List<Point> getMyPoints();
}

玩家基础抽象类

import java.util.ArrayList;
import java.util.List; 

public abstract class BasePlayer implements IPlayer {
  //我已下的棋子
  protected List<Point> myPoints = new ArrayList<Point>(200);
  //棋盘
  protected IChessboard chessboard;
  //棋盘最大横坐标和纵标,
  protected int maxX;
  protected int maxY; 

  //所有空白棋子
  protected List<Point> allFreePoints; 

  @Override
  public final List<Point> getMyPoints() {
    return myPoints;
  } 

  @Override
  public void setChessboard(IChessboard chessboard) {
    this.chessboard = chessboard;
    allFreePoints = chessboard.getFreePoints();
    maxX = chessboard.getMaxX();
    maxY = chessboard.getMaxY();
    myPoints.clear();
  } 

  private final Point temp = new Point(0, 0);
  //我是否是否赢了
  public final boolean hasWin(){
    if(myPoints.size()<5){
      return false;
    }
    Point point = myPoints.get(myPoints.size()-1);
    int count = 1;
    int x=point.getX(),y=point.getY();
    //横向--
    temp.setX(x).setY(y);
    while (myPoints.contains(temp.setX(temp.getX()-1)) && temp.getX()>=0 && count<5) {
      count ++;
    }
    if(count>=5){
      return true;
    }
    temp.setX(x).setY(y);
    while (myPoints.contains(temp.setX(temp.getX()+1)) && temp.getX()<maxX && count<5) {
      count ++;
    }
    if(count>=5){
      return true;
    }
    //纵向|
    count = 1;
    temp.setX(x).setY(y);
    while (myPoints.contains(temp.setY(temp.getY()-1)) && temp.getY()>=0) {
      count ++;
    }
    if(count>=5){
      return true;
    }
    temp.setX(x).setY(y);
    while (myPoints.contains(temp.setY(temp.getY()+1)) && temp.getY()<maxY && count<5) {
      count ++;
    }
    if(count>=5){
      return true;
    }
    //正斜向 /
    count =1;
    temp.setX(x).setY(y);
    while (myPoints.contains(temp.setX(temp.getX()-1).setY(temp.getY()+1)) && temp.getX()>=0 && temp.getY()<maxY) {
      count ++;
    }
    if(count>=5){
      return true;
    }
    temp.setX(x).setY(y);
    while (myPoints.contains(temp.setX(temp.getX()+1).setY(temp.getY()-1)) && temp.getX()<maxX && temp.getY()>=0 && count<6) {
      count ++;
    }
    if(count>=5){
      return true;
    }
    //反斜 \
    count = 1;
    temp.setX(x).setY(y);
    while (myPoints.contains(temp.setX(temp.getX()-1).setY(temp.getY()-1)) && temp.getX()>=0 && temp.getY()>=0) {
      count ++;
    }
    if(count>=5){
      return true;
    }
    temp.setX(x).setY(y);
    while (myPoints.contains(temp.setX(temp.getX()+1).setY(temp.getY()+1)) && temp.getX()<maxX && temp.getY()<maxY && count<5) {
      count ++;
    }
    if(count>=5){
      return true;
    }
    return false;
  }
}

电脑AI类实现

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map; 

//算法核心类,算法的主体思想分三个步骤,
//第一步:根据双方的当前的形势循环地假设性的分别给自己和对方下一子(在某个范围内下子),并判断此棋子能带来的形势上的变化,如能不能冲4,能不能形成我方或敌方双3等,
//第二步:根据上一步结果,组合每一步棋子所带来的所有结果(如某一步棋子可能形成我方1个活3,1个冲4(我叫它半活4)等),包括敌方和我方的。
//第三步:根据用户给的规则对上一步结果进行排序,并选子(有进攻形、防守形规则)
public class BaseComputerAi extends BasePlayer { 

  // 四个方向,横- 、纵| 、正斜/ 、反斜\
  private static final int HENG = 0;
  private static final int ZHONG = 1;
  private static final int ZHENG_XIE = 2;
  private static final int FAN_XIE = 3;
  //往前往后
  private static final boolean FORWARD = true;
  private static final boolean BACKWARD = false; 

  //标示分析结果当前点位是两头通(ALIVE)还是只有一头通(HALF_ALIVE),封死的棋子分析过程自动屏蔽,不作为待选棋子
  private static final int ALIVE = 1;
  private static final int HALF_ALIVE = 0;
  //private static final int DEAD = -1; 

  //计算范围,太大的范围会有性能问题
  private class CalcuteRange{
    int xStart,yStart,xStop,yStop;
    private CalcuteRange(int xStart, int yStart, int xStop, int yStop) {
      this.xStart = xStart;
      this.yStart = yStart;
      this.xStop = xStop;
      this.yStop = yStop;
    }
  } 

  //限定电脑计算范围,如果整个棋盘计算,性能太差,目前是根据所有已下的棋子的边界值加RANGE_STEP值形成,目前为1
  private static final int RANGE_STEP = 1;
  CalcuteRange currentRange = new CalcuteRange(0, 0, 0, 0);
  private void initRange(List<Point> comuters, List<Point> humans){
    currentRange.xStart = humans.get(0).getX()-RANGE_STEP;
    currentRange.yStart = humans.get(0).getY()-RANGE_STEP;
    currentRange.xStop = humans.get(0).getX()+RANGE_STEP;
    currentRange.yStop = humans.get(0).getY()+RANGE_STEP;
    for (Point point : humans) {
      if(point.getX()-RANGE_STEP<currentRange.xStart){
        currentRange.xStart = point.getX()-RANGE_STEP;
      }else if(point.getX()+RANGE_STEP>currentRange.xStop){
        currentRange.xStop = point.getX()+RANGE_STEP;
      }
      if(point.getY()-RANGE_STEP<currentRange.yStart){
        currentRange.yStart = point.getY()-RANGE_STEP;
      }else if(point.getY()+RANGE_STEP>currentRange.yStop){
        currentRange.yStop = point.getY()+RANGE_STEP;
      }
    }
    for (Point point : comuters) {
      if(point.getX()-RANGE_STEP<currentRange.xStart){
        currentRange.xStart = point.getX()-RANGE_STEP;
      }else if(point.getX()+RANGE_STEP>currentRange.xStop){
        currentRange.xStop = point.getX()+RANGE_STEP;
      }
      if(point.getY()-RANGE_STEP<currentRange.yStart){
        currentRange.yStart = point.getY()-RANGE_STEP;
      }else if(point.getY()+RANGE_STEP>currentRange.yStop){
        currentRange.yStop = point.getY()+RANGE_STEP;
      }
    } 

    //如果范围扩大后超过了棋盘,则等于棋盘
    currentRange.xStart=currentRange.xStart<0?0:currentRange.xStart;
    currentRange.yStart=currentRange.yStart<0?0:currentRange.yStart;
    currentRange.xStop=currentRange.xStop>=maxX?maxX-1:currentRange.xStop;
    currentRange.yStop=currentRange.yStop>=maxY?maxY-1:currentRange.yStop;
  } 

  // 分析当前形式的入口方法,分析总共分三个步骤,第三步骤可由子类干预以作难度控制
  private Point doAnalysis(List<Point> comuters, List<Point> humans) {
    if(humans.size()==1){//第一步
      return getFirstPoint(humans);
    } 

    //初始化计算范围
    initRange(comuters, humans); 

    //清除以前的结果
    initAnalysisResults();
    // 开始分析,扫描所有空白点,形成第一次分析结果
    Point bestPoint = doFirstAnalysis(comuters, humans);
    if(bestPoint!=null){
      //System.out.println("这个棋子最重要,只能下这个棋子");
      return bestPoint;
    }
    // 分析第一次结果,找到自己的最佳点位
    bestPoint = doComputerSencondAnalysis(computerFirstResults,computerSencodResults);
    if(bestPoint!=null){
      //System.out.println("快要赢了,就下这个棋子");
      return bestPoint;
    }
    computerFirstResults.clear();
    System.gc();
    // 分析第一次结果,找到敌人的最佳点位
    bestPoint = doHumanSencondAnalysis(humanFirstResults,humanSencodResults);
    if(bestPoint!=null){
      //System.out.println("再不下这个棋子就输了");
      return bestPoint;
    }
    humanFirstResults.clear();
    System.gc();
    //没找到绝杀点,第三次结果分析
    return doThirdAnalysis();
  } 

  //下第一步棋子,不需要复杂的计算,根据人类第一步棋子X值减1完成
  private Point getFirstPoint(List<Point> humans) {
    Point point = humans.get(0);
    if(point.getX()==0 || point.getY()==0 || point.getX()==maxX && point.getY()==maxY)
      return new Point(maxX/2, maxY/2);
    else{
      return new Point(point.getX()-1,point.getY());
    }
  } 

// private int debugx,debugy;//用于DEBUG 

  // 开始分析,扫描所有空白点,形成第一次分析结果
  private Point doFirstAnalysis(List<Point> comuters, List<Point> humans){
    int size = allFreePoints.size();
    Point computerPoint = null;
    Point humanPoint = null;
    int x,y;
    FirstAnalysisResult firstAnalysisResult;
    for (int i = 0; i < size; i++) {
      computerPoint = allFreePoints.get(i);
      //先把X、Y坐标记下来,因为在分析过程中会改变原来的对象
      x = computerPoint.getX();
      y = computerPoint.getY();
      if(x<currentRange.xStart || x>currentRange.xStop || y<currentRange.yStart || y>currentRange.yStop){
        continue;
      } 

//     if(x==debugx && y==debugy){
//       System.out.println("sssssssssssss");
//     } 

      //尝试在此位置上下一个棋子,并分析在“横向”这个方向上我方可形成的状态,如活4,活3,半活4,活2等所有状态
      firstAnalysisResult = tryAndCountResult(comuters,humans, computerPoint, HENG);
      computerPoint.setX(x).setY(y);//回复点位的原值,以供下次分析
      if(firstAnalysisResult!=null){//无返回结果此方向上不可能达到五个棋子,
        if(firstAnalysisResult.count==5)//等于5表示在此点上下棋子即可连成5个,胜利了,不再往下进行分析
          return computerPoint;
        //记录第一次分析结果
        addToFirstAnalysisResult(firstAnalysisResult,computerFirstResults);
      } 

      //在“纵向”这个方向上重复上面的步骤
      firstAnalysisResult = tryAndCountResult(comuters,humans, computerPoint, ZHONG);
      computerPoint.setX(x).setY(y);
      if(firstAnalysisResult!=null){//死棋,不下
        if(firstAnalysisResult.count==5)
          return computerPoint; 

        addToFirstAnalysisResult(firstAnalysisResult,computerFirstResults);
      } 

      //正斜向
      firstAnalysisResult = tryAndCountResult(comuters,humans, computerPoint, ZHENG_XIE);
      computerPoint.setX(x).setY(y);
      if(firstAnalysisResult!=null){//死棋,不下
        if(firstAnalysisResult.count==5)
          return computerPoint; 

        addToFirstAnalysisResult(firstAnalysisResult,computerFirstResults);
      } 

      //反斜向
      firstAnalysisResult = tryAndCountResult(comuters,humans, computerPoint, FAN_XIE);
      computerPoint.setX(x).setY(y);
      if(firstAnalysisResult!=null){//死棋,不下
        if(firstAnalysisResult.count==5)
          return computerPoint; 

        addToFirstAnalysisResult(firstAnalysisResult,computerFirstResults);
      } 

      //在“横向”上分析此棋子可在敌方形成如何状态,如敌方的活3、半活4等
      firstAnalysisResult = tryAndCountResult(humans,comuters, computerPoint, HENG);
      computerPoint.setX(x).setY(y);
      if(firstAnalysisResult!=null){//死棋,不下
        if(firstAnalysisResult.count==5)
          humanPoint = computerPoint; 

        addToFirstAnalysisResult(firstAnalysisResult,humanFirstResults);
      } 

      //“纵向”
      firstAnalysisResult = tryAndCountResult(humans,comuters, computerPoint, ZHONG);
      computerPoint.setX(x).setY(y);
      if(firstAnalysisResult!=null){//死棋,不下
        if(firstAnalysisResult.count==5)
          humanPoint = computerPoint; 

        addToFirstAnalysisResult(firstAnalysisResult,humanFirstResults);
      } 

      //“正斜”
      firstAnalysisResult = tryAndCountResult(humans,comuters, computerPoint, ZHENG_XIE);
      computerPoint.setX(x).setY(y);
      if(firstAnalysisResult!=null){//死棋,不下
        if(firstAnalysisResult.count==5)
          humanPoint = computerPoint; 

        addToFirstAnalysisResult(firstAnalysisResult,humanFirstResults);
      } 

      //“反斜”
      firstAnalysisResult = tryAndCountResult(humans,comuters, computerPoint, FAN_XIE);
      computerPoint.setX(x).setY(y);
      if(firstAnalysisResult!=null){//死棋,不下
        if(firstAnalysisResult.count==5)
          humanPoint = computerPoint; 

        addToFirstAnalysisResult(firstAnalysisResult,humanFirstResults);
      }
    }
    //如果没有绝杀棋子,第一次分析不需要返回结果
    return humanPoint;
  } 

  //第二次分析,分析第一次形成的结果,第一次分析结果会把一步棋在四个方向上可形成的结果生成最多四个FirstAnalysisResult对象(敌我各四)
  //这里要把这四个对象组合成一个SencondAnalysisResult对象,
  private Point doComputerSencondAnalysis(Map<Point,List<FirstAnalysisResult>> firstResults,List<SencondAnalysisResult> sencodResults) {
    List<FirstAnalysisResult> list = null;
    SencondAnalysisResult sr = null;
    for (Point p : firstResults.keySet()) {
      sr = new SencondAnalysisResult(p);
      list = firstResults.get(p);
      for (FirstAnalysisResult result : list) {
        if(result.count==4){
          if(result.aliveState==ALIVE){//经过前面的过滤,双方都排除了绝杀棋,有活4就下这一步了,再下一步就赢了
            return result.point;//如果有绝杀,第一轮已返回,在此轮活4已经是好的棋子,直接返回,不再往下分析
          }else{
            sr.halfAlive4 ++;
            computer4HalfAlives.add(sr);
          }
        }else if(result.count==3){
          if(result.aliveState==ALIVE){
            sr.alive3++;
            if(sr.alive3==1){
              computer3Alives.add(sr);
            }else{
              computerDouble3Alives.add(sr);
            }
          }else{
            sr.halfAlive3++;
            computer3HalfAlives.add(sr);
          }
        }else{//半活2在第一阶段已被排除,不再处理
          sr.alive2++;
          if(sr.alive2==1){
            computer2Alives.add(sr);
          }else{
            computerDouble2Alives.add(sr);
          }
        }
      }
      sencodResults.add(sr);
    }
    //没有找到活4
    return null;
  } 

  //这个方法和上面的基本一样,但为了性能,少作几次判断,将人类和电脑的分开了
  private Point doHumanSencondAnalysis(Map<Point,List<FirstAnalysisResult>> firstResults,List<SencondAnalysisResult> sencodResults) {
    List<FirstAnalysisResult> list = null;
    SencondAnalysisResult sr = null;
    for (Point p : firstResults.keySet()) {
      sr = new SencondAnalysisResult(p);
      list = firstResults.get(p);
      for (FirstAnalysisResult result : list) {
        if(result.count==4){
          if(result.aliveState==ALIVE){
            human4Alives.add(sr);
          }else{
            sr.halfAlive4 ++;
            human4HalfAlives.add(sr);
          }
        }else if(result.count==3){
          if(result.aliveState==ALIVE){
            sr.alive3++;
            if(sr.alive3==1){
              human3Alives.add(sr);
            }else{
              humanDouble3Alives.add(sr);
            }
          }else{
            sr.halfAlive3++;
            human3HalfAlives.add(sr);
          }
        }else{
          sr.alive2++;
          if(sr.alive2==1){
            human2Alives.add(sr);
          }else{
            humanDouble2Alives.add(sr);
          }
        }
      }
      sencodResults.add(sr);
    }
    //没有找到活4
    return null;
  } 

  private void sleep(int miniSecond){
    try {
      Thread.sleep(miniSecond);
    } catch (InterruptedException e) {
    }
  } 

  //第三次分析,双方都不可以制造活4,找双活3棋子,不行就找半活4,再不行就找单活3,双活2
  private Point doThirdAnalysis() {
    if(!computer4HalfAlives.isEmpty()){
      return computer4HalfAlives.get(0).point;
    }
    System.gc();
    sleep(300);
    Collections.sort(computerSencodResults);
    System.gc(); 

    //即将单活4,且我没有半活4以上的,只能堵
    Point mostBest = getBestPoint(human4Alives, computerSencodResults);
    if(mostBest!=null)
      return mostBest; 

    Collections.sort(humanSencodResults);
    System.gc(); 

    mostBest = getBestPoint();
    if(mostBest!=null)
      return mostBest; 

    //拿出各自排第一的,谁好就下谁
    return computerSencodResults.get(0).point;
  } 

  //子类实现这个方法,并改变其顺序可以实现防守为主还是猛攻
  protected Point getBestPoint(){
    //即将单活4,且我没有半活4以上的,只能堵
    Point mostBest = getBestPoint(computerDouble3Alives, humanSencodResults);
    if(mostBest!=null)
      return mostBest; 

    mostBest = getBestPoint(computer3Alives, humanSencodResults);
    if(mostBest!=null)
      return mostBest; 

    mostBest = getBestPoint(humanDouble3Alives, computerSencodResults);
    if(mostBest!=null)
      return mostBest; 

    mostBest = getBestPoint(human3Alives, computerSencodResults);
    if(mostBest!=null)
      return mostBest; 

    mostBest = getBestPoint(computerDouble2Alives, humanSencodResults);
    if(mostBest!=null)
      return mostBest; 

    mostBest = getBestPoint(computer2Alives, humanSencodResults);
    if(mostBest!=null)
      return mostBest; 

    mostBest = getBestPoint(computer3HalfAlives, humanSencodResults);
    if(mostBest!=null)
      return mostBest; 

    mostBest = getBestPoint(human4HalfAlives, computerSencodResults);
    if(mostBest!=null)
      return mostBest; 

    mostBest = getBestPoint(humanDouble2Alives, computerSencodResults);
    if(mostBest!=null)
      return mostBest; 

    mostBest = getBestPoint(human2Alives, computerSencodResults);
    if(mostBest!=null)
      return mostBest; 

    mostBest = getBestPoint(human3HalfAlives, computerSencodResults);
    return mostBest;
  } 

  //第三次分析的最后一步,第二次结果已经过排序,在此可以从前面选出最好的棋子
  protected Point getBestPoint(List<SencondAnalysisResult> myBest,List<SencondAnalysisResult> yourSencodResults){
    if(!myBest.isEmpty()){
      if(myBest.size()>1){
        for (SencondAnalysisResult your : yourSencodResults) {
          if(myBest.contains(your)){
            return your.point;
          }
        }
        return myBest.get(0).point;
      }else{
        return myBest.get(0).point;
      }
    }
    return null;
  } 

  //第一次分析结果
  private final Map<Point,List<FirstAnalysisResult>> computerFirstResults = new HashMap<Point,List<FirstAnalysisResult>>();
  private final Map<Point,List<FirstAnalysisResult>> humanFirstResults = new HashMap<Point,List<FirstAnalysisResult>>();
  //第二次总结果
  protected final List<SencondAnalysisResult> computerSencodResults = new ArrayList<SencondAnalysisResult>();
  protected final List<SencondAnalysisResult> humanSencodResults = new ArrayList<SencondAnalysisResult>();
  //第二次分结果,电脑
  protected final List<SencondAnalysisResult> computer4HalfAlives = new ArrayList<SencondAnalysisResult>(2);
  protected final List<SencondAnalysisResult> computerDouble3Alives = new ArrayList<SencondAnalysisResult>(4);
  protected final List<SencondAnalysisResult> computer3Alives = new ArrayList<SencondAnalysisResult>(5);
  protected final List<SencondAnalysisResult> computerDouble2Alives = new ArrayList<SencondAnalysisResult>();
  protected final List<SencondAnalysisResult> computer2Alives = new ArrayList<SencondAnalysisResult>();
  protected final List<SencondAnalysisResult> computer3HalfAlives = new ArrayList<SencondAnalysisResult>(); 

  //第二次分结果,人类
  protected final List<SencondAnalysisResult> human4Alives = new ArrayList<SencondAnalysisResult>(2);
  protected final List<SencondAnalysisResult> human4HalfAlives = new ArrayList<SencondAnalysisResult>(5);
  protected final List<SencondAnalysisResult> humanDouble3Alives = new ArrayList<SencondAnalysisResult>(2);
  protected final List<SencondAnalysisResult> human3Alives = new ArrayList<SencondAnalysisResult>(10);
  protected final List<SencondAnalysisResult> humanDouble2Alives = new ArrayList<SencondAnalysisResult>(3);
  protected final List<SencondAnalysisResult> human2Alives = new ArrayList<SencondAnalysisResult>();
  protected final List<SencondAnalysisResult> human3HalfAlives = new ArrayList<SencondAnalysisResult>(); 

  //第一次分析前清空上一步棋子的分析结果
  private void initAnalysisResults(){
    computerFirstResults.clear();
    humanFirstResults.clear();
    //第二次总结果
    computerSencodResults.clear();
    humanSencodResults.clear();
    //第二次分结果
    computer4HalfAlives.clear();
    computerDouble3Alives.clear();
    computer3Alives.clear();
    computerDouble2Alives.clear();
    computer2Alives.clear();
    computer3HalfAlives.clear(); 

    //第二次分结果,人类
    human4Alives.clear();
    human4HalfAlives.clear();
    humanDouble3Alives.clear();
    human3Alives.clear();
    humanDouble2Alives.clear();
    human2Alives.clear();
    human3HalfAlives.clear();
    System.gc();
  } 

  //加入到第一次分析结果中
  private void addToFirstAnalysisResult(FirstAnalysisResult result,Map<Point,List<FirstAnalysisResult>> dest){
    if(dest.containsKey(result.point)){
      dest.get(result.point).add(result);
    }else{
      List<FirstAnalysisResult> list = new ArrayList<FirstAnalysisResult>(1);
      list.add(result);
      dest.put(result.point, list);
    }
  } 

  //第一次分析结果类
  private class FirstAnalysisResult{
    //连续数
    int count;
    //点位
    Point point;
    //方向
    int direction;
    //状态
    int aliveState;
    private FirstAnalysisResult(int count, Point point, int direction) {
      this(count, point, direction, ALIVE);
    } 

    private FirstAnalysisResult(int count, Point point, int direction,int aliveState) {
      this.count = count;
      this.point = point;
      this.direction = direction;
      this.aliveState = aliveState;
    } 

    private FirstAnalysisResult init(Point point,int direction,int aliveState){
      this.count = 1;
      this.point = point;
      this.direction = direction;
      this.aliveState = aliveState;
      return this;
    } 

    private FirstAnalysisResult cloneMe(){
      return new FirstAnalysisResult(count, point, direction,aliveState);
    } 

  } 

  //第二次分析结果类
  class SencondAnalysisResult implements Comparable<SencondAnalysisResult>{
    int alive4 = 0;
    //活3数量
    int alive3 = 0;
    //半活4,一头封的
    int halfAlive4 = 0;
    //半活3,一头封的
    int halfAlive3 = 0;
    //活2数量
    int alive2 = 0;
    //点位
    Point point; 

    @Override
    public int hashCode() {
      final int prime = 31;
      int result = 1;
      result = prime * result + ((point == null) ? 0 : point.hashCode());
      return result;
    }
    @Override
    public boolean equals(Object obj) {
      SencondAnalysisResult other = (SencondAnalysisResult) obj;
      if (point == null) {
        if (other.point != null)
          return false;
      } else if (!point.equals(other.point))
        return false;
      return true;
    } 

    private SencondAnalysisResult(Point point) {
      this.point = point;
    } 

    //第三次分析时,对第二次分析结果进行排序,此为排序回调函数
    @Override
    public int compareTo(SencondAnalysisResult another) {
      return compareTowResult(this, another);
    } 

  } 

  //返加-1则第一个参数优先,1则第二个参数优先,0则按原来顺序
  private int compareTowResult(SencondAnalysisResult oneResult,SencondAnalysisResult another){
    if(oneResult.alive4>another.alive4){
      return -1;
    }
    if(oneResult.alive4<another.alive4){
      return 1;
    }
    if(oneResult.halfAlive4>another.halfAlive4){
      return -1;
    }
    if(oneResult.halfAlive4<another.halfAlive4){
      return 1;
    }
    if(oneResult.alive3>another.alive3){
      return -1;
    }
    if(oneResult.alive3<another.alive3){
      return 1;
    }
    if(oneResult.alive2>another.alive2){
      return -1;
    }
    if(oneResult.alive2<another.alive2){
      return 1;
    }
    if(oneResult.halfAlive3>another.halfAlive3){
      return -1;
    }
    if(oneResult.halfAlive3>another.halfAlive3){
      return 1;
    }
    return 0;
  } 

  //一个临时对象,供第一次分析时临时存放分析结果使用,如果分析出有活1以上(不含)的结果,则调用其cloneMe方法获得结果,否则抛弃此结果
  private final FirstAnalysisResult far = new FirstAnalysisResult(1, null, HENG);
  // 分析如果在当前位下一子,会形成某个方向上多少个子,参数:当前己方已下的所有点,当前要假设的点,需要判断的方向
  private FirstAnalysisResult tryAndCountResult(List<Point> myPoints,List<Point> enemyPoints, Point point,int direction) {
    int x = point.getX();
    int y = point.getY();
    FirstAnalysisResult fr = null; 

    int maxCountOnThisDirection = maxCountOnThisDirection(point, enemyPoints, direction, 1);
    if(maxCountOnThisDirection<5){
      //无意义的棋子
      return null;//此方向不足五个空位,已排除己方已下的棋子
    }else if(maxCountOnThisDirection==5){
      //半死状态,当是一头通
      fr = far.init(point, direction,HALF_ALIVE);
    }else{
      //两头皆通
      fr = far.init(point, direction,ALIVE);
    } 

    //在前和后的方向上计算一次
    countPoint(myPoints,enemyPoints,point.setX(x).setY(y),fr,direction,FORWARD);
    countPoint(myPoints,enemyPoints,point.setX(x).setY(y),fr,direction,BACKWARD); 

    if(fr.count<=1 || (fr.count==2 && fr.aliveState==HALF_ALIVE)){//活1,半活2及其以下结果,抛弃
      return null;
    }
    //返回复制的结果
    return fr.cloneMe();
  } 

  //棋子出了墙
  private boolean isOutSideOfWall(Point point,int direction){
    if(direction==HENG){
      return point.getX()<0 || point.getX()>=maxX;//最大的X和Y值均在墙外所以用等号
    }else if(direction==ZHONG){
      return point.getY()<0 || point.getY()>=maxY;
    }else{//这里可能有问题
      return point.getX()<0 || point.getY()<0 || point.getX()>=maxX || point.getY()>=maxY;
    }
  } 

  private Point pointToNext(Point point,int direction,boolean forward){
    switch (direction) {
      case HENG:
        if(forward)
          point.x++;
        else
          point.x--;
        break;
      case ZHONG:
        if(forward)
          point.y++;
        else
          point.y--;
        break;
      case ZHENG_XIE:
        if(forward){
          point.x++;
          point.y--;
        }else{
          point.x--;
          point.y++;
        }
        break;
      case FAN_XIE:
        if(forward){
          point.x++;
          point.y++;
        }else{
          point.x--;
          point.y--;
        }
        break;
    }
    return point;
  } 

  //在某个方向(八个中的一个)可下多少棋子,这个方法是第一分析中的核心方法
  private void countPoint(List<Point> myPoints, List<Point> enemyPoints, Point point, FirstAnalysisResult fr,int direction,boolean forward) {
    if(myPoints.contains(pointToNext(point,direction,forward))){
      fr.count ++;
      if(myPoints.contains(pointToNext(point,direction,forward))){
        fr.count ++;
        if(myPoints.contains(pointToNext(point,direction,forward))){
          fr.count ++;
          if(myPoints.contains(pointToNext(point,direction,forward))){
            fr.count ++;
          }else if(enemyPoints.contains(point) || isOutSideOfWall(point,direction)){
            fr.aliveState=HALF_ALIVE;
          }
        }else if(enemyPoints.contains(point) || isOutSideOfWall(point,direction)){
          fr.aliveState=HALF_ALIVE;
        }
      }else if(enemyPoints.contains(point) || isOutSideOfWall(point,direction)){
        fr.aliveState=HALF_ALIVE;
      }
    }else if(enemyPoints.contains(point) || isOutSideOfWall(point,direction)){
      fr.aliveState=HALF_ALIVE;
    }
  } 

  //在某个方向上是否还能下到满五个棋子
  private int maxCountOnThisDirection(Point point,List<Point> enemyPoints,int direction,int count){
    int x=point.getX(),y=point.getY();
    switch (direction) {
    //横向
    case HENG:
      while (!enemyPoints.contains(point.setX(point.getX()-1)) && point.getX()>=0 && count<6) {
        count ++;
      }
      point.setX(x);
      while (!enemyPoints.contains(point.setX(point.getX()+1)) && point.getX()<maxX && count<6) {
        count ++;
      }
      break;
    //纵向
    case ZHONG:
      while (!enemyPoints.contains(point.setY(point.getY()-1)) && point.getY()>=0) {
        count ++;
      }
      point.setY(y);
      while (!enemyPoints.contains(point.setY(point.getY()+1)) && point.getY()<maxY && count<6) {
        count ++;
      }
      break;
    //正斜向 /
    case ZHENG_XIE:
      while (!enemyPoints.contains(point.setX(point.getX()-1).setY(point.getY()+1)) && point.getX()>=0 && point.getY()<maxY) {
        count ++;
      }
      point.setX(x).setY(y);
      while (!enemyPoints.contains(point.setX(point.getX()+1).setY(point.getY()-1)) && point.getX()<maxX && point.getY()>=0 && count<6) {
        count ++;
      }
      break;
    //反斜 /
    case FAN_XIE:
      while (!enemyPoints.contains(point.setX(point.getX()-1).setY(point.getY()-1)) && point.getX()>=0 && point.getY()>=0) {
        count ++;
      }
      point.setX(x).setY(y);
      while (!enemyPoints.contains(point.setX(point.getX()+1).setY(point.getY()+1)) && point.getX()<maxX && point.getY()<maxY && count<6) {
        count ++;
      }
      break;
    }
    return count;
  } 

  //下棋子,对外接口
  @Override
  public void run(List<Point> humans,Point p) {
    //把人类下的最后一步棋子去除
    allFreePoints.remove(humans.get(humans.size()-1));
    //电脑可以下的一步棋子
    Point result = doAnalysis(myPoints, humans);
    //去除电脑下的棋子
    allFreePoints.remove(result);
    //加入到电脑棋子中,下棋了
    myPoints.add(result);
  }
} 

人类玩家实现起来就非常简单

import java.util.List; 

public class HumanPlayer extends BasePlayer { 

  @Override
  public void run(List<Point> enemyPoints,Point p) {
    getMyPoints().add(p);
    allFreePoints.remove(p);
  }
}

总结:虽然是Java写的但算法已被抽象可以方便的修改成各种平台的实现。

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

(0)

相关推荐

  • java实现单机版五子棋

    这个小游戏是我和我姐们儿的JAVA课程设计,也是我做的第一个JAVA项目,适合初学者,希望能帮到那些被JAVA课设所困扰的孩纸们~~~ 一.该游戏需要实现 1.设计主框架,界面. 2.利用ActionListener接口实现按钮事件的监听. 3.重新开始功能的实现. 4.悔棋功能的实现. 5.退出功能的实现. 6.棋盘中棋子点类的定义. 7.利用MouseListener接口实现事件监听,并实现接口里的所有方法. 8.当鼠标移动到棋盘上的交点上,且该点上无棋子时能够变成小手形状. 9.点击棋盘时

  • AI算法实现五子棋(java)

    本文实例为大家分享了AI算法实现五子棋的具体代码,供大家参考,具体内容如下 首先,实现一个五子棋要有一个棋盘,然后在这个棋盘上我们再来画出图画,五子棋棋盘有固定的行数和列数,再加上界面的大小和菜单栏,这些数据可能很多个类都需要用到,我们可以先考虑自己写一个接口用来存储这些数据: public interface Config { public static final int SIZE=703; //面板大小 public static final int X0=SIZE/19*2-8; pub

  • Java事件监听机制讲解

    给组件加上监听器 定义一个类,这个类继承ActionListener pubulic class ButListener implements ActionListener{ Public void actionPerformed(ActionEvent e){ }} 给按钮添加动作监听器方法 ButListener but = new ButListen(); jbu.addActionListener(but); 加上监听机制后再监听器ButListener时间处理方法中再创建窗口即可得到点

  • Java抽象类的概念讲解

    简单来说 抽象类通常用来作为一个类族的最顶端的父类,用最底层的类表示现实中的具体事物,用最顶层的类表示该类族所有事物的共性.用abstract关键字类修饰一个类,该类叫做抽象类. 有抽象类那么肯定也有抽象方法,什么是抽象方法呢? 抽象方法就是有名字,形参列表,返回值,没有方法体的方法就做抽象方法. 抽象方法和抽象类的关系? 凡是没有方法体的方法必须使用关键字abstract修饰为抽象方法. 凡是含有抽象方法的类必须声明为抽象类. abstract class A{ abstract public

  • Javascript迭代、递推、穷举、递归常用算法实例讲解

    累加和累积 累加:将一系列的数据加到一个变量里面.最后的得到累加的结果 比如:将1到100的数求累加和 小球从高处落下,每次返回到原来一半,求第十次小球落地时小球走过的路程 <script> var h=100; var s=0; for(var i=0;i<10;i++){ h=h/2; s+=h; } s=s*2+100; </script> 累积:将一系列的数据乘积到一个变量里面,得到累积的结果. 常见的就是n的阶乘 var n=100; var result= 1;

  • Java五子棋AI实现代码

    思路: ①五子棋界面的实现 ②交互下棋的实现 ③重绘 ④AI,实现人机对战 五子棋和简单AI的实现: 首先将五子棋的界面写出来. 首先我们写一个接口类,定义好棋盘的数据(目的是方便修改). public interface Config { public static final int X0=50;//左上角起点X值 public static final int Y0=50;//左上角起点Y值 public static final int ROWS=15;//横向线数 public sta

  • Java实现五子棋网络版

    本文实例为大家分享了Java实现五子棋网络版的具体代码,供大家参考,具体内容如下 需求分析: 对于网络五子棋而言,在普通五子棋的基础上需要添加以下功能: 1.拥有服务器端和客户端,用户通过客户端登录服务器后可与其他登录的用户进行对弈 2.服务器支持多组用户同时进行对弈 3.用户可以在服务器上创建新游戏或加入已创建的游戏 4.用户在下棋的时候可以进行聊天交流 由上可以知道需要实现的功能: ·提供服务器和客户端的功能 ·服务器将监听客户端的登录情况并允许多个客户端进行登录 ·用户通过客户端可以登录服

  • Java版AI五子棋游戏

    本文实例为大家分享了java五子棋游戏的具体代码,供大家参考,具体内容如下 AI思路:通过判断棋盘上每个空位的分数,去分数最高的几个点,随机下棋 分数计算思路:能成5个说明能赢了,给最高分 不能成5个,对方能成5个,说明对方要赢了,给第二高分 能成活4,给第三高分 能成活3,给第四高分 能成冲4,给第五高分 能成冲3,给第六高分 能成活2,给第七高分 能成冲2,给第八高分 其他,给最低分 分数设定可自己定义. 因为是去年写的了,思路记得大概就是这样.最近根据书上写了个棋类游戏的设计框架,待完善后

  • Java压缩之LZW算法字典压缩与解压讲解

    压缩过程: 前面已经写过一篇哈夫曼压缩,LZW字典压缩与哈夫曼压缩的不同之处在于不需要把编码写入文件,编码表是在读文件中生成的,首先将0-255个ASCLL码与对应的数字存入哈希表中,作为基础码表. 这里的后缀为当前 前缀+后缀 如果在码表中存在,前缀等于前缀+后缀.如果不存在,将前缀+后缀所表示的字符串写入编码表编码,同时将前缀写入压缩文件中.这里重点注意一下,一个字节所能表示的数字范围为0-255,所以我们将一个字符的编码变成两个字节写进去,分别写入它的高八位和低八位,比如256即为0000

  • JavaTCP上传图片代码实例

    1.客户端代码 public class UploadPicClient { public static void main(String[] args) throws UnknownHostException, IOException { // TODO Auto-generated method stub //1,创建客户端socket Socket s = new Socket("localhost",10088); //2,读取客户端要上传的图片文件 FileInputStre

随机推荐