java.lang.reflect.InvocationTargetException error - java
I am working on a robot maze where the robot finds the target without bumping into walls. As a "backtrack" method, I need the robot to go in the opposite direction as it did when it first came across a junction. This is my code:
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;
}
}
Whenever it is backtracking and reaches a junction it has already visited, it freezes and this comes up.
`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`
I don't think your searchJunction() is right or safe, the ConcurrentModificationException might be thrown due to the incorrect iterator through junctionList . The problem should be more about the iterator rather than reflection.
You might try:
private Iterator<Junction> junctionIterator = junctionList.iterator(); doesn't make much sense since the list is empty when initialize a RobotData object. Try to move it into searchJunction()
Check hasNext() first then invoke 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;
}
It looks like that issue is in following code -
`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;
}
You are calling junctionIterator.next() before calling junctionIterator.hasNext(). Iterator specification says that you should call next() only after calling hasNext()
Related
Java maze won't print
I have to make a maze for a java assignment, and I was able to finish most of it. I was provided with an outline of the code that had all the methods. Can someone help me? My issue is that the maze wont print out, and I can't figure out why. package maze; public class Maze { private char direction; private int r; // x position of the mouse private int c; //y position of the mouse private boolean exitFound = false; public Maze(int[][] arrMaze) { this.r = arrMaze.length - 1; this.c = 0; } //Prints out the maze without solution public void displayMaze(int[][] arrMaze) { //display the maze putting blank spaces where there are 1's in the array and putting //another symbol where there are 0's to show the maze without the solution for(int i=0; i<arrMaze.length; i++){ System.out.println(" "); for(int j=0; j<arrMaze[i].length; j++){ if(arrMaze[i][j] == 0){ System.out.print("#"); } if(arrMaze[i][j] == 1) { System.out.print(" "); } if(arrMaze[i][j] == 2){ System.out.print("#"); } if(arrMaze[i][j] == 3){ System.out.println("~"); } } } } //displays the Maze with the path taken public void displayPath(int[][] arrMaze) { //show the user how far the mouse has gone since the start. //The path the mouse has gone will be filled in but the path ahead will not. for (int i = 0; i < arrMaze.length; i++) { System.out.println(" "); for (int j = 0; j < arrMaze[i].length; j++) { if (arrMaze[i][j] == 3) { System.out.print("#"); } else if (arrMaze[i][j] == 2) { System.out.print("~"); } else if (arrMaze[i][j] == 0) { System.out.print("#"); } else { } } } } public boolean takeStep(int[][] newMaze) { // moveNorth(newMaze) for (int i = 0; i < newMaze.length; i++) { System.out.println(" "); for (int j = 0; j < newMaze[i].length; j++) { if (newMaze[r][c] == 3) { moveNorth(newMaze); System.out.print("~"); } else if (newMaze[r][c] == 2) { System.out.print("#"); } else { } } } return isAnExit(newMaze); } public void moveNorth(int[][] arrMaze) { //complete the code here /*method will check for a 0 or a 1 in the position above the current position * and then if not a 0 will change the current position to the row above it, but in the same column. */ if (arrMaze[r][c - 1] != 0) { arrMaze[r][c - 1] = 3; arrMaze[r][c + 1] = 2; } else { moveSouth(arrMaze); } displayPath(arrMaze); } public void moveSouth(int[][] arrMaze) { //method will check for a 0 or a 1 in the position below the current position and then if not a 0 //it will change the current position to the row below it, but in the same column. if (arrMaze[r][c + 1] != 0) { arrMaze[r][c + 1] = 3; arrMaze[r][c + 1] = 2; } else { moveNorth(arrMaze); } displayPath(arrMaze); } public void moveEast(int[][] arrMaze) { //method will check for a 0 or a 1 in the position to the right of  the current position and then if //not a 0 will change the current position to the column to the right but the same row. if (arrMaze[r + 1][c] != 0) { arrMaze[r + 1][c] = 3; arrMaze[r - 1][c] = 2; } else { moveWest(arrMaze); } displayPath(arrMaze); } public void moveWest(int[][] arrMaze) { //method will check for a 0 or a 1 in the position to the left of  the current position and then if //not a 0 will change the current position to the column to the left but the same row. if (arrMaze[r - 1][c] != 0) { arrMaze[r - 1][c] = 3; arrMaze[r + 1][c] = 2; } else { } displayPath(arrMaze); } private boolean isAnExit(int[][] arrMaze) { //method will return true if the user arrives into the last column of the array because there is only one //location in the last column that is a 1, so if the user reaches the array[i].length then that means that it found an exit. if (arrMaze[r][c] > arrMaze.length) { exitFound = true; } else { exitFound = false; } return exitFound; } //finds the path without stopping at every step //method will show the complete path from start to finish of the maze and the suggested route to the end. public void findExit(int[][] arrMaze) { if (arrMaze[r][c] > arrMaze.length) { for (int i = 0; i < arrMaze.length; i++) { takeStep(arrMaze); } } } } This is the test code. I was provided the test code, and I haven't changed it. package maze; import java.util.Scanner; public class TestMaze { public static void main(String[] args) { int[][] mazeArray = { {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0}, {0,0,0,1,1,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1}, {0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0}, {0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0}, {1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; Maze myMaze = new Maze(mazeArray); boolean keepAsking = true; Scanner scan = new Scanner(System.in); String input = ""; myMaze.displayPath(mazeArray); System.out.println("Maze"); do { System.out.println("T = Take a step | S = Show path | Q = Quit"); System.out.print("Enter command: "); input = scan.nextLine(); input.trim(); input.toLowerCase(); if(input.equals("t")) { keepAsking = !myMaze.takeStep(mazeArray); System.out.println("Which direction would you like to go? N, S, E, W?"); String direction = scan.nextLine(); if(direction.equalsIgnoreCase("n")) myMaze.moveNorth(mazeArray); if(direction.equalsIgnoreCase("s")) myMaze.moveSouth(mazeArray); if(direction.equalsIgnoreCase("e")) myMaze.moveEast(mazeArray); if(direction.equalsIgnoreCase("w")) myMaze.moveWest(mazeArray); } else if(input.equals("s")) { myMaze.findExit(mazeArray); keepAsking = false; } else if(input.equals("q")) { keepAsking = false; } else { System.out.println("ERR: Invalid input"); } } while(keepAsking); System.out.println("Quitting program..."); scan.close(); } }
You need to call displayMaze() (in displayPath()) to print it. Currently, you're not calling the method, meaning that your code will never print the maze as it's no being instructed to. Also, where are you assigning values to r and c? I think you meant to use i and j in your displayPath() method ([i][j] instead of [r][c]).
I imagine you're throwing an error somewhere because your r and c values are undefined everywhere they are used. Try adding code to initialize and update these values, then you should see your maze print.
A* Pathfinding - Weird Bug in Multi-Floored Maps
I'm attempting to create a game "dungeon" map generator in Java in the style of roguelike etc. games. I generate rooms randomly, and then connect them with corridors. I'm trying to use A* pathfinding in corridor creation. I currently am creating just one corridor between rooms in the indices 1 and 2, if there is more than one room. For some reason, the corridor creation seems to fail when I try to generate more than 1 maps ("floors"). The amount of floors is specified as a command-line parameter. Thus far, when I've generated just one floor, everything works perfectly. My gut feeling says that there's something about the floors that messes up my algorithm. I thought that maybe an outside view of the project could help. There is quite a lot of code, but I'd be very grateful if someone took the time to review it. I can provide more information if it's needed. THE RESULTS The result, when correct, should look like this: Map 1 # wall . floor + door $ corridor .............................. .............................. .............................. .............................. .............................. .............................. .............................. .............................. ...........$$$$$$$$$$......... ...........$......##+#######.. .....######$......#........#.. .....#....#$......#........#.. .....#....#$......#........#.. .....#....#$......#........#.. .....#....#$......#........#.. .....#....#$......#........#.. .....#....#$......#........#.. .....##+###$......##########.. .......$$$$$.................. .............................. The buggy result looks like this (the corridor does not go door-to-door, it just ends in a random location): ...........$$$...#########.... ...........$#+##.#.......#.... ...........$#..#.#.......#.... ...........$#..#.#.......+.... ###+###....$#..#.#.......#.... #.....#....$#..#.#.......#.... #.....#....$#..#.#.......#.... #.....#....$#..#.#########.... #.....#....$####.............. #.....#....$.................. #.....#....$.................. #######....$.................. ...........$.................. ...........$.................. ...........$.................. ...........$.................. ...........$.................. ...........$.................. .......$$$$$.................. .............................. THE CODE AStar.java: /** * See https://www.raywenderlich.com/4946/introduction-to-a-pathfinding */ public class AStar { private List<AStarSquare> openList; private List<AStarSquare> closedList; private Exporter debugExporter; private static final Coords[] squareOffsetsToCheck = new Coords[] { new Coords(0, 1), new Coords(1, 0), new Coords(0, -1), new Coords(-1, 0) }; public AStar() { openList = new ArrayList<>(); closedList = new ArrayList<>(); debugExporter = new Exporter(); } public List<Coords> findPath(Coords start, Coords end, Map map) { List<Coords> path = new ArrayList<>(); // each square on the generated path AStarSquare currentSquare = new AStarSquare(start, null); // current square around which possible squares are evaluated - start point closedList.add(currentSquare); // add start point to closed list createUpdateOpenSquares(currentSquare, start, end, map); // create open squares for first iteration calculateScores(start, end, map); // calculate scores for first iteration int loopGuard = 0; // loop until break while(true) { if(openList.size() == 0) { break; } currentSquare = getLowestOpenSquare(); // get the square with the lowest score if(isAdjacentToDoor(currentSquare.getCoords(), end) /*|| currentSquare.getCoords().equalz(end) || loopGuard >= 1000*/) // end point reached or no possible next squares break; // - exclude last square (door) openList.remove(currentSquare); closedList.add(currentSquare); createUpdateOpenSquares(currentSquare, start, end, map); // create and/or update squares next to the current square calculateScores(start, end, map); map.setDebugCorridor(formulatePath(currentSquare)); loopGuard++; } path = formulatePath(currentSquare); return path; } private void createUpdateOpenSquares(AStarSquare currentSquare, Coords start, Coords end, Map map) { for(Coords squareOffsetToCheck : squareOffsetsToCheck) { Coords coordsToCheck = currentSquare.getCoords().vectorAdd(squareOffsetToCheck); if(map.isFloor(coordsToCheck) && !map.isInsideRoom(coordsToCheck) && isWithinMap(map, coordsToCheck) && !isClosed(coordsToCheck)) { AStarSquare openSquare = getOpen(coordsToCheck); if(openSquare == null) openList.add(new AStarSquare(coordsToCheck, currentSquare)); else // is open openSquare.setPrevious(currentSquare); } } } private boolean isClosed(Coords coords) { for(AStarSquare closed : closedList) { if(closed.getCoords().equalz(coords)) return true; } return false; } private AStarSquare getOpen(Coords coords) { for(AStarSquare open : openList) { if(open.getCoords().equalz(coords)) return open; } return null; } private boolean isWithinMap(Map map, Coords coords) { if(coords.getX() < 0 || coords.getY() < 0 || coords.getX() >= map.getW() || coords.getY() >= map.getH()) return false; return true; } private boolean isAdjacentToDoor(Coords coords, Coords end) { for(Coords squareOffset : squareOffsetsToCheck) { Coords offsetSquare = coords.vectorAdd(squareOffset); if(offsetSquare.equalz(end)) return true; } return false; } private void calculateScores(Coords start, Coords end, Map map) { for(AStarSquare square : openList) { square.calculateScores(map, start, end); } } private AStarSquare getLowestOpenSquare() { AStarSquare lowestScore = null; for(AStarSquare square : openList) { // if lowestScore not set or if square.f is lower than lowestScore.f, set square to lowestScore if(lowestScore == null || lowestScore.getF() > square.getF()) lowestScore = square; } return lowestScore; } // exclude first square (door) private List<Coords> formulatePath(AStarSquare currentSquare) { List<Coords> path = new ArrayList<>(); while(currentSquare.getPrevious() != null) { path.add(currentSquare.getCoords()); currentSquare = currentSquare.getPrevious(); } return path; } } AStarSquare.java: /** * See https://www.raywenderlich.com/4946/introduction-to-a-pathfinding */ public class AStarSquare { private Coords coords; private AStarSquare previous; private int g, h; private boolean calculated; public AStarSquare() { g = h = 0; calculated = false; } public AStarSquare(Coords coords) { this(); this.coords = coords; previous = null; } public AStarSquare(Coords coords, AStarSquare previous) { this(); this.coords = coords; this.previous = previous; } public void calculateScores(Map map, Coords start, Coords destination) { g = previous.getG() + 1; // g = distance from start point h = destination.getDistance(coords); // h = estimated (=shortest) distance from the current location to the destination calculated = true; } } Main class: public class DungeonMapGenerator { public static void main(String[] args) { List<String> argsList = Arrays.asList(args); if(!argsList.contains("-w") || !argsList.contains("-h") || !argsList.contains("-f")) { System.out.println("Usage: java -jar DungeonMapGenerator.jar -w [width] -h [height] -f [floors] -[export option]"); System.exit(1); } int width = 0, height = 0, floors = 0; for(int i = 0; i < args.length; i++) { if(args[i].equalsIgnoreCase("-w")) width = tryParseInt(args, i + 1, 30); else if(args[i].equalsIgnoreCase("-h")) height = tryParseInt(args, i + 1, 20); else if(args[i].equalsIgnoreCase("-f")) floors = tryParseInt(args, i + 1, 1); } Generator mapGenerator = new Generator(width, height, floors); List<Map> maps = mapGenerator.generateMaps(); Exporter mapExporter = new Exporter(); if(argsList.contains("-c")) mapExporter.exportToConsole(maps); else System.out.println("No export option selected, quitting"); } private static int tryParseInt(String[] args, int index, int deflt) { int res; if(index >= args.length) // index out of range res = deflt; try { res = Integer.parseInt(args[index], 10); } catch(NumberFormatException ex) { res = deflt; } return res; } } Generator.java public class Generator { private static final int MIN_ROOMS = 1, MAX_ROOMS = 5, MIN_DIM = 3, // dim = min and max room dimensions MAX_DIM = 10; private AStar pathfinder; private Random random; private int mapWidth, mapHeight, floors; public Generator(int mapWidth, int mapHeight, int floors) { pathfinder = new AStar(); random = new Random(System.currentTimeMillis()); this.mapWidth = mapWidth; this.mapHeight = mapHeight; this.floors = floors; } public List<Map> generateMaps() { List<Map> mapList = new ArrayList<>(); for(int i = 0; i < floors; i++) { Map map = new Map(i + 1, mapWidth, mapHeight, generateRooms(mapWidth, mapHeight), null); generateDoors(map, map.getRooms()); debugFindPath(map); mapList.add(map); } return mapList; } private List<Room> generateRooms(int mapWidth, int mapHeight) { List<Room> roomList = new ArrayList<>(); int nRooms = random.nextInt(5) + 1; for(int i = 0; i < nRooms; i++) { Room room = null; do { int w = 0, h = 0, x = 0, y = 0; w = getRandomDim(); h = getRandomDim(); x = random.nextInt(mapWidth - w); y = random.nextInt(mapHeight - h); room = new Room(x, y, w, h); } while(roomsOverlap(room, roomList)); roomList.add(room); } return roomList; } private boolean roomsOverlap(Room room, List<Room> rooms) { for(Room listRoom : rooms) { if(room.overlapsWithRoom(listRoom)) return true; } return false; } private int getRandomDim() { return random.nextInt(MAX_DIM - MIN_DIM + 1) + MIN_DIM; } private void generateDoors(Map map, List<Room> roomList) { for(int i = 0; i < roomList.size(); i++) { Door door = new Door(roomList.get(i)); do { door.setSide(getRandomCardinal()); door.setDistNW(getRandomDistNW(roomList.get(i), door.getSide())); } while(!validateDoor(map, door)); roomList.get(i).setDoors(Arrays.asList(new Door[] { door })); map.getDoors().add(door); } } private Cardinal getRandomCardinal() { int cardinalInt = random.nextInt(4); Cardinal cardinal; switch(cardinalInt) { case 1: cardinal = Cardinal.EAST; break; case 2: cardinal = Cardinal.SOUTH; break; case 3: cardinal = Cardinal.WEST; case 0: default: cardinal = Cardinal.NORTH; break; } return cardinal; } private int getRandomDistNW(Room room, Cardinal cardinal) { int distNW = 0; if(cardinal == Cardinal.NORTH || cardinal == Cardinal.SOUTH) distNW = random.nextInt(room.getW() - 2) + 1; // exclude corners else if(cardinal == Cardinal.EAST || cardinal == Cardinal.WEST) distNW = random.nextInt(room.getH() - 2) + 1; // exclude corners return distNW; } private boolean validateDoor(Map map, Door door) { Coords doorCoordsOnMap = door.getCoordsOnMap(); if(door.getSide() == Cardinal.NORTH && (door.getParent().getTop() == 0 // check if adjacent to another room || map.isWall(new Coords(doorCoordsOnMap.getX(), doorCoordsOnMap.getY() - 1)))) return false; else if(door.getSide() == Cardinal.EAST && (door.getParent().getRight() == mapWidth - 1 // check if adjacent to another room || map.isWall(new Coords(doorCoordsOnMap.getX() + 1, doorCoordsOnMap.getY())))) return false; else if(door.getSide() == Cardinal.SOUTH && (door.getParent().getBottom() == mapHeight - 1 // check if adjacent to another room || map.isWall(new Coords(doorCoordsOnMap.getX(), doorCoordsOnMap.getY() + 1)))) return false; else if(door.getSide() == Cardinal.WEST && (door.getParent().getLeft() == 0 // check if adjacent to another room || map.isWall(new Coords(doorCoordsOnMap.getX() - 1, doorCoordsOnMap.getY())))) return false; return true; } private void debugFindPath(Map map) { if(map.getRooms().size() == 1) return; map.setDebugCorridor(pathfinder.findPath( map.getRooms().get(0).getDoors().get(0).getCoordsOnMap(), map.getRooms().get(1).getDoors().get(0).getCoordsOnMap(), map )); } } Room.java public class Room { private Coords topLeft; private int w, h; private List<Door> doors; public Room(int topLeftX, int topLeftY, int w, int h) { topLeft = new Coords(topLeftX, topLeftY); this.w = w; this.h = h; doors = new ArrayList<>(); } public boolean overlapsWithRoom(Room otherRoom) { return !(otherRoom.getLeft() > this.getRight() || otherRoom.getRight() < this.getLeft() || otherRoom.getTop() > this.getBottom() || otherRoom.getBottom() < this.getTop()); } #Override public String toString() { return "Room ~ top: " + getTop() + " right: " + getRight() + " bottom: " + getBottom() + " left: " + getLeft() + " width: " + w + " height: " + h; } public boolean isWall(Coords coords) { /*** TESTAA!!! ***/ if( // x is either left or right, y is between top and bottom ((coords.getX() == topLeft.getX() || coords.getX() == topLeft.getX() + w) && coords.getY() >= topLeft.getY() && coords.getY() < topLeft.getY() + h + 1) || // y is either top or bottom, x is between left and right ((coords.getY() == topLeft.getY() || coords.getY() == topLeft.getY() + h) && coords.getX() >= topLeft.getX() && coords.getX() < topLeft.getX() + w) ) return true; return false; } } Door.java (Cardinal is a simple enum containing NORTH, EAST, SOUTH and WEST) public class Door { private Room parent; private Cardinal side; private int distNW = 0; public Door(Room parent) { this.parent = parent; this.side = null; } public Door(Room parent, Cardinal side) { this.parent = parent; this.side = side; } public Coords getCoordsOnMap() { Coords coords = null; if(side == Cardinal.NORTH) coords = new Coords(parent.getLeft() + distNW, parent.getTop()); else if(side == Cardinal.EAST) coords = new Coords(parent.getRight(), parent.getTop() + distNW); else if(side == Cardinal.SOUTH) coords = new Coords(parent.getLeft() + distNW, parent.getBottom()); else if(side == Cardinal.WEST) coords = new Coords(parent.getLeft(), parent.getTop() + distNW); return coords; } }
In AStar, your A* pathfinding algorithm adds to its opened and closed lists before returning the chosen path When pathfinding with different start/end destinations or a different map, those lists will need to be reset The issue is that you're reusing the AStar object for each path you're trying to find, causing conflicts with old searches To fix it, use a new AStar object for every path you search, or add a method to clear the old data
I removed this line from the Generator constructor: public Generator(int mapWidth, int mapHeight, int floors) { // pathfinder = new AStar(); // REMOVED THIS LINE ... } And I added the following line to the Generator.generateMaps method: public List<Map> generateMaps() { List<Map> mapList = new ArrayList<>(); for(int i = 0; i < floors; i++) { pathfinder = new AStar(); // ADDED THIS LINE Map map = new Map(i + 1, mapWidth, mapHeight, generateRooms(mapWidth, mapHeight), null); generateDoors(map, map.getRooms()); debugFindPath(map); mapList.add(map); } return mapList; } And now everything seems to work. Another option is to add the following lines to AStar.findPath(): public List<Coords> findPath(Coords start, Coords end, Map map) { openList = new ArrayList<>(); closedList = new ArrayList<>(); ... }
Connect 4 right to left diagonal check
There's probably a very simple solution to this but I can't figure out where I'm doing something wrong. I'm making a small game with android studio that is connect 4. There is a 5x7 matrix of single cells, and 5 imageviews above that when clicked on put a fiche in the right place. Up to this point it's all working fine. When I however have to check if someone won, I thought I could break up the process in 4 main functions: one that check horizontally, one vertically, one diagonally left to right and one diagonally right to left. Now they all work perfectly except the right to left one. I'll post the code below: private void checkRightLeftDiagonally() { int winCondition = 0; boolean goingRight = true; int y = 1; int i = 4; int j = 0; while (y < 6 && won == false) { while (i > 0 && j < 7 && won == false) { if (cells[j][i].getFull() == true && players[playerTurn].getFicheColor() == cells[j][i].getFicheColor()) { winCondition++; winningCells.add(cells[j][i]); } else { winCondition = 0; winningCells.clear(); } if (winCondition == 4) { won = true; for (int x = 0; x < 4; x++) { winningCells.get(x).won(); } } i--; j++; } if(goingRight == true) { if(y<=4) { i=4-y; j=0; y++; } else { goingRight = false; y=0; i=0; j=0+y; } } if(goingRight == false) { i=0; j=0+y; y++; } if(won == false) { winCondition = 0; winningCells.clear(); } } if(won == false) { winCondition = 0; winningCells.clear(); } } And here is one of the arrow imageview code: imgArrows[0].setOnClickListener(new View.OnClickListener() { #Override public void onClick(View view) { if(cells[0][0].getFull() == false && won == false) { int i = 0; while(cells[i][0].getFull() == false) { i++; if(i>6) break; } i--; cells[i][0].ficheDown(players[playerTurn]); checkVertically(); checkHorizantally(); checkLeftRightDiagonally(); checkRightLeftDiagonally(); playerTurn++; if(playerTurn==2) { playerTurn = 0; } } } }); I've also made the cell class, which is here if it could help you public class Cell { private boolean full; private Player.FicheColor ficheColor; private ImageView fiche; public Cell(Player currentPlayer, ImageView img) { full = false; ficheColor = currentPlayer.getFicheColor(); fiche = img; img.setAlpha(0f); } public void ficheDown(Player currentPlayer) { full = true; ficheColor = currentPlayer.getFicheColor(); switch(ficheColor) { case red: fiche.setImageResource(R.drawable.redfiche); break; case blue: fiche.setImageResource(R.drawable.bluefiche); break; case green: fiche.setImageResource(R.drawable.greenfiche); break; case white: fiche.setImageResource(R.drawable.whitefiche); break; case black: fiche.setImageResource(R.drawable.whitefiche); break; } fiche.setAlpha(1f); } public Player.FicheColor getFicheColor() { return ficheColor; } public boolean getFull() { return full; } public void won(){ fiche.setColorFilter(Color.GREEN); } public void reset() { fiche.clearColorFilter(); } } Thank a lot, even just for reading
In the end the problem was that in the first paragraph of code the int i needed to be set to 4 and that solved it. Thanks to everyone that tried to help me
Autocomplete byReverseWeightOrder comparator issue
I have been working on this problem for several hours now and I just cannot figure out what I am doing wrong here. Could anyone help point me in the right direction? I was asked to write an Autocomplete program and I've completed everything except for this one method I cannot get working. Each term has: 1. String query and 2. long weight. Here is the method: public static Comparator<Term> byReverseWeightOrder() { return new Comparator<Term>() { // LINE CAUSING PROBLEM public int compare(Term t1, Term t2) { if (t1.weight > t2.weight) { // LINE CAUSING PROBLEM return -1; } else if (t1.weight == t2.weight) { return 0; } else { return 1; } } }; } My problem is that no matter how I mess with the method I always result in a NullPointerException(). Which, it points to this method (byReverseWeightOrder) as well as these two statements. Arrays.sort(matches, Term.byReverseWeightOrder()); Term[] results = autocomplete.allMatches(prefix); Here is the rest of the code if it can be found helpful: Term import java.util.Comparator; public class Term implements Comparable<Term> { public String query; public long weight; public Term(String query, long weight) { if (query == null) { throw new java.lang.NullPointerException("Query cannot be null"); } if (weight < 0) { throw new java.lang.IllegalArgumentException("Weight cannot be negative"); } this.query = query; this.weight = weight; } public static Comparator<Term> byReverseWeightOrder() { return new Comparator<Term>() { public int compare(Term t1, Term t2) { if (t1.weight > t2.weight) { return -1; } else if (t1.weight == t2.weight) { return 0; } else { return 1; } } }; } public static Comparator<Term> byPrefixOrder(int r) { if (r < 0) { throw new java.lang.IllegalArgumentException("Cannot order with negative number of characters"); } final int ref = r; return new Comparator<Term>() { public int compare(Term t1, Term t2) { String q1 = t1.query; String q2 = t2.query; int min; if (q1.length() < q2.length()) { min = q1.length(); } else { min = q2.length(); } if (min >= ref) { return q1.substring(0, ref).compareTo(q2.substring(0, ref)); } else if (q1.substring(0, min).compareTo(q2.substring(0, min)) == 0) { if (q1.length() == min) { return -1; } else { return 1; } } else { return q1.substring(0, min).compareTo(q2.substring(0, min)); } } }; } public int compareTo(Term that) { String q1 = this.query; String q2 = that.query; return q1.compareTo(q2); } public long getWeight() { return this.weight; } public String toString() { return this.weight + "\t" + this.query; } } BinarySearchDeluxe import java.lang.*; import java.util.*; import java.util.Comparator; public class BinarySearchDeluxe { public static <Key> int firstIndexOf(Key[] a, Key key, Comparator<Key> comparator) { if (a == null || key == null || comparator == null) { throw new java.lang.NullPointerException(); } if (a.length == 0) { return -1; } int left = 0; int right = a.length - 1; while (left + 1 < right) { int middle = left + (right - left)/2; if (comparator.compare(key, a[middle]) <= 0) { right = middle; } else { left = middle; } } if (comparator.compare(key, a[left]) == 0) { return left; } if (comparator.compare(key, a[right]) == 0) { return right; } return -1; } public static <Key> int lastIndexOf(Key[] a, Key key, Comparator<Key> comparator) { if (a == null || key == null || comparator == null) { throw new java.lang.NullPointerException(); } if (a == null || a.length == 0) { return -1; } int left = 0; int right = a.length - 1; while (left + 1 < right) { int middle = left + (right - left)/2; if (comparator.compare(key, a[middle]) < 0) { right = middle; } else { left = middle; } } if (comparator.compare(key, a[right]) == 0) { return right; } if (comparator.compare(key, a[left]) == 0) { return left; } return -1; } } AutoComplete import java.util.Arrays; import java.util.Scanner; import java.io.File; import java.io.IOException; import java.util.Comparator; public class Autocomplete { public Term[] terms; public Autocomplete(Term[] terms) { if (terms == null) { throw new java.lang.NullPointerException(); } this.terms = terms.clone(); Arrays.sort(this.terms); } public Term[] allMatches(String prefix) { if (prefix == null) { throw new java.lang.NullPointerException(); } Term theTerm = new Term(prefix, 0); int start = BinarySearchDeluxe.firstIndexOf(terms, theTerm, Term.byPrefixOrder(prefix.length())); int end = BinarySearchDeluxe.lastIndexOf(terms, theTerm, Term.byPrefixOrder(prefix.length())); int count = start; System.out.println("Start: " + start + " End: " + end); if (start == -1 || end == -1) { // System.out.println("PREFIX: " + prefix); throw new java.lang.NullPointerException(); } // Needed? Term[] matches = new Term[end - start + 1]; //matches = Arrays.copyOfRange(terms, start, end); for (int i = 0; i < end - start; i++) { matches[i] = this.terms[count]; count++; } Arrays.sort(matches, Term.byReverseWeightOrder()); System.out.println("Finished allmatches"); return matches; } public int numberOfMatches(String prefix) { if (prefix == null) { throw new java.lang.NullPointerException(); } Term theTerm = new Term(prefix, 0); int start = BinarySearchDeluxe.firstIndexOf(terms, theTerm, Term.byPrefixOrder(prefix.length())); int end = BinarySearchDeluxe.lastIndexOf(terms, theTerm, Term.byPrefixOrder(prefix.length())); System.out.println("Finished numberMatches"); return end - start + 1; // +1 needed? } public static void main(String[] args) throws IOException { // Read the terms from the file Scanner in = new Scanner(new File("wiktionary.txt")); int N = in.nextInt(); // Number of terms in file Term[] terms = new Term[N]; for (int i = 0; i < N; i++) { long weight = in.nextLong(); // read the next weight String query = in.nextLine(); // read the next query terms[i] = new Term(query.replaceFirst("\t",""), weight); // construct the term } Scanner ip = new Scanner(System.in); // TO DO: Data Validation Here int k; do { System.out.println("Enter how many matching terms do you want to see:"); k = ip.nextInt(); } while (k < 1 || k > N); Autocomplete autocomplete = new Autocomplete(terms); // TO DO: Keep asking the user to enter the prefix and show results till user quits boolean cont = true; do { // Read in queries from standard input and print out the top k matching terms System.out.println("Enter the term you are searching for. Enter * to exit"); String prefix = ip.next(); if (prefix.equals("*")) { cont = false; break; } Term[] results = autocomplete.allMatches(prefix); System.out.println(results.length); for(int i = 0; i < Math.min(k,results.length); i++) System.out.println(results[i].toString()); } while(cont); System.out.println("Done!"); } } I apologize for the sloppy code, I have been pulling my hair out for awhile now and keep forgetting to clean it up. Two examples: Example 1: int k = 2; String prefix = "auto"; Enter how many matching terms do you want to see: 2 Enter the term you are searching for. Enter * to exit auto 619695 automobile 424997 automatic Example 2: int k = 5; String prefix = "the"; Enter how many matching terms do you want to see: 5 Enter the term you are searching for. Enter * to exit the 5627187200 the 334039800 they 282026500 their 250991700 them 196120000 there
Passing variables from class method to another class
I am trying to create a win condition for my text game. I have two methods that decide whether a player has established criteria for a win or loss. These methods are in one class, while I want to use them in my controller class. The variables are hitTimes and nonHits: class1: if(choiceC > 0 || choiceR > 0) { Character currentCharacter; currentCharacter= grid[choiceR][choiceC]; gameBoard[choiceR][choiceC] = currentCharacter; loseTest(currentCharacter); winTest(currentCharacter); } } } } public int loseTest(Character currentCharacter) { int hitTimes = 0; if(currentCharacter.minePresent == true) { hitTimes = 1; } return hitTimes; } public int winTest(Character currentCharacter) { int nonHits = 0; if(currentCharacter.minePresent == false) { nonHits++; } return nonHits; } class2: Grid grid = new Grid(); double notMines = grid.notMine; View view = new View(); result = grid.toString(); view.display(result); final int ITERATIONS = 13; final int numGames = 1000; for (int i=0;i <= numGames; i++) { while (hitTimes != 1 || nonHits != notMines ) { grid.runGame(); result2 = grid.toString(); view.display(result2); if(nonHits == ITERATIONS) { System.out.println("You Win!"); } if(hitTimes == 1) { System.out.println("You Lose!"); } } }
You could make boolean attributes gameWon and gameLost, and put them both at false initial value. Then if conditions are fulfilled you turn one of them into true depending on the case of course. Make also getter methods in your class so you can access to them from another class. Place this in your second method: private boolean gameWon = false; private boolean gameLost = false; public boolean getGameWon() { return gameWon; } public boolean getGameLost() { return gameLost; } Change if condition to also have: if(nonHits == ITERATIONS) { gameWon = true; } if(hitTimes == 1) { gameLost = true; } In your other class create this class and access your gameWon/gameLost values through getters. SecondClass sc = new SecondClass(); boolean isGameWon = sc.gameWon(); boolean isGameLost = sc.gameLost(); Hopefully I gave you an idea.. I can't see your whole code so this is just an assumption I made of what's bothering you. Cheers!