2014-12-05 52 views
-1

我製作了一個機器人迷宮,機器人在沒有撞到牆壁的情況下自動達到目標。我希望機器人一次做迷宮,學習正確的路線,然後第二次能夠直接到達那裏,而不需要任何死刑。我想我可以通過製作三個陣列列表來做到這一點。
一個用於機器人訪問的所有廣場。 兩個爲所有導致死衚衕的正方形。 三個適用於機器人的所有方向。匹配和刪除arraylists中的元素

如果在第一個數組列表中找到導致死衚衕的正方形,那麼我可以刪除第三個數組列表中的相同索引。這樣,第二次,我可以迭代第三名Arraylist。

我的全代碼如下:

import java.util.ArrayList; 
import java.util.*; 
import java.util.Iterator; 
import java.util.stream.IntStream; 

public class Explorer { 

    private int pollRun = 0; // Incremented after each pass. 
    private RobotData robotData; // Data store for junctions. 
    private ArrayList<Integer> nonWallDirections; 
    private ArrayList<Integer> passageDirections; 
    private ArrayList<Integer> beenbeforeDirections; 
    private Random random = new Random(); 
    int [] directions = {IRobot.AHEAD, IRobot.LEFT, IRobot.RIGHT, IRobot.BEHIND}; 
    private ArrayList<Square> correctSquares; 
    private ArrayList<Square> wrongSquares; 
    private ArrayList<Integer> correctDirections; 

    public void controlRobot (IRobot robot) { 

     // On the first move of the first run of a new maze. 
     if ((robot.getRuns() == 0) && (pollRun ==0)) 
      robotData = new RobotData(); 
     pollRun++; /* Increment poll run so that the data is not reset 
         each time the robot moves. */ 


     int exits = nonwallExits(robot); 
     int direction; 

     if ((robot.getRuns() != 0)) 
      direction = grandfinale(robot); 

     nonWallDirections = new ArrayList<Integer>(); 
     passageDirections = new ArrayList<Integer>(); 
     beenbeforeDirections = new ArrayList<Integer>(); 
     correctSquares = new ArrayList<Square>(); 
     correctDirections = new ArrayList<Integer>(); 

      // Adding each direction to the appropriate state ArrayList. 
      for(int item : directions) { 
       if(robot.look(item) != IRobot.WALL) { 
        nonWallDirections.add(item); 
       } 
      } 

      for(int item : directions) { 
       if(robot.look(item) == IRobot.PASSAGE) { 
        passageDirections.add(item); 
       } 
      } 

      for(int item : directions) { 
       if(robot.look(item) == IRobot.BEENBEFORE) { 
        beenbeforeDirections.add(item); 
       } 
      } 

     // Calling the appropriate method depending on the number of exits. 
     if (exits < 2) { 
      direction = deadEnd(robot); 
     } else if (exits == 2) { 
      direction = corridor(robot); 
     } else { 
      direction = junction(robot); 
      robotData.addJunction(robot); 
      robotData.printJunction(robot); 
     } 

     robot.face(direction); 
     addcorrectSquares(robot); 
     correctDirections.add(direction); 

    } 


    /* The specification advised to have to seperate controls: Explorer and Backtrack 
     and a variable explorerMode to switch between them. 
     Instead, whenever needed I shall call this backtrack method. 
     If at a junction, the robot will head back the junction as to when it first approached it. 
     When at a deadend or corridor, it will follow the beenbefore squares until it 
     reaches an unexplored path. */ 
    public int backtrack (IRobot robot) { 

     if (nonwallExits(robot) > 2) { 
      addwrongSquares(robot); 
      return robotData.reverseHeading(robot); 
     } else { 
       do { 
        addwrongSquares(robot); 
        return nonWallDirections.get(0); 
       } while (nonwallExits(robot) == 1); 
     } 



    } 


    // Deadend method makes the robot follow the only nonwall exit. 
    public int deadEnd (IRobot robot) { 

     return backtrack(robot); 

    } 


    /* Corridor method will make the robot follow the one and only passage. 
     The exception is at the start. Sometimes, the robot will start with 
     two passages available to it in which case it will choose one randomly. 
     If there is no passage, it will follow the beenbefore squares 
     until it reaches an unexplored path.*/ 
    public int corridor (IRobot robot) { 

     if (passageExits(robot) == 1) { 
      return passageDirections.get(0); 
     } else if (passageExits(robot) == 2) { 
      int randomPassage = random.nextInt(passageDirections.size()); 
      return passageDirections.get(randomPassage); 
     } else { 
       return backtrack(robot); 
     } 
    } 


    /* Junction method states if there is more than one passage, it will randomly select one. 
     This applies to crossroads as well as essentially they are the same. 
     If there is no passage, it will follow the beenbefore squares until it reaches an unexplored 
     path. */ 
    public int junction(IRobot robot) { 

     if (passageExits(robot) == 1) { 
      return passageDirections.get(0); 
     } else if (passageExits(robot) > 1) { 
      int randomPassage = random.nextInt(passageDirections.size()); 
      return passageDirections.get(randomPassage); 
     } else { 
      return backtrack(robot); 
     } 

    } 


    // Calculates number of exits. 
    private int nonwallExits (IRobot robot) { 

     int nonwallExits = 0; 

     for(int item : directions) { 
      if(robot.look(item) != IRobot.WALL) { 
       nonwallExits++; 
      } 
     } 

     return nonwallExits; 
    } 


    // Calculates number of passages. 
    private int passageExits (IRobot robot) { 

     int passageExits = 0; 

     for(int item : directions) { 
      if(robot.look(item) == IRobot.PASSAGE) { 
       passageExits++; 
      } 
     } 

     return passageExits; 
    } 


    // Calculates number of beenbefores. 
    private int beenbeforeExits (IRobot robot) { 

     int beenbeforeExits = 0; 

     for(int item : directions) { 
      if(robot.look(item) == IRobot.PASSAGE) { 
       beenbeforeExits++; 
      } 
     } 

     return beenbeforeExits; 
    } 

    // Resets Junction Counter in RobotData class. 
    public int reset() { 

     return robotData.resetJunctionCounter(); 

    } 


    public void addcorrectSquares(IRobot robot) { 

     Square newSquare = new Square(robot.getLocation().x, robot.getLocation().y); 
     correctSquares.add(newSquare); 

    } 


    public void addwrongSquares(IRobot robot) { 

     Square badSquare = new Square(robot.getLocation().x, robot.getLocation().y); 
     wrongSquares.add(badSquare); 

    } 


    public int grandfinale (IRobot robot) { 

     IntStream.range(0, correctSquares.size()) 
      .map(index -> correctSquares.size() - index - 1) 
      .filter(index -> (((wrongSquares.x).contains(correctSquares.x)) && ((wrongSquares.y).contains(correctSquares.y))).get(index)) 
      .forEach(index -> correctDirections.remove(index)); 

     Iterator<Integer> routeIterator = correctDirections.iterator(); 
     while (routeIterator.hasNext()) { 
      break; 
     } 

     return (routeIterator.next()); 
    } 
} 

class RobotData { 

    /* It was advised in the specification to include the variable: 
     private static int maxJunctions = 10000; 
     However, as I am not using arrays, but ArrayLists, I do not 
     need this. */ 
    private static int junctionCounter = 0; 
    private ArrayList<Junction> junctionList = new ArrayList<Junction>(); 

    // Resets the Junction counter. 
    public int resetJunctionCounter() { 

     return junctionCounter = 0; 

    } 


    // Adds the current junction to the list of arrays. 
    public void addJunction(IRobot robot) { 

     Junction newJunction = new Junction(robot.getLocation().x, robot.getLocation().y, robot.getHeading()); 
     junctionList.add(newJunction); 
     junctionCounter++; 

    } 


    // Gets the junction counter for Junction info method in Junction class. 
    public int getJunctionCounter (IRobot robot) { 

     return junctionCounter; 
    } 


    // Prints Junction info. 
    public void printJunction(IRobot robot) { 

     String course = ""; 
     switch (robot.getHeading()) { 
      case IRobot.NORTH: 
       course = "NORTH"; 
       break; 
      case IRobot.EAST: 
       course = "EAST"; 
       break; 
      case IRobot.SOUTH: 
       course = "SOUTH"; 
       break; 
      case IRobot.WEST: 
       course = "WEST"; 
       break; 
     } 

     System.out.println("Junction " + junctionCounter + " (x=" + robot.getLocation().x + ", y=" + robot.getLocation().y +") heading " + course); 

    } 

    /* Iterates through the junction arrayList to find the 
     heading of the robot when it first approached the junction. 
     It does this by finding the first junction in the ArrayList 
     that has the same x and y coordinates as the robot.*/ 
    public int searchJunction(IRobot robot) { 

    Junction currentJunction = null; 

    Iterator<Junction> junctionIterator = junctionList.iterator(); 
    while (junctionIterator.hasNext()) { 
     currentJunction = junctionIterator.next(); 
     if ((((currentJunction.x)==(robot.getLocation().x))) && ((currentJunction.y)==(robot.getLocation().y))) 
      break; 
    } 

    return currentJunction.arrived; 
} 


    // Returns the reverse of the heading the robot had when first approaching the junction. 
    public int reverseHeading(IRobot robot) { 

     int firstHeading = searchJunction(robot); 
     int reverseHeading = 1; // Random integer to Iniitalise variable. 

     switch (firstHeading) { 
        case IRobot.NORTH: 
         if (robot.getHeading() == IRobot.NORTH) 
          reverseHeading = IRobot.BEHIND; 
         else if (robot.getHeading() == IRobot.EAST) 
          reverseHeading = IRobot.RIGHT; 
         else if (robot.getHeading() == IRobot.SOUTH) 
          reverseHeading = IRobot.AHEAD; 
         else 
          reverseHeading = IRobot.LEFT; 
        break; 

        case IRobot.EAST: 
         if (robot.getHeading() == IRobot.NORTH) 
          reverseHeading = IRobot.LEFT; 
         else if (robot.getHeading() == IRobot.EAST) 
          reverseHeading = IRobot.BEHIND; 
         else if (robot.getHeading() == IRobot.SOUTH) 
          reverseHeading = IRobot.RIGHT; 
         else 
          reverseHeading = IRobot.AHEAD; 
        break; 

        case IRobot.SOUTH: 
         if (robot.getHeading() == IRobot.NORTH) 
          reverseHeading = IRobot.AHEAD; 
         else if (robot.getHeading() == IRobot.EAST) 
          reverseHeading = IRobot.LEFT; 
         else if (robot.getHeading() == IRobot.SOUTH) 
          reverseHeading = IRobot.BEHIND; 
         else 
          reverseHeading = IRobot.RIGHT; 
        break; 

        case IRobot.WEST: 
         if (robot.getHeading() == IRobot.NORTH) 
          reverseHeading = IRobot.RIGHT; 
         else if (robot.getHeading() == IRobot.EAST) 
          reverseHeading = IRobot.AHEAD; 
         else if (robot.getHeading() == IRobot.SOUTH) 
          reverseHeading = IRobot.LEFT; 
         else 
          reverseHeading = IRobot.BEHIND; 
        break; 
       } 

     return reverseHeading; 

    } 

} 


class Junction { 

    int x; 
    int y; 
    int arrived; 

    public Junction(int xcoord, int ycoord, int course) { 

     x = xcoord; 
     y = ycoord; 
     arrived = course; 

    } 

} 


class Square { 

    int x; 
    int y; 

    public Square(int cordx, int cordy){ 

     x = cordx; 
     y = cordy; 

    } 
} 
+0

你有什麼事嗎?請提供您的代碼。 – 2014-12-05 04:58:12

回答

1
IntStream.range(0, al1.length) 
    .filter(index -> al2.contains(al1.get(index))) 
    .forEach(index -> al3.remove(index)); 

稍微複雜一些比這如果去除AL3元素轉變他們離開,但在這種情況下,前.filter-只是反向流,然後它會刪除從最後。要做到這一點,最簡單的方法是:

.map(index -> al1.length - index - 1) 

沒有流相當於將

for (int i = 0; i < al1.length; i++) { 
    if (al2.contains(al1.get(i))) { 
     al3.remove(i); 
    } 
} 

同樣,如果您需要正確的刪除,然後for循環需要倒計時而不是向上。

沒有關於arraylist結構的進一步細節,很難提供更多的提示。

+0

它說它無法找到Instream的符號? – codeav3 2014-12-05 04:59:23

+0

我覺得他沒有使用java8 – 2014-12-05 04:59:47

+0

對不起,應該是IntStream - 我在我的回答中改變了它 – sprinter 2014-12-05 05:01:14