As the title says, I'm having a problem with objects overlapping. I want them to be able to overlap because I need object X to be on top of object Y to get a point and if I remove object X from being on top of Y, I remove the said point. My problem then is, if object Y is created before object X, once I place object X on top of Y, I can no longer move it and it always outputs to the console, Object Y. I was wondering if there would be an easier way to fix this.
I try moving forward but the Box doesn't budge:
[
This is the code that I'm using to generate the level Data
private List<ImageTile> createLevel(){
ArrayList<Movable> aux1 = new ArrayList<>();
ArrayList<Immovable> aux2 = new ArrayList<>();
try {
Scanner sc = new Scanner(new File ("levels/level" + levelID + ".txt"));
String line = "";
while(sc.hasNextLine()) {
for (int y = 0; y < HEIGHT; y++) {
line = sc.nextLine();
for(int x = 0; x < WIDTH ; x++) {
levelObjects.add(new floor(new Point2D(x,y), "Floor", 0));//adding the floor before anything else
char letter = line.charAt(x); // checking the character in the X coordinate
if (letter == 'E') { // in case, there's a E, that's the starting position of the player
player = new Forklift(new Point2D(x,y), "Forklift_U", 2);
levelObjects.add(player);
objects.add(player);
} else if(letter != ' ') {
AbstractObject obj = ObjectCreation.readChar(letter, x, y); // going to look for the object in Factory to be put in the X and Y position
if(obj instanceof Immovable) {
aux2.add((Immovable) obj);
}else if(obj instanceof Movable) {
aux1.add((Movable) obj);
}
// comp.comprator(obj, obj);
objects.add(obj);
levelObjects.add(obj);//implementing said object into the Level
}
}
}
}
sc.close(); //Closing Scanner
} catch (FileNotFoundException e) {
System.out.println("No levels found!");
}
still = aux2;
moving = aux1;
return levelObjects;
}
Then I'm checking with the general move function if the box( or any object part of the instance Movable) can move to the next position
public void move(Direction direction) {
Vector2D pos = direction.asVector(); // Transforming the direction in a vector right off the bat.
Point2D currentPosition = getPosition(); // getting the current position of either player or object.
Point2D nextPosition = currentPosition.plus(pos); // the next position as to which the player or the object intend to go to.
if(isTransposable(nextPosition)) { // calls the function to see if the object is able to move to the next position, this prevents the boxes from pushing up into the walls and from into each other {
setPosition(nextPosition); //if it can, then the object will go to the next position
}
}
And this is to check whether or not the object can advance to the next position;
public boolean isTransposable(Point2D pos) { // is the object able to move to the next position
for(AbstractObject obj1 : Game.getInstance().getObjects()) { // for-each to get all the objects, with the exception of the floor, from the game.
if((obj1.isBlockable() && obj1.getPosition().equals(pos))){ // if the object is able to block and if it's position is the same as the nextPosition.
return false;
}
}
return true; // otherwise it's able to be walked on.
}
It was a simple case of having two lists and one having priority over the other.
In the picture, you can the box is on top of the target, but as soon as that happened, the engine would read the tile that came first, in this case being the Target one. Since that one is immovable it meant that it could not be pushed/moved by any means. Regardless if you had anything on top of it that could.
A way I used to fix it, was to simply check if the object was of class movable
public boolean isMovable(Point2D pos) {
for(AbstractObject obj1 : Game.getInstance().getObjects()) {
if((obj1.isMovable() && instanceof Movable)){
return true;
}
}
return false;
}
Related
I was trying to make a battleship clone but ended up running into one problem. I made a BattleShipGrid class that had two 2D arrays, one for each player. The array called p1/p2grid holds their ship and the locations the other player has shot at. The second array called p1/p2fire is the one that shows only where they shot, and not where the enemy ship is, though they can see where they’ve hit it. Im having a problem where I want to print player 1's fire grid after them firing to show if they missed or not. But each time I print player 1's fire grid it still sets everything as 0, like they never even fired on anything. I made 1 a miss and 3 a hit and 2 to represent the location of a ship.
Here is my code in my main:
boolean player1Turn = true;
if (player1Turn) {
fire = grid.fireAtPlayerTwo(x, y);
} else {
fire = grid.fireAtPlayerOne(x, y);
}
if (fire == 0) {
System.out.println("Miss!");
} else if (fire == 2) {
System.out.println("=====================================");
System.out.println("Hit!");
if (player1Turn) {
System.out.println(grid.printP1Fire());/* printing regular old empty array filled with zeros like when a player just starts and hasn't fired on anything.*/
} else {
System.out.println(grid.printP2Fire());
}
System.out.println("=====================================");
}
Here is my methods that I called when firing on the other player( fire at player one and fire at player two do the same thing but are named different ) :
int Empty = 0;
public int fireAtPlayerTwo ( int x, int y)
{
int result = p2Grid[x][y];
if (result == EMPTY) {
p1Grid[x][y] = MISS;/* This should change the value in p1Grid at that coordinate but it is not refelcting back in the main*/
p2Fire[x][y] = MISS;
} else if (result == SHIP) {
p1Grid[x][y] = HIT;
p2Fire[x][y] = HIT;
}
return result;
}
I'm a beginner when it comes to Java and I'm trying to find a way to see if an object is located on certain coordinates. I've tried to search for similar questions, but I still haven't found an answer.
The program I'm working on is a map (image file) and the user should be able to create places and place them on the map (which will be displayed as triangles on the map). There is also this function where the user should be able to type in coordinates to see if there already is a place on those coordinates.
The object is an object of the class "Place" and consists a name, an x-coordinate and an y-coordinate.
Here is my code:
class CoordinatesListener implements ActionListener {
public void actionPerformed(ActionEvent ave) {
try {
CoordinatesForm c = new CoordinatesForm();
int answer = c.getAnswer();
if (answer != JOptionPane.OK_OPTION) {
return;
}
if (c.getPosition() == null) {
JOptionPane.showMessageDialog(null, "Invalid Input kkk", "Invalid Input", JOptionPane.ERROR_MESSAGE);
} else {
Position p = c.getPosition();
boolean flag = false;
for (Position key : positionList.keySet()) {
if (key.getXCoordinate() == p.getXCoordinate() && key.getYCoordinate() == p.getYCoordinate()) {
flag = true;
this.setAllMarkedPlacesUnMarked();
Place place = positionList.get(key);
if (place != null) {
System.out.println("the place " + place + "against position " + key);
place.setMarked(true);
if (!place.isVisible()) {
place.setVisible(true);
}
markedPlacesHashMap.put(place.getName(), place);
if (markedPlacesHashMap.containsKey(place.getName())) {
markedPlacesHashMap.get(place.getName()).add(place);
} else {
// ArrayList<Place> newMarkedPlaces = new ArrayList<>();
// newMarkedPlaces.add(place);
markedPlacesHashMap.put(place.getName(), place);
}
}
}
}
Also, when a place is created, the user shouldn't be able to place another place on the same coordinates. There should be an error message saying that a place already exists on those coordinates.
Here is the code where a place is created:
private void createNamedPlace(int x, int y, String answer) {
Position pos = new Position(x, y);
display.add(n = new NamedPlace(selectedCategory, pos, answer));
p = n;
places = new ArrayList<>();
placeByCategory = new ArrayList<>();
positionList.put(pos, n);
if (categoryMap.containsKey(selectedCategory)) {
categoryMap.get(selectedCategory).add(n);
if (nameList.containsKey(answer)) {
nameList.get(answer).add(n);
} else {
places.add(n);
nameList.put(answer, places);
}
} else {
placeByCategory.add(n);
categoryMap.put(selectedCategory, placeByCategory);
if (nameList.containsKey(answer)) {
nameList.get(answer).add(n);
System.out.println("The new Place have been added in the Name
List, the place name is :" + answer);
this.displayMap(nameList, " PlACES LIST BY NAME");
} else {
places.add(n);
nameList.put(answer, places);
this.displayMap(nameList, "PLACES LIST BY NAME");
}
this.displayMap(categoryMap, " PlACES LIST BY CATEGORY");
}
n.addMouseListener(new TriangleListener());
display.validate();
display.repaint();
display.removeMouseListener(mouseListener);
display.setCursor(Cursor.getDefaultCursor());
newButton.setEnabled(true);
categoryList.clearSelection();
isSaved = false;
}
All Swing components are ultimately derived from the Component class, which has a method getBounds(), returning a rectangle. So you can simply write something like
if (myComponent.getBounds().contains(x,y)) {
// do something
where x and y are the co-ordinates of the point you're trying to check.
Here is the program that I am trying to run:
/**
* Write a description of class mainGame here.
*
* #author Anthony Parsch
* #version 0.1.1
*/
//Import what I need to.
import java.io.*;
public class mainGame
{
/**
* Constructor for objects of class mainGame
*/
public static void main(String[] args)
{
// initialise instance variables
int xCoord = 10; //The map's max x coordinate +1
int yCoord = 10; //The map's max y coordinate +1
int playerX = 0; //The player's current x coordinate
int playerY = 0; //The player's current y coordinate
//Declare the arrays
String[][] map; //[x][y]The map
String[][] direc; //[x][y]Which directions that you can go
String[][] items; //[x][y]Where items are at
String[] inv; // Holds your inventory.
int[][] helpInt; //[x][y] All the other stuff in the
//Initalize the arrays
//---The player arrays
inv = new String[10]; //The player's inventory
inv[0] = "0";
inv = addItem(inv, "Blarg");//GET RID OF THIS LATER
//---The map arrays
map = new String[xCoord][yCoord]; //Descriptions
direc = new String[xCoord][yCoord]; //north y++,west x--,south y--,east x++
items = new String[xCoord][yCoord]; //The items within the world
//Declare the values of map
map[0][0] = "You wake up with the feel of cold metal on your back. The only other thing in this room is the door.";
map[0][1] = "You are now in a hallway with a door behind you and one either side. Forward is a continuation of the hallway.com";
//Declare the values of direc
direc[0][0] = "north";
direc[0][1] = "north, south, east, west";
print(inv[0]); //Check that the functions work
print(findDirec(direc, 0, 0));
}
/**
* Finds and displays the avaliable exits for a coordinate.
*
* #param map[][] The map array from which this method pulls the directions from.
* #param x The x value of the map
* #param y The y value of the map
* #return The string value of which way you can go
*/
static String findDirec(String[][] map, int x, int y){
//Pulls the directions
String match = map[x][y];
//Checks Directions
boolean nor = match.matches("(.*)north(.*)");
boolean sou = match.matches("(.*)south(.*)");
boolean wes = match.matches("(.*)west(.*)");
boolean eas = match.matches("(.*)east(.*)");
//Displays directions
String placeHolder = "You can go ";
if (nor == true){
placeHolder = placeHolder + "north, ";
} else if(sou == true) {
placeHolder = placeHolder + "south, ";
} else if(wes == true) {
placeHolder = placeHolder + "west, ";
} else if(eas == true) {
placeHolder = placeHolder + "east";
}
//---Checks if east is in the string, if not it removes the space and comma
if (eas == false){
StringBuffer soo = new StringBuffer(placeHolder);
soo.delete((placeHolder.length()-3), (placeHolder.length()-1));
placeHolder = soo.toString();
}
//Adds the ending period
placeHolder = placeHolder + ".";
//Returns the string
return placeHolder;
}
//Adds an item to an inventory
static String[] addItem(String inv[], String item){
int i; //Counter for the for loop, and where to add the item at.
boolean stop = false;
for(i=0; stop = true; i++)
{
if(inv[i].equals("0"))
{
stop = true;
}
}
inv[i] = item;
return inv;
}
static void print(String entry){
System.out.print(entry);
}
}
And when I try and run it through the Command Prompt, I get this error:
Exception in thread "main" java.lang.NullPointerExcpetion
at mainGame.addItem(mainGame.java:113)
at mainGame.main(mainGame.java:38)
When I paste this in to a text editor, line 113 is simply a closing brace }.
However, one line before that is a logic flaw which I presume is really line 113 for you.
for(i=0; stop = true; i++)
{
if(inv[i].equals("0"))
{
stop = true;
}
}
Each iteration of the loop assigns true to stop and then tests if true equals true, which it does. Your condition to exit the loop is when true equals false, which is never the case, therefore your loop goes forever until an error occurs. Also, don't you want to iterate while stop is false? I think you have it backwards.
The next problem is your if statement, which is probably where your NullPointerException is coming from:
if(inv[i].equals("0"))
{
stop = true;
}
You assume that inv[i] refers to an object. You need a null check.
Three recommendations:
Never use = for a comparison. Use ==. Since this is a boolean, you can even simplify this to stop.
Check the length in your for loop.
Compare "0" to inv[i] instead of the other way around to avoid null pointer dereferencing.
Try this:
boolean stop = false;
for (int i = 0; i < inv.length && !stop; i++)
{
if("0".equals(inv[i])
{
stop = true;
}
}
Another option, and this is a matter of form, is to remove the looping variable and just break out of the loop explicitly.
for (int i = 0; i < inv.length; i++)
{
if("0".equals(inv[i])
{
break;
}
}
inv = new String[10]; //The player's inventory
inv[0] = "0";
inv = addItem(inv, "Blarg");//GET RID OF THIS LATER
So you only initialize one index of your array but here:
for(i=0; stop = true; i++)
{
if(inv[i].equals("0"))
{
stop = true;
}
}
.. you loop through all of them. just kidding, didn't read the full problem. You should still read the rest of my answer, but the reason why you get the NPE is because your loop condition is broken. (by the way your for loop condition is broken, it should test for equivalence using the == operator, not the assignment = operator.)
So what you actually are doing with that code is this :
inv = new String[10];
At this point you have a new String array of capacity 10, with no values inside, something like this:
[null][null][null][null][null][null][null][null][null][null]
inv[0] = "0";
Now you set [0] to "0", so:
["0"][null][null][null][null][null][null][null][null][null]
Then your loop attempts to access all of those null references, that'll probably be why you have a null reference exception.
To fix it, simply every index position in your array to anything that is not-null:
Arrays.fill(inv, "");
I use Arrays.fill() because it's shorter.
In your for loop condition, which one do you prefer?
stop = true or stop == true
for(i=0; i<inv.length && !stop; i++)
{
if(inv[i]!=null && inv[i].equals("0"))
{
stop = true;
}
}
I'm trying to do a game. When you press "A" my character was supposed to jump ONE square forward, but he is jumping like 7 squares each time I press the "A" key. Someone knows how to limit it to 1? I know why it is happening, but I didn't find any ways to do that until now.
My "Player" class code, that is my Character class:
ArrayList<Square> squareList = new ArrayList<Square>();
int count = 0;
Vector2 position = new Vector2(50,50);
if(Gdx.input.isKeyPressed(Keys.A))
{
j = j + 1;
position.x = squareList.get(i).getPosition().x;
position.y = squareList.get(i).getPosition().y;
i++;
}
Try this:
if (Gdx.input.isKeyJustPressed(Keys.A)) {
System.out.println("KEY PRESSED");
}
It only runs once when you press the key, but if you press and hold it only triggers once. Tested it.
Something like this i imagine would work:
if (Gdx.input.isKeyPressed(Input.Keys.P)) {
// Use a helper so that a held-down button does not continuously switch between states with every tick
if (pauseHelper) {
if (isPaused) {
Util.toConsole ("No longer paused");
isPaused = false;
}
else {
Util.toConsole ("Now paused");
isPaused = true;
}
pauseHelper = false;
}
}
else {
pauseHelper = true;
}
(See http://pastebin.com/vsVWeHj6)
However, technically you need to implement an InputProcessor provided by LibGDX to handle key presses.
Another way to do it if you don't want to implement an InputProcessor:
//Member variable:
boolean mAKeyWasPressed = false;
//In method:
boolean aKeyIsPressed = Gdx.input.isKeyPressed(Keys.A);
if (aKeyIsPressed && !mAKeyWasPressed)
//Just pressed. Do stuff here.
}
mAKeyWasPressed = aKeyIsPressed;
I'm solving this BFS homework problem, I believe the logic I'm following is right, but I got stuck in an implementation error I can't pinpoint. I'm looking for help debugging this solution, not proposing a new one.
Problem Statement:
A kids has two robots that he controls remotely, both robots are on a NxN checkerboard and should be placed on the positions A and B in the checkerboard.
Both robots are affected by the remote controller simultaneously, the same command affects both of their states.
The remote controller can only make both robots turn clockwise or counterclockwise 90 degreees at a time or order both robots to move forward.
Example:
The leftmost image shows the initial setting. The arrow pointing right is a robot facing east and the arraw pointing up is a robot facing north. Positions A and B are the robots destinies.
Center image shows the result of moving both robots one step forward.
Right image shows the result of making the robots rotate counterclockwise.
The kid desires to calculate the minimum number of movements necessary to take the robots from their initial positions to their destinies.
If a robot is commanded to run over a wall, it will remain on the same spot.
Both robots will remain on their original spot if they're commanded to move to the same spot.
Figure 2 shows this special cases.
Both robots should at arrive at a different destiny simultaneously.
Input:
Input consists of various test cases, the first line starts with an integer with the size N of the inputMatrix (the checkerboard), with 2<= N <=25.
The following N lines describe the checkerboard and have N characters each.
A '.' indicates an empty position.
N, E, S or O (Spanish for Oeste=West) indicates the original positiona and orientation of the robot.
D indicates a destiny for the robot in the checkerboard and '*' indicates an obstacle.
Input finishes with a case where N=0.
input.txt
5
D....
N...S
.....
*...*
....D
5
.....
S..S.
.....
.....
D..D.
3
SN.
***
.DD
0
correct output for input.txt:
8
3
-1
input2.txt:
5
.....
..D.S
.D...
.....
..N..
6
......
..S...
......
.ED...
......
.D....
11
....E......
....D......
...........
..S...D....
...........
...........
...........
...........
...........
...........
...........
13
.............
.............
.............
.............
.....N.......
.............
.........D...
..D..........
.............
...E.........
.............
.............
.............
25
...*.......*.*...........
........*..D...*.**....*.
*..*.*.........*..*..*..D
...*.**.*........*...*...
......**..*..***.***...**
.............*...........
....*...***.....*.**.....
......**.......**.*.*...*
.........*..*...*.*......
....**.*.*....**.*.*.*.*.
.......*............**...
..........*.*.....*......
...........**....*.**....
.....E.*.*..........**.*.
.........*.*.*.*..*..*...
*........**...*..........
................***..*...
........*....*....*...*..
......*...*.*...*.....**.
...*..........*.**.......
.**............*.*..*.*..
........*........*...*...
*......*..........*......
*...*......N*......*..*.*
. .....*..*.*..*...*......
0
"correct" (?) output for input2.txt:
-1
-1
9
-1
46
My solution:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
class Position {
int i;
int j;
char orientation;
Position() {
}
void setIJ(int i, int j){
this.i=i;
this.j=j;
}
void setOrientation(char c){
orientation = c;
}
public boolean equals(Object o){
if(o instanceof Position){
Position p = (Position)o;
if((p.i==this.i)&&(p.j==this.j)&&(p.orientation==this.orientation))
{
return true;
}
else return false;
}
return false;
}
} //end class Position
class TransitionState {
Position positionA;
Position positionB;
int counter;
public boolean equals (Object o){
if (o instanceof TransitionState){
TransitionState transitionState= (TransitionState)o;
if ((this.positionA.equals(transitionState.positionA))
&&(this.positionB.equals(transitionState.positionB)))
{
return true;
}
}
return false;
}
}
public class Robots {
static Position moveForward(Position oldPosition, int matrixSize, char orientation, char [][] inputMatrix){
// add possible new Position
Position newPosition= new Position();
//first return oldPosition in border positions in which the robot shouldn't move
if ((orientation=='O')&&(oldPosition.j==0))
return oldPosition;
if ((orientation=='E')&&(oldPosition.j==(matrixSize-1)))
return oldPosition;
if ((orientation=='N')&&(oldPosition.i==0))
return oldPosition;
if ((orientation=='S')&&(oldPosition.i==(matrixSize-1)))
return oldPosition;
if ((orientation=='O'))
newPosition.setIJ(oldPosition.i, oldPosition.j-1);
if ((orientation=='E'))
newPosition.setIJ(oldPosition.i, oldPosition.j+1);
if ((orientation=='S'))
newPosition.setIJ(oldPosition.i-1, oldPosition.j);
if ((orientation=='N'))
newPosition.setIJ(oldPosition.i+1, oldPosition.j);
//return oldPosition for positions in which the robot is blocked by *
if (inputMatrix[newPosition.i][newPosition.j]=='*'){
return oldPosition;
}
return newPosition; // if it got here, all ok
}
static char turnCounter (char orientation){
if(orientation=='N')
return 'O';
if(orientation=='O')
return 'S';
if (orientation=='S')
return 'E';
else
return 'N';
}
static char turnClock(char orientation){
if(orientation=='N')
return 'E';
if(orientation=='E')
return 'S';
if (orientation=='S')
return 'O';
else
return 'N';
}
static Position[] robotInitialPositions(char [][]inputMatrix){
Position [] helperArray = new Position[2];
int aux=0;
for (int i=0; i<(inputMatrix[0].length); i++)
for (int j=0; j<(inputMatrix[0].length); j++)
{
if((inputMatrix[i][j]=='N')||(inputMatrix[i][j]=='S')||(inputMatrix[i][j]=='O')||(inputMatrix[i][j]=='E'))
{
helperArray[aux]= new Position();
helperArray[aux].setIJ(i, j);
if (inputMatrix[i][j]=='N'){helperArray[aux].orientation='N'; }
if (inputMatrix[i][j]=='S'){helperArray[aux].orientation='S'; }
if (inputMatrix[i][j]=='E'){helperArray[aux].orientation='E'; }
if (inputMatrix[i][j]=='O'){helperArray[aux].orientation='O'; }
aux= aux+1;
}
}
return helperArray;
}
static Position[] getDestinies(char [][]inputMatrix){
Position [] helperArray = new Position[2];
int aux=0;
for (int i=0; i<(inputMatrix[0].length); i++)
for (int j=0; j<(inputMatrix[0].length); j++)
{
if((inputMatrix[i][j]=='D'))
{
helperArray[aux]= new Position();
helperArray[aux].i=i; helperArray[aux].j=j;
helperArray[aux].orientation='D';
aux=aux+1;
}
}
return helperArray;
}
static boolean [][]getUnvisitedMatrix(int matrixLength){
boolean[][] unvisitedMatrix = new boolean [matrixLength][matrixLength];
for (int i=0; i<matrixLength;i++)
for (int j=0; j<matrixLength; j++)
unvisitedMatrix[i][j]=false;
return unvisitedMatrix;
}
static Position[]getNewRobotPositions (Position oldR1Pos,Position oldR2Pos, String movement, char [][]inputMatrix){
Position[]newPositions = new Position[2];
Position newR1Pos = new Position();
Position newR2Pos = new Position();
if(movement.equals("counter")){
if (oldR1Pos.orientation=='N'){
newR1Pos.orientation='O';
}
if (oldR1Pos.orientation=='S'){
newR1Pos.orientation='E';
}
if (oldR1Pos.orientation=='E'){
newR1Pos.orientation='N';
}
if (oldR1Pos.orientation=='O'){
newR1Pos.orientation='S';
}
if (oldR2Pos.orientation=='N'){
newR2Pos.orientation='O';
}
if (oldR2Pos.orientation=='S'){
newR2Pos.orientation='E';
}
if (oldR2Pos.orientation=='E'){
newR2Pos.orientation='N';
}
if (oldR2Pos.orientation=='O'){
newR2Pos.orientation='S';
}
newR1Pos.i=oldR1Pos.i;
newR1Pos.j=oldR1Pos.j;
newR2Pos.i=oldR2Pos.i;
newR2Pos.j=oldR2Pos.j;
newPositions[0]=newR1Pos;
newPositions[1]=newR2Pos;
// System.out.println("MOVED COUNTERCLOCKWISE");
// System.out.println("previous Robot 1 position was "+oldR1Pos.i + ","+oldR1Pos.j + " orientation was " + oldR1Pos.orientation +
// " new Robot 1 position is " + newR1Pos.i + "," + newR1Pos.j+ " orientation is "+newR1Pos.orientation);
//
// System.out.println("previous Robot 2 position was "+oldR2Pos.i + ","+oldR2Pos.j + " orientation was " + oldR2Pos.orientation +
// " new Robot 2 position is " + newR2Pos.i + "," + newR2Pos.j+ " orientation is "+newR2Pos.orientation);
return newPositions;
}
if(movement.equals("clock")){
newR1Pos.i = oldR1Pos.i;
newR1Pos.j = oldR1Pos.j;
newR2Pos.i = oldR2Pos.i;
newR2Pos.j = oldR2Pos.j;
if (oldR1Pos.orientation=='N'){
newR1Pos.orientation= 'E';
}
if (oldR1Pos.orientation=='S'){
newR1Pos.orientation= 'O';
}
if (oldR1Pos.orientation=='E'){
newR1Pos.orientation= 'S';
}
if (oldR1Pos.orientation=='O'){
newR1Pos.orientation= 'N';
}
if (oldR2Pos.orientation=='N'){
newR2Pos.orientation= 'E';
}
if (oldR2Pos.orientation=='S'){
newR2Pos.orientation= 'O';
}
if (oldR2Pos.orientation=='E'){
newR2Pos.orientation= 'O';
}
if (oldR2Pos.orientation=='O'){
newR2Pos.orientation= 'N';
}
// System.out.println("MOVED CLOCKWISE");
// System.out.println("previous Robot 1 position was "+oldR1Pos.i + ","+oldR1Pos.j + " orientation was " + oldR1Pos.orientation +
// " new Robot 1 position is " + newR1Pos.i + "," + newR1Pos.j+ " orientation is "+newR1Pos.orientation);
/ /
// System.out.println("previous Robot 2 position was "+oldR2Pos.i + ","+oldR2Pos.j + " orientation was " + oldR2Pos.orientation +
// " new Robot 2 position is " + newR2Pos.i + "," + newR2Pos.j+ " orientation is "+newR2Pos.orientation);
newPositions[0]=newR1Pos;
newPositions[1]=newR2Pos;
return newPositions;
}
if(movement.equals("forward")){
//default case, if conditions not satisfied
newR1Pos.i=oldR1Pos.i;
newR1Pos.j=oldR1Pos.j;
newR1Pos.orientation = oldR1Pos.orientation;
newR2Pos.i=oldR2Pos.i;
newR2Pos.j=oldR2Pos.j;
newR2Pos.orientation = oldR2Pos.orientation;
if(oldR1Pos.orientation=='N'){
if(oldR1Pos.i-1>=0){ //doesn't exceed the upper border
//doesn't collide with '*'
if (inputMatrix[oldR1Pos.i-1][oldR1Pos.j]!='*'){
newR1Pos.i=oldR1Pos.i-1;
newR1Pos.j=oldR1Pos.j;
newR1Pos.orientation = oldR1Pos.orientation;
}
}
}
if(oldR1Pos.orientation=='S'){
if(oldR1Pos.i+1<inputMatrix.length){ //doesn't exceed the lower border
//doesn't collide with '*'
if (inputMatrix[oldR1Pos.i+1][oldR1Pos.j]!='*'){
newR1Pos.i=oldR1Pos.i+1;
newR1Pos.j=oldR1Pos.j;
newR1Pos.orientation = oldR1Pos.orientation;
}
}
}
if(oldR1Pos.orientation=='E'){
if(oldR1Pos.j+1<inputMatrix.length){ //doesn't exceed the right border
//doesn't collide with '*'
if (inputMatrix[oldR1Pos.i][oldR1Pos.j+1]!='*'){
newR1Pos.i=oldR1Pos.i;
newR1Pos.j=oldR1Pos.j+1;
newR1Pos.orientation = oldR1Pos.orientation;
}
}
}
if(oldR1Pos.orientation=='O'){
if(oldR1Pos.j-1>=0){ //doesn't exceed the left border
//doesn't collide with '*'
if (inputMatrix[oldR1Pos.i][oldR1Pos.j-1]!='*'){
newR1Pos.i=oldR1Pos.i;
newR1Pos.j=oldR1Pos.j-1;
newR1Pos.orientation = oldR1Pos.orientation;
}
}
}
//same for robot 2
if(oldR2Pos.orientation=='N'){
if(oldR2Pos.i-1>=0){ //doesn't exceed the upper border
//doesn't collide with '*'
if (inputMatrix[oldR2Pos.i-1][oldR2Pos.j]!='*'){
newR2Pos.i=oldR2Pos.i-1;
newR2Pos.j=oldR2Pos.j;
newR2Pos.orientation=oldR2Pos.orientation;
}
}
}
if(oldR2Pos.orientation=='S'){
if(oldR2Pos.i+1<inputMatrix.length){ //doesn't exceed the lower border
//doesn't collide with '*'
if (inputMatrix[oldR2Pos.i+1][oldR2Pos.j]!='*'){
newR2Pos.i=oldR2Pos.i+1;
newR2Pos.j=oldR2Pos.j;
newR2Pos.orientation=oldR2Pos.orientation;
}
}
}
if(oldR2Pos.orientation=='E'){
if(oldR2Pos.j+1<inputMatrix.length){ //doesn't exceed the right border
//doesn't collide with '*'
if (inputMatrix[oldR2Pos.i][oldR2Pos.j+1]!='*'){
newR2Pos.i=oldR2Pos.i;
newR2Pos.j=oldR2Pos.j+1;
newR2Pos.orientation=oldR2Pos.orientation;
}
}
}
if(oldR2Pos.orientation=='O'){
if(oldR2Pos.j-1>=0){ //doesn't exceed the left border
//doesn't collide with '*'
if (inputMatrix[oldR2Pos.i][oldR2Pos.j-1]!='*'){
newR2Pos.i=oldR2Pos.i;
newR2Pos.j=oldR2Pos.j-1;
newR2Pos.orientation=oldR2Pos.orientation;
}
}
}
//if robots collide in new positions, revert to their original positions
if ((newR1Pos.i==newR2Pos.i) && (newR1Pos.j==newR2Pos.j)){
//revert robot 1 position
newR1Pos.i=oldR1Pos.i;
newR1Pos.j=oldR1Pos.j;
newR1Pos.orientation = oldR1Pos.orientation;
//revert robot 2 position
newR2Pos.i=oldR2Pos.i;
newR2Pos.j=oldR2Pos.j;
newR2Pos.orientation = oldR2Pos.orientation;
}
newPositions[0] = newR1Pos;
newPositions[1] = newR2Pos;
// System.out.println("MOVED FORWARD");
// System.out.println("previous Robot 1 position was "+oldR1Pos.i + ","+oldR1Pos.j + " orientation was " + oldR1Pos.orientation +
// " new Robot 1 position is " + newR1Pos.i + "," + newR1Pos.j+ " orientation is "+newR1Pos.orientation);
//
// System.out.println("previous Robot 2 position was "+oldR2Pos.i + ","+oldR2Pos.j + " orientation was " + oldR2Pos.orientation +
// " new Robot 2 position is " + newR2Pos.i + "," + newR2Pos.j+ " orientation is "+newR2Pos.orientation);
} //end movement.equals("forward")
return newPositions;
}
//1 procedure BFS(Graph,source):
//2 create a queue Q
//3 enqueue source onto Q
//4 mark source
//5 while Q is not empty:
//6 dequeue an item from Q into v
//7 for each edge e incident on v in Graph:
//8 let w be the other end of e
//9 if w is not marked:
//10 mark w
//11 enqueue w onto Q
static void BFS (char [][] inputMatrix){
ArrayList<TransitionState> transitionStatesArray = new ArrayList<TransitionState>();
int moveCounter=0; //turns and forward movements add here
int tempMoveCounterRobot1=0; int tempMoveCounterRobot2=0;
int maxMoveCounter=0;
PositionsAndCounter positionsAndCounter= new PositionsAndCounter();
Queue <PositionsAndCounter>queue = new LinkedList<PositionsAndCounter>();
Position robotInitial[] = robotInitialPositions(inputMatrix); //get source
positionsAndCounter.positionPair=robotInitial; //used to encapsulate the positions with a counter to output
positionsAndCounter.counter=0;//first initialize to 0
Position destinies[] = getDestinies(inputMatrix); //get destinies
TransitionState firstTransitionState = new TransitionState();
firstTransitionState.positionA=robotInitial[0];
firstTransitionState.positionB=robotInitial[1];
transitionStatesArray.add(firstTransitionState);
//mark transition used , if the transition is new, it should be queued
queue.add(positionsAndCounter);
String [] movement = {"forward", "counter", "clock"};
//possible movements inside inputMatrix
outer: while (!queue.isEmpty()){ //while queue is not empty
PositionsAndCounter v= queue.poll(); //dequeue an item from Q into V
for(int k = 0; k<3; k++){ //for each edge e incident on v in Graph:
Position[] newRobotPositions = getNewRobotPositions(v.positionPair[0], v.positionPair[1], movement[k], inputMatrix);
TransitionState newTransitionState = new TransitionState();
newTransitionState.positionA=newRobotPositions[0];
newTransitionState.positionB=newRobotPositions[1];
if(!transitionStatesArray.contains(newTransitionState)){ //if the transition state is new add and enqueue new robot positions
transitionStatesArray.add(newTransitionState);
//if transition is new then queue
PositionsAndCounter newPositionsAndCounter = new PositionsAndCounter();
newPositionsAndCounter.positionPair=newRobotPositions;
newPositionsAndCounter.counter = v.counter +1;
queue.add(newPositionsAndCounter);
}
inputMatrix[v.positionPair[0].i][v.positionPair[1].j]='.';
inputMatrix[v.positionPair[1].i][v.positionPair[1].j]='.';
//inputMatrix[v[0].i][v[0].j]='.'; // mark old position of robot 1 with .
//inputMatrix[v[1].i][v[1].j]='.'; // mark old position of robot 2 with .
//update new robot positions
inputMatrix[newRobotPositions[0].i][newRobotPositions[0].j]= newRobotPositions[0].orientation;
inputMatrix[newRobotPositions[1].i][newRobotPositions[1].j]= newRobotPositions[1].orientation;
//check if solution has been found
if
(
((destinies[0].i==newRobotPositions[0].i)&&(destinies[0].j==newRobotPositions[0].j) //robot in 0 arrived to destiny
|| (destinies[1].i==newRobotPositions[0].i)&&(destinies[1].j==newRobotPositions[0].j))// in 0 or 1
&& //and
((destinies[0].i==newRobotPositions[1].i)&&(destinies[0].j==newRobotPositions[1].j) //robot in 1 arrived to destiny
|| (destinies[1].i==newRobotPositions[0].i)&&(destinies[1].j==newRobotPositions[0].j))//in 0 or 1
) //end if
{
System.out.println("robots arrived at destinies");
System.out.println("robot 1, starting at " + robotInitial[0].i + "," + robotInitial[0].j
+ " is in " + newRobotPositions[0].i + ","+ newRobotPositions[0].j);
System.out.println("robot 2, starting at " + robotInitial[1].i + "," + robotInitial[1].j
+ " is in " + newRobotPositions[1].i + ","+ newRobotPositions[1].j);
System.out.println("movements: " + (v.counter));
return;
//break outer;
}
}
}
System.out.println("robots can never arrive at their destinies");
System.out.println(-1);
}
static void printInputMatrix(char [][] inputMatrix){
for (int i=0; i<inputMatrix[0].length;i++)
for(int j=0; j<inputMatrix[0].length;j++)
{
System.out.print(" "+inputMatrix[i][j]+" ");
if(j==inputMatrix[0].length-1){System.out.println("");}
}
}
public static void main(String[] args) throws IOException {
// System.out.println("Test transition checker");
// Position p1 = new Position();
// p1.i=1;
// p1.j=1;
// p1.orientation='N';
// Position p2 = new Position();
// p2.i=1;
// p2.j=2;
// p2.orientation='N';
// Position p3 = new Position();
// p3.i=1;
// p3.j=1;
// p3.orientation='N';
// Position p4 = new Position();
// p4.i=1;
// p4.j=1;
// p4.orientation='N';
//
// TransitionState transitionChecker1 = new TransitionState();
// transitionChecker1.positionA=p1;
// transitionChecker1.positionB=p2;
//
// TransitionState transitionChecker2 = new TransitionState();
// transitionChecker2.positionA=p1;
// transitionChecker2.positionB=p2;
//
//
// ArrayList<TransitionState> arrayTransitions = new ArrayList<TransitionState>();
// arrayTransitions.add(transitionChecker1);
// System.out.println("Test contains? " + arrayTransitions.contains(transitionChecker2));
BufferedReader br = new BufferedReader(new FileReader(new File("input.txt")));
char [][] inputMatrix;
String line;
char [] lineAsCharArray;
int matrixSize;
while(true){
line = br.readLine();
matrixSize=Integer.parseInt(line);
inputMatrix = new char [matrixSize][matrixSize];
if (matrixSize==0){ // end outer looping
break;
}
else { //begin inner looping
for (int i=0; i<matrixSize; i++){
line = br.readLine();
inputMatrix[i] =line.toCharArray();
}
//matrix loaded
BFS(inputMatrix);
}
}
}
}
class PositionsAndCounter {
Position[] positionPair;
int counter;
PositionsAndCounter() {
positionPair = new Position[2];
counter=0;
}
}
Problems:
1) On the first input.txt file, it finds 9 movements to find the solution of the first course (when they should be 8) and 6 to find the solution of the second course (when it should be 3) though it correctly prints out -1 for the last (impossible) course configuration.
2) On the second input.txt file, professor says it should print -1 and -1 for the to first courses, though my program finds a plaussible solution for the second case and a bizarre one for the first (this is where I think a more experienced debugger could help, I'm at a loss tracking the reason for the displaced destiny output on the first case). Are the outputs proposed by my professor right? My algorithm is also getting stuck on that case where 46 should be printed.
The are 2 careless copy and paste problems causes the code not working,
1, in the clockwise turning part:
if (oldR2Pos.orientation == 'E') {
newR2Pos.orientation = 'O';
}
This is wrong... it should be a direct copy and paste from the above block
if (oldR2Pos.orientation == 'E') {
newR2Pos.orientation = 'S';
}
Yet you missed it.
Another problem is actually in the end condition testing block
//check if solution has been found
if
(
((destinies[0].i==newRobotPositions[0].i)&&(destinies[0].j==newRobotPositions[0].j) //robot in 0 arrived to destiny
|| (destinies[1].i==newRobotPositions[0].i)&&(destinies[1].j==newRobotPositions[0].j))// in 0 or 1
&& //and
((destinies[0].i==newRobotPositions[1].i)&&(destinies[0].j==newRobotPositions[1].j) //robot in 1 arrived to destiny
|| **(destinies[1].i==newRobotPositions[0].i)&&(destinies[1].j==newRobotPositions[0].j)**)//in 0 or 1
) //end if
The last part (code highlighted) should be
(destinies[1].i==newRobotPositions[1].i)&&(destinies[1].j==newRobotPositions[1].j)
It is obviously an copy and paste but forget to change error. The logic is a little bit hard to understand, but works,
(A in X or B in Y) and (A in Y or B in X)
Although it is the same (logically not exactly the same but it some how works for your case as A and B cannot occupy the same location), it is much clearer if you use
(A in X and B in Y) or (A in Y and B in X)
Apart from the fatal errors stated above, your program has a few other issues need to addressed.It looks like you are a university student taking Computer science, please, read the given source code before coding: TransistionState class is not used at all but you created your own PositionsAndCounter, turning logic is implemented twice, if you didn't rewrite the turning code, and use the one given, you won't commit problem 1.... If I were your professor, i may fail you on that. Plan your solution well before hitting the keyboard, and make sure your code is clear and readable as plan english, if you stare at your source code for 5 min and cannot figure out what the block of code is for, may be you didn't structure it correctly.
The listing below is an example solution for your question:
import java.awt.Point;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class DualRobot {
public enum Orientation{
E(1, 0), S(0, 1), O(-1, 0), N(0, -1);
public final int dx, dy;
private Orientation(int dx, int dy){
this.dx = dx;
this.dy = dy;
}
public Orientation left(){
return Orientation.values()[(this.ordinal() + 3) % 4];
}
public Orientation right(){
return Orientation.values()[(this.ordinal() + 1) % 4];
}
public static Orientation valueOf(char c){
for(Orientation o : Orientation.values()){
if(o.toString().equalsIgnoreCase("" + c)) return o;
}
return null;
}
}
public enum Action {FORWARD, COUNTER_CLOCKWISE, CLOCKWISE}; // F: forward, L: Counter clockwise, R: clockwise
private static class Robot{
Point position;
Orientation orientation;
public Robot(Robot r){
this.position = new Point(r.position);
this.orientation = r.orientation;
}
public Robot(int x, int y, Orientation orientation){
this.position = new Point(x, y);
this.orientation = orientation;
}
public void move(Action action, char[][] map){
switch (action) {
case FORWARD:
Point nextPosition = new Point(position);
nextPosition.translate(orientation.dx, orientation.dy);
if(isValidPosition(nextPosition, map)) position = nextPosition;
break;
case COUNTER_CLOCKWISE:
this.orientation = this.orientation.left();
break;
case CLOCKWISE:
this.orientation = this.orientation.right();
break;
}
}
#Override
public boolean equals(Object obj) {
if (obj instanceof Robot) {
Robot r = (Robot) obj;
return r.position.equals(this.position) && r.orientation == this.orientation;
}
return super.equals(obj);
}
#Override
public int hashCode() {
return orientation.ordinal() + position.x * 10 + position.y * 1000;
}
private boolean isValidPosition(Point p, char[][] map){
return p.x >= 0 && p.x < map[0].length
&& p.y >= 0 && p.y < map.length
&& map[p.y][p.x] != '*';
}
}
private static class State{
private Robot a, b;
private int counter;
public State(Robot a, Robot b, int counter) {
this.a = new Robot(a);
this.b = new Robot(b);
this.counter = counter;
}
public List<State> nextStates(char[][] map){
List<State> states = new ArrayList<State>();
for(Action action : Action.values()){
State s = new State(this.a, this.b, this.counter + 1);
s.a.move(action, map);
s.b.move(action, map);
if(!s.a.position.equals(s.b.position)){ // Test for collision
states.add(s);
}
}
return states;
}
#Override
public boolean equals(Object obj) {
if (obj instanceof State) {
State state = (State) obj; // Consider the state to be the same if the 2 robots are at identical location and orientation
return (this.a.equals(state.a) && this.b.equals(state.b))
|| (this.a.equals(state.b) && this.b.equals(state.a));
}
return super.equals(obj);
}
#Override
public int hashCode() {
// The quality of this hashCode can affect the program's speed
// Multiply is transitive, so if you swap a and b, the hashcode is the same
return a.hashCode() * b.hashCode();
}
}
public static void main(String[] args) throws IOException {
BufferedReader input = new BufferedReader(new FileReader("input.txt"));
int size;
while((size = Integer.parseInt(input.readLine())) > 0){
// Load the data;
char[][] map = new char[size][size];
for (int i = 0; i < size; i++) {
map[i] = input.readLine().toCharArray();
}
// Construct initial state
List<Robot> robots = new ArrayList<Robot>();
List<Point> destinations = new ArrayList<Point>();
for(int i = 0; i < size; i ++){
for(int j = 0; j < size; j ++){
Orientation orientation = Orientation.valueOf(map[i][j]);
if(orientation != null){
robots.add(new Robot(j, i, orientation));
}else if(map[i][j] == 'D'){
destinations.add(new Point(j, i));
}
}
}
System.out.println(BFSSearch(map, new State(robots.get(0), robots.get(1), 0), destinations));
}
}
private static int BFSSearch(char[][] map, State initialState, List<Point> destinations) throws IOException{
List<State> queue = new LinkedList<State>(); // Array list is slightly more efficient
queue.add(initialState); // Initial state
Map<State, Boolean> testedStates = new HashMap<State, Boolean>();
while(queue.size() > 0){
State currentState = queue.remove(0);
if(testedStates.containsKey(currentState)) continue;
// Testing for end condition
if((currentState.a.position.equals(destinations.get(0)) && currentState.b.position.equals(destinations.get(1)))
|| (currentState.a.position.equals(destinations.get(1)) && currentState.b.position.equals(destinations.get(0)))){
return currentState.counter;
}
testedStates.put(currentState, true);
queue.addAll(currentState.nextStates(map));
}
return -1;
}
}
This program spit out the final answer in around 10 seconds.
The main difference is I used an hash table to store the tested states to improve the speed, thus the quality of the hash function would have an effect on the speed.
Recommended reading: hash table, DRY principle.