Package de.axxeed.animosy.ai

Source Code of de.axxeed.animosy.ai.VirtualBoard

/**
* Defines the board for the game
*
* @author Shashi Mittal
* @version 1.5(08-09-2002)
*/
package de.axxeed.animosy.ai;
import java.io.*;
import java.util.*;
import java.awt.*;
import javax.swing.*;

import org.apache.log4j.Logger;

import de.axxeed.animosy.model.BoardModel;
import de.axxeed.animosy.model.Constants;
import de.axxeed.animosy.model.Detective;
import de.axxeed.animosy.model.Fugitive;
import de.axxeed.animosy.model.Game;
import de.axxeed.animosy.model.GameBoard;
import de.axxeed.animosy.model.Link;
import de.axxeed.animosy.model.Manager;
import de.axxeed.animosy.model.Move;
import de.axxeed.animosy.model.Node;

public class VirtualBoard implements Comparator,Comparable, Constants
{
  private static Logger log = Logger.getLogger(VirtualBoard.class);

  static private final int INF=100;
    static private int DEPTH=3;
    static private final int WIN=200;
    static private final int LOSE=-200;
    static private final int NBEST=25;
    static private Point pos[] = null;

    private int alphabeta[];
    private int currentMoves;
    private static int [][]shortestDistance = null;
    private int [] checkPoints;
    private Detective []detectives;
    private Fugitive MrX;

    /**This constructor initializes the board
     */
    public VirtualBoard(GameBoard board)
    {
      int nrOfcheckPoints = 5;
      int nrOfDetectives = Manager.getOptions().getNumberOfDetectives();
        currentMoves=0;
        checkPoints=new int[nrOfcheckPoints];
        for(int i=0;i<nrOfcheckPoints;i++)
          checkPoints[i]=3+(3+Manager.getOptions().getLevel())*i;
        detectives=new Detective[nrOfDetectives];
      for(int i=0;i<nrOfDetectives;i++)
      {
          detectives[i]=new Detective(board.getDetectives()[i].getPosition());
      }
        MrX=new Fugitive(board.getMrX().getPosition());
        int noOfNodes = BoardModel.nodesCount();
        if(shortestDistance == null) {
            shortestDistance=new int[noOfNodes][noOfNodes];
            for(int i=0;i<noOfNodes;i++)
                for(int j=0;j<noOfNodes;j++)
                    shortestDistance[i][j]=weight(BoardModel.getNode(i),BoardModel.getNode(j));
            shortestDistance=getShortestDistanceMatrix(shortestDistance,1);
            // test();
        }
      alphabeta=new int[DEPTH+1];
    }


    /**This constructor make a copy of the VirtualBoard board
     *@param board the VirtualBoard whose copy has to be made
     */
    private VirtualBoard(VirtualBoard board)
    {
//      log.debug("New virtual board ("+hashCode()+") with "+board.detectives.length+" detectives...");
  this.currentMoves=board.currentMoves;
        this.checkPoints=board.checkPoints;
        detectives=new Detective[board.detectives.length];
        for(int i=0;i<detectives.length;i++)
      {
    Node n=board.detectives[i].getPosition();
    if(n==null) {
      log.warn("No position node found for detective "+i);
    }
    detectives[i]=new Detective(n);
      }
        Node n=board.MrX.getPosition();
        MrX=new Fugitive(n);
    }

    /**This method changes the difficulty level for the game
      *@param d the required dificulty level
      */
    public void setDepth(int d)
    {
  DEPTH=d;
    }

    /**This method returns the distance between the two nodes
     * @param x,y the two nodes given
     * @return 0 if x and y are the same nodes
     * 100 if they are not adjacent nodes
     * weight of the link if the two nodes are connected
     */
    private int weight(Node x,Node y)
    {
        if(x.equals(y)) return 0;
        int weight=INF;
        {
            Link []lk=x.getLinks();
            for(int i=0;i<lk.length;i++)
    {
        Node n=lk[i].getToNode();
        if(n.equals(y)) weight=lk[i].getType();
    }
        }
        return weight;
    }

    /**This method evaluates the shortest distance between all the possible nodes
     * It uses Floyd Warshalls Algorithm
     */
    private int[][] getShortestDistanceMatrix(int [][]mat,int k)
    {
      int noOfNodes = BoardModel.nodesCount();
        if (k==noOfNodes-1) return mat;
        int newMat[][]=new int[noOfNodes][noOfNodes];
        {
            for(int i=0;i<noOfNodes;i++)
                for(int j=0;j<noOfNodes;j++) {
                    newMat[i][j]=Math.min(mat[i][j],mat[i][k]+mat[k][j]);
                }
        }
        k=k+1;
        return getShortestDistanceMatrix(newMat,k);
    }

    /**Prints the initial matrix
     */
    public void test()
    {
      int noOfNodes = BoardModel.nodesCount();
        for(int i=0;i<noOfNodes;i++) {
          StringBuilder buffer = new StringBuilder();
          buffer.append("Node"+i).append(";");
            for(int j=0;j<noOfNodes;j++) {
              buffer.append(shortestDistance[i][j]).append(";");
            }
            System.out.println(buffer);
        }
    }

    /**Display the map*/
    public void displayMap()
    {
        JFrame frame=new JFrame();
  ImageIcon map=new ImageIcon("map.jpg");
  JLabel label=new JLabel(map);
  frame.getContentPane().add(label);
  frame.show();
    }

    /**Checks if the move to node n is legal or not
     *@param n the node n to be tested
     *@return true if the move is legal otherwise it returns false
     */
    private boolean isLegalMove(Node to)
    {
        boolean canMove=true;
        for(int i=0;i<detectives.length;i++)
      {
    Node n=detectives[i].getPosition();
    if(n.getPosition()==to.getPosition()) canMove=false;
      }
        return canMove;
    }

    /**This method returns all the possible moves for a given detective
      *@param i the detective index of the detective whose possible moves we want
      *@return the possible moves of this detective in a TreeSet
      */     
    public TreeSet getDetectivePossibleMoves(int i)
    {
  if(!canMove(this, i))
  {
    detectives[i].setStaticState();
    throw new IllegalArgumentException();
  }
  return getPossibleMoves(this, i);
    }

    /**This methos is used to change the position of a detective
      *@param i the index of the detective whose position we want to change
      *@param move the new move for this detective
      */   
    public void changeDetectivePosition(int i,Move move)
    {
  detectives[i].changePosition(BoardModel.getNode(move.getNode()),move.getType());
    }

    /**Checks whether the machine has won
     * @return true if machine has won,otherwise false
     */
    public boolean isMachineWin()
    {
        boolean noneCanMove=true;
        for(int i=0;i<Manager.getOptions().getNumberOfDetectives();i++)
            if(canMove(this, i)) noneCanMove=false;
        return((currentMoves==Manager.getOptions().getNumberOfMoves())||noneCanMove);
    }

    /**Checks if the user has won
     * @return true if the user has won,otherwise false
     */
    public  boolean isUserWin()
    {
  Link []xLinks=MrX.getPosition().getLinks();
  boolean isBlocked=true;
  for(int i=0;i<xLinks.length;i++)
      {
    Node xNode=xLinks[i].getToNode();
    boolean thisIsOccupied=false;
    for(int j=0;j<Manager.getOptions().getNumberOfDetectives();j++)
        {
      Node dNode=detectives[j].getPosition();
      if(dNode.equals(xNode)) thisIsOccupied=true;
        }
    if(!thisIsOccupied) isBlocked=false;
      }
  boolean isCaptured=false;
  for(int i=0;i<Manager.getOptions().getNumberOfDetectives();i++)
      {
    Node detNode=detectives[i].getPosition();
    if(detNode.equals(MrX.getPosition())) isCaptured=true;
      }
  return(isBlocked||isCaptured);
    }

    /**This is the most important method of this class
     * It returns the best possible move by calling the evaluate() method
     * @return the best node posiion of  MrX
     */
    private Node bestMove()
    {
  Node n=MrX.getPosition();
  Link[] lk=n.getLinks();
  int score[]=new int[20];  
  Node possibleNodes[]=new Node[20];
  int legalMoves=0;
  int noOfNodes=lk.length;
  for(int i=0;i<lk.length;i++)
      {
    if(isLegalMove(lk[i].getToNode()))
        {
      VirtualBoard board=new VirtualBoard(this);
      board.MrX.change(lk[i].getToNode());
      possibleNodes[legalMoves]=lk[i].getToNode();
      score[legalMoves]=evaluateMove(board,false,0);
      legalMoves++;
        }
      }
  Node toNode=possibleNodes[0];
  int max=score[0];
  for(int i=0;i<legalMoves;i++)
      {
    if(max<score[i])
        {
      toNode=possibleNodes[i];
      max=score[i];
        }
      }
  return toNode;
    }

    /**This method evaluates the position of the Node using depth first shallow search algorithm
     *@param b the initial VirtualBoard passed by the user
     *@param depth the current depth of the recursion tree
     *@param isMachineMove true if the next move is of the machine,else returns false
     */
    private int evaluateMove(VirtualBoard b,boolean isMachineMove,int depth)
    {
        VirtualBoard board=new VirtualBoard(b);
        if(isMachineMove)
      {
    Node dPos=board.MrX.getPosition();
    Link []lk=dPos.getLinks();
    int score[]=new int[lk.length];
    int legalMoves=0;
    for(int i=0;i<lk.length;i++)
        {
      Node newPos=lk[i].getToNode();
      if (!board.isLegalMove(newPos)) continue;
      board.MrX.change(newPos);
      if(board.isUserWin()) score[legalMoves]=LOSE;
      else if(board.isUserWin()) score[legalMoves]=WIN;
      else if(depth==DEPTH) score[legalMoves]=scoreBoard(board);
      else score[legalMoves]=evaluateMove(board,false,depth+1);
      if(i==0) alphabeta[depth]=score[legalMoves];
      if(score[legalMoves]>alphabeta[depth]) alphabeta[depth]=score[legalMoves];
      if((depth>0)&&(score[legalMoves]>alphabeta[depth-1]))
                            return score[legalMoves];         
      legalMoves++;
        }
    int max=score[0];
    for(int i=0;i<legalMoves;i++)
        if(score[i]>max) max=score[i];
    return max;
      }
        else
      {
    int score[]=new int[NBEST];
    int legalMoves=0;
    TreeSet possibleMoves=generateUserMoves(board);
    for(int i=0;(i<NBEST)&&(!possibleMoves.isEmpty());i++)
        {
      board=(VirtualBoard)possibleMoves.first();
            if(board.isUserWin()) score[legalMoves]=LOSE;
          else if(board.isMachineWin()) score[legalMoves]=WIN;
        else if(depth==DEPTH) score[legalMoves]=scoreBoard(board);
            else score[legalMoves]=evaluateMove(board,true,depth+1);
      possibleMoves.remove(board);
     
         if(legalMoves==0) alphabeta[depth]=score[legalMoves];
      if(score[legalMoves]<alphabeta[depth]) alphabeta[depth]=score[legalMoves];
          if((depth>0)&&(score[legalMoves]<alphabeta[depth-1]))
          return score[legalMoves];
      legalMoves++;
            }
    int min=score[0];
    for(int i=0;i<legalMoves;i++)
        if(score[i]<min) min=score[i];
    return min;
      }
    }

    /**This method generates all the possible user moves for the given board.The generated
     *possible moves are stored in a TreeSet and only the first n(ie the n-best boards ) are
     *used for continuing the minimax tree.Thus this is done for the forward prunning   
     *of the branch.
     *@param b the board for which the moves have to be generated
     *@return all possible board positions in a TreeSet
     */
    private TreeSet generateUserMoves(VirtualBoard b) {
     TreeSet possibleMoves=new TreeSet();
     int nrOfDetectives = Manager.getOptions().getNumberOfDetectives();
    Node n[]=new Node[nrOfDetectives];
    Node detNode[]=new Node[nrOfDetectives];
    for(int i=0;i<nrOfDetectives;i++)
        detNode[i]=b.detectives[i].getPosition();

    for(int detLnk=0;detLnk<detNode[0].getLinks().length;detLnk++) {
      VirtualBoard board=new VirtualBoard(b);
      Link []lnk=detNode[0].getLinks();
      if(!canMove(board, 0)) {
        n[0]=detNode[0];
      }
      else if(!board.isLegalMove(lnk[detLnk].getToNode())) {
        continue;
      }
      else {
        n[0]=lnk[detLnk].getToNode();
      }
      generateDetectiveMove(1, possibleMoves, n, detNode, board);
    }
     
  // This is the old version
/*
  for(int d1=0;d1<detNode[0].getLinks().length;d1++)
      {
    board=new VirtualBoard(b);
    Link []l1=detNode[0].getLinks();
    if(!canMove(board, 0)) n[0]=detNode[0];
    else if(!board.isLegalMove(l1[d1].getToNode())) continue;
    else n[0]=l1[d1].getToNode();
    for(int d2=0;d2<detNode[1].getLinks().length;d2++)
        {
      Link []l2=detNode[1].getLinks();
      n[1]=l2[d2].getToNode();
      if(!canMove(board, 1)) n[1]=detNode[1];
      else if(!board.isLegalMove(l2[d2].getToNode())) continue;

      for(int d3=0;d3<detNode[2].getLinks().length;d3++)
          {
        Link []l3=detNode[2].getLinks();
        n[2]=l3[d3].getToNode();
        if(!canMove(board, 2)) n[2]=detNode[2];
        else if(!board.isLegalMove(l3[d3].getToNode())) continue;

        for(int d4=0;d4<detNode[3].getLinks().length;d4++)
            {
          Link []l4=detNode[3].getLinks();
          n[3]=l4[d4].getToNode();
          if(!canMove(board, 3)) n[3]=detNode[3];
          else if(!board.isLegalMove(l3[d3].getToNode())) continue;

          for(int d5=0;d5<detNode[4].getLinks().length;d5++)
              {
            Link []l5=detNode[4].getLinks();
            n[4]=l5[d5].getToNode();
            if(!canMove(board, 4)) n[4]=detNode[4];
            else if(!board.isLegalMove(l5[d5].getToNode())) continue;

            for(int count=0;count<nrOfDetectives;count++)
                board.detectives[count].change(n[count]);
            possibleMoves.add((Object)board);
              }
            }
          }
        }
      }
*/
  return possibleMoves;
    }

    private void generateDetectiveMove(int detNr, TreeSet possibleMoves, Node[] n, Node[] detNode, VirtualBoard board) {
       int nrOfDetectives = Manager.getOptions().getNumberOfDetectives();
    for(int det=0;det<detNode[detNr].getLinks().length;det++) {
      Link []lnk=detNode[detNr].getLinks();
      n[detNr]=lnk[det].getToNode();

      if(!canMove(board, detNr)) n[detNr]=detNode[detNr];
      else if(!board.isLegalMove(lnk[det].getToNode())) continue;
 
      if(detNr==nrOfDetectives-1) {
        for(int count=0;count<nrOfDetectives;count++)
            board.detectives[count].change(n[count]);
        possibleMoves.add((Object)board);
      }
      else {
        generateDetectiveMove(detNr+1, possibleMoves, n, detNode, board);
      }
      }
    }
   
    /**This method evaluates the given board
     *@param board the given board
     *@return the score for this board
     */
    private static int scoreBoard(VirtualBoard board)
    {
  Detective []detectives=board.detectives;
  Fugitive mrx=board.MrX;
  int totalDistance=0;
  int totalMobility=0;
  for(int count=0;count<Manager.getOptions().getNumberOfDetectives();count++)
      {
    totalDistance+=shortestDistance[detectives[count].getPosition().getPosition()][mrx.getPosition().getPosition()];
    totalMobility+=detectives[count].mobility();
      }
  int score=3*totalDistance-totalMobility/5;
  return score;
    }

    /**This method compares two objects of this class depending on the score of the boards
     *@param b1,b2 the two boards which are to be compared
     *@return negative if score of b1 less then score of b2
     *positive otherwise
     */
    public int compare(Object b1,Object b2)
    {
  int s1=scoreBoard((VirtualBoard)b1);
  int s2=scoreBoard((VirtualBoard)b2);
  if(s1<s2) return -1;
        else return 1
    }

    /**This method checks whether two boards are equal
     *@param b1.b2 the two boards
     *@return true if the boards are equal,false otherwise
     */
    public boolean equal(VirtualBoard b1,VirtualBoard b2)
    {
  return (scoreBoard(b1)==scoreBoard(b2));
    }

    /**This method comapres this board to another board o
     *@param o the board with which this is to be compared
     *@return similar to the compare() method
     */
    public int compareTo(Object o)
    {
  VirtualBoard b=(VirtualBoard)o;
  return compare(this,b);
    }

    public Move moveMrX()
    {
  Node bestNode=bestMove();
  int type=MrX.changePosition(bestNode);
  int pos=MrX.getPosition().getPosition();
  currentMoves++;
  return (new Move(pos,type));
    }

    /**This method is used to get the detectives of this board
     *@return the array containing the detectives of the current game
     */
    public Detective[] getDetectives()
    {
  return detectives;
    }

    /**This method is used to get the MrX of this object
     *@return the MrX of this object
     */
    public Fugitive getMrX()
    {
  return MrX;
    }

    /**This methos returns the currentMoves of this object
      *@return the currentMoves of this object
      */
    public int getCurrentMoves()
    {
  return currentMoves;
    }

    /**String representation of this board
      *@return the score of this board in String form
      */
    public String toString()
    {
  return ""+scoreBoard(this);
    }
   
    public static Point getPos(int i) {
      return pos[i];
    }
   
    /**Checks if the detective can make a move or not
     * @return true if the detective can move,false if the detective is stranded
     */
    private boolean canMove(VirtualBoard board, int detNo)
    {
        Node n=board.getDetectives()[detNo].getPosition();
        // log.debug("Detective #"+detNo+", Node: "+n+" on board ("+board.hashCode()+")");
        Link []lk=n.getLinks();
        boolean canMove=false;
        for(int i=0;i<lk.length;i++)
        {
      boolean canGoToThisNode=true;
      Node toNode=lk[i].getToNode();
      Detective[] det=Manager.getGame().getBoard().getDetectives();
      for(int j=0;j<det.length;j++)
    if (toNode.equals(det[j].getPosition())) canGoToThisNode=false;

            int t=lk[i].getType();
            switch(t)
            {
                case TAXI:if(getDetectives()[detNo].getTaxiTickets()<=0) if(canGoToThisNode) canGoToThisNode=false;
                           break;
                case  BUS:if(getDetectives()[detNo].getBusTickets()<=0) if(canGoToThisNode) canGoToThisNode=false;
                            break;
                case   UG:if(getDetectives()[detNo].getUndergroundTickets()<=0) if(canGoToThisNode) canGoToThisNode=false;
                      break;
                case   BLACK:canGoToThisNode=false;
                      break;
            }
      if(canGoToThisNode) canMove=true;
        }
        return canMove;
    }

    /**This method returns the possible moves of the detective in a TreeSet
     * @param board the board of which this detective is a part of
     * @return all the possible moves in TreeSet
     */
    private TreeSet getPossibleMoves(VirtualBoard board, int detNo)
    {
  if(!canMove(board, detNo)) return null;
  boolean added=false;
  Node n=board.getDetectives()[detNo].getPosition();
  Link []lk=n.getLinks();
      TreeSet possibleMoves=new TreeSet();
  for(int i=0;i<lk.length;i++)
  {
      boolean canGoToThisNode=true;
      Node toNode=lk[i].getToNode();
      Detective[] det=Manager.getGame().getBoard().getDetectives();
      for(int j=0;j<det.length;j++)
    if(toNode.equals(det[j].getPosition())) canGoToThisNode=false;

      int t=lk[i].getType();
        switch(t)
        {
            case  TAXI:if(getDetectives()[detNo].getTaxiTickets()<=0) if(canGoToThisNode) canGoToThisNode=false;
                       break;
            case   BUS:if(getDetectives()[detNo].getBusTickets()<=0) if(canGoToThisNode) canGoToThisNode=false;
                        break;
            case    UG:if(getDetectives()[detNo].getUndergroundTickets()<=0) if(canGoToThisNode) canGoToThisNode=false;
                  break;
            case BLACK:canGoToThisNode=false;
                  break;
        }
      if(canGoToThisNodepossibleMoves.add(new Move(toNode.getPosition(),t));
  }
  return possibleMoves;
    }

}
TOP

Related Classes of de.axxeed.animosy.ai.VirtualBoard

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.