2014-12-05 67 views
0

我正在研究机器人迷宫,其中机器人发现目标而没有撞到墙上。作为一种“回溯”方法,我需要机器人以与刚刚遇到交叉路口时相反的方向行进。这是我的代码:java.lang.reflect.InvocationTargetException错误

import uk.ac.warwick.dcs.maze.logic.IRobot; 
import java.util.ArrayList; 
import java.util.*; 
import java.util.Iterator; 

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}; 

    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; 

     nonWallDirections = new ArrayList<Integer>(); 
     passageDirections = new ArrayList<Integer>(); 
     beenbeforeDirections = 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); 
    } 


    /* 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) { 
      return robotData.reverseHeading(robot); 
     } else { 
       do { 
        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(); 

    } 
} 

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>(); 
    private Iterator<Junction> junctionIterator = junctionList.iterator(); 

    // 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. */ 
    public int searchJunction(IRobot robot) { 

     Junction currentJunction = junctionIterator.next(); 
     while (junctionIterator.hasNext()) { 
      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; 

    } 

} 

每当它是回溯并达到它已经访问过一个路口,冻结这来了。

`java.lang.reflect.InvocationTargetException 
    at sun.reflect.GeneratedMethodAccessor41.invoke(Unknown Source) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:483) 
    at uk.ac.warwick.dcs.maze.controllers.PolledControllerWrapper.start(PolledControllerWrapper.java:70) 
    at uk.ac.warwick.dcs.maze.logic.ControllerThread.run(ControllerThread.java:46) 
Caused by: java.util.ConcurrentModificationException 
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901) 
    at java.util.ArrayList$Itr.next(ArrayList.java:851) 
    at RobotData.searchJunction(Explorer.java:242) 
    at RobotData.reverseHeading(Explorer.java:255) 
    at Explorer.backtrack(Explorer.java:74) 
    at Explorer.junction(Explorer.java:122) 
    at Explorer.controlRobot(Explorer.java:56) 
    ... 5 more` 
+1

请不要删除你的代码,错误消息或其他相关数据毁损你的问题,因为这会让问题对未来的游客完全没有价值。我已经将你的问题回滚到之前的状态,并且如果你将来试图破坏它,它会再次执行。 – 2014-12-05 12:12:29

回答

3

我认为您的searchJunction()是正确的或安全的,但由于错误的迭代器通过junctionList可能会引发ConcurrentModificationException。问题应该更多地是关于迭代器而不是反射。

您可以试试:

  1. private Iterator<Junction> junctionIterator = junctionList.iterator();当初始化RobotData对象并没有太大的意义,因为该列表是空的。尝试将其移动到searchJunction()
  2. 检查hasNext()第一,然后调用next()

    public int searchJunction(IRobot robot) { 
        Iterator<Junction> junctionIterator = junctionList.iterator(); 
        while (junctionIterator.hasNext()) { 
         Junction currentJunction = junctionIterator.next(); 
         if ((((currentJunction.x)==(robot.getLocation().x))) && ((currentJunction.y)==(robot.getLocation().y))) 
          break; 
        } 
    
        return currentJunction.arrived; 
    } 
    
+1

非常感谢!你是个天才!我还有一个问题。是否有可能让机器人跑迷宫一次,记住正确的路线,然后在第二次运行时采取正确的路线?如果是这样,我该怎么做? – codeav3 2014-12-05 03:21:51

+1

如何使用LinkedList类型的实例变量保存正确的路径:IRobot.AHEAD/IRobot.LEFT/.....?如果迷宫可能发生变化,则需要设计一些映射机制来在返回保存的解决方案时评估迷宫的身份。 – 2014-12-05 03:27:17

+0

嗯我从来没有听说过LinkedList。思想进入更多细节? – codeav3 2014-12-05 03:30:15

1

它看起来像这个问题是在下面的代码 -

`public int searchJunction(IRobot robot) { 

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

    return currentJunction.arrived; 
} 

要调用junctionIterator.next()调用junctionIterator.hasNext前()。迭代器规范说,只有在调用hasNext()后,才应该调用next()

相关问题