I'm trying to add newly created objects to a grid and to a graph. Specifically, how to efficiently add nodes to a graph with a for loop. They grid has been set up as a double array, in order to update the initial view. (The object grid is the model and updates the view via push). I also set up a HashMap using the items in i and j within the for loops in order to define the object's keys. However, in order to set up a graph in order to later calculate the shortest path from node to node, I need to add these nodes to a Graph. I would like to use Djikstra's algorithm to calculate the shortest path. I could create a conditional statement to define what are corner nodes and edge nodes in the grid and define what items would have bi directional edges but this seems to be a 'long cut'. Is there any way to add nodes to a graph with a pre determined matrix size, such as for example 20 X 20, similar to a double array?
Below is the constructor code on how I am creating the first two items (creating double array and HashMap):
// **Constructor
// Construct a new Grid object. Sets up a HashMap of square object in order efficiently to get
// and add Square objects later.
public ObjectGrid(Integer width, Integer height)
{
// View
gui = new GUI(); // Instantiate GUI
boardView = new BoardView(width,height); // Instantiate BoardView
// Initialize Gui, set time and add simulation event listener to model (ObjectGrid)
gui.initGUI(BoardView);
gui.addSimulationEventListener(this);
// Initialize turnInSteps variable count to 0
turnInSteps = 0;
// Initialize numberOfDays variable count to 0
numberOfDays = 1;
// Instantiate HashMap
objectHashMap = new HashMap();
// Declare new object grid using double array of type objects.
// Size determined by parameter Integer values in constructor
myObjectGrid = new ObjectType[width][height];
// Instantiate Graph object
Graph graph = new ListGraph();
// For loop sets up the initial grid with ObejctType using a double array. After
// the completion of this loop, the grid will have XXX objects in the grid
// each with a reference to an object. Objects are also added
// to HashMap using coordinates as keys and square objects as values.
for(int i = 0; i < width; i++)
{
// Iterate through rows
for(int j = 0; j < height; j++)
{
// Iterate through columns
myObjectGrid[i][j] = new ObjectType(); // Instantiate a new Square at each row/column using default constructor
gridView.addObjectView(myObjectGrid[i][j].getObjectView(), i, j); // Add object view to each row/column placement
String hashMapKey = (i + ", " + j); // Use values from i and j as Key for objects HashMap
myObjectGrid[i][j].setID(hashMapKey); // Add ID's for each ObjectView to display in object using values from i and j
objectHashMap.add(hashMapKey, myObjectGrid[i][j]); // Add object to HashMap using string value of coordinates as key
listGraph.add(myObjectGrid[i][j]);
// Pseudo code
if (i != (width-height) && (j != height) etc)
{
listGraph.addBidirectionalEdge(mySquareGrid[i][j], (mySquareGrid[i][j+1]), 1);
listGraph.addBidirectionalEdge(mySquareGrid[i][j], (mySquareGrid[i+1][j]), 1);
listGraph.addBidirectionalEdge(mySquareGrid[i][j], (mySquareGrid[i+1][j+1]), 1);
}
}
}
}
With the unit tests that I did the vertices in the graph return null.
The reason is the following lines:
listGraph.addBidirectionalEdge(mySquareGrid[i][j], (mySquareGrid[i][j+1]), 1);
listGraph.addBidirectionalEdge(mySquareGrid[i][j], (mySquareGrid[i+1][j]), 1);
listGraph.addBidirectionalEdge(mySquareGrid[i][j], (mySquareGrid[i+1][j+1]), 1);
You are in the middle of initialization of mySquareGrid and create edges with nodes from future. These nodes with j+1 and i+1 are nulls at this moment.
Try the simplest solution - after grid initialization do the same cycling through grid and create graph's edges.
Also, you can try to change it to the following:
listGraph.addBidirectionalEdge(mySquareGrid[i][j-1], (mySquareGrid[i][j]), 1);
listGraph.addBidirectionalEdge(mySquareGrid[i-1][j], (mySquareGrid[i][j]), 1);
listGraph.addBidirectionalEdge(mySquareGrid[i-1][j-1], (mySquareGrid[i][j]), 1);
Related
so I am new to programming and having some issues with classes. I am using the lens next brick. There is a class from the libuary called Node. It takes a X and Y. Like so:
Node nodeNameOne = new Node(2,3);
What I want to do:
I have a 12 by 12 array. And for each position in the array I want to get its X and Y and create a new node. The problem is I want to automatically change the " nodeNameOne" .
My solution was to create a intiger variable and increment it, then do a .to string and use that as the nodes name by when I use my intiger variable name it uses the name of the variable not the value within the variable.
I have looked at other posts that sujest using "Class.newInstance" but I can't get this to work.
Any help is appreciated.
Thanks
UPDATE:
I have a 12 by 12 array. I will scan the array and when I detect a 0 in any position of the array i want to create a new Node with the X and Y of the array position.
because it is a 12 by 12 array there are 144 possible places that 0 can occur.
therefore the code that is needed to make a new is node is:
Node nodename = new Node(x,y);
I want to automate the instance name: "nodeName" to use a string variable, that I will get from:
int nameOfNode= 0;
String temp = Integer.toString(nameOfNode);
Node temp = new Node(x,y);
nameOfNode++;
the error i get is that it says that temp is already used, but i know that. i want it to use the value of temp not the name "temp". - i hope this is clearer.
What you want is probably an array. A twodimensional array is a mapping from (i,j) --> Node[i][j]:
// Step 1 and 2: Create and add nodes
Node nodes[12][12];
for (int i = 0; i < 12; i++) {
for (int j = 0; j < 12; j++) {
nodes[i][j] = new Node(i, j);
mesh.add(nodes[i][j], 0);
}
}
You can then refer to a node by using numbers (or integer variables):
// Step 3: Connect nodes:
mesh.connect(nodes[2][3], nodes[2][4]);
mesh.connect(nodes[2][3], nodes[3][3]);
mesh.connect(nodes[2][4], nodes[2][5]);
...
I think you want a java.util.Map;
A Maps is an object that maps keys to values. A map cannot contain duplicate keys; each key can map to at most one value. You can use Strings "x,y" as keys for your nodes objects then you can retrieve your node objects by strings the way you want.
you can use an map like this:
final Map<String,Node> nodesMapedByName = new HashMap<>();
(...)
//asssuming x and y are integers, this will create an
//new node for x and y and put it in the map using the string
//"x,y" as key
nodesMapedByName.put(x + "," + y, new Node(x,y);
(...)
//asssuming x and y are integers, this will retrieve the node
//mapped by the String "x,y"
final Node someNome = nodesMapedByName.get(x + "," + y);
I have a list (boxlist) of 6 boxes, each with a count of 1 object per box (num_objects). Each box exists in a geography context (are located at specific latitude and longitude coordinates):
//iterate through each of the boxes in the list (6)
for (int i = 0; i < boxlist.size(); i++){
//get the first box... then second box... etc (call it target box)
Box targetbox = boxlist.get(i);
Context context = ContextUtils.getContext(targetbox);
Geography<Object> geography = (Geography)context.getProjection("Geography");
Geometry geom = geography.getGeometry(targetbox);
//get the coordinates of the target box
Coordinate coord = geom.getCoordinates()[0];
//for each of the 6 boxes, get the number of objects in the target box
double num = targetbox.getNum_objects();
// print the number of objects in each box (1)
System.out.println(num);
//create random utility
Random random = new Random();
// create the same number of BoxObjects as the num_objects in the box and place them in the geography at the same location as the box they are in (take them out of the box)
for (int j = 0; j < num; j++) {
boolean randomBoolean = random.nextBoolean();
boolean anotherBoolean = false;
BoxObject obj = new BoxObject(context, geography, randomBoolean, anotherBoolean);
context.add(obj);
// move to the object to the same coordinates of its box
geography.move(obj, new GeometryFactory().createPoint(coord));
}
}
My loop is correctly counting that there are 6 boxes with 1 object in the box which should create 6 objects, but its creating 12 objects. How can I fix this?
Note: in the actual simulation, boxes may have more than one object.
My problem was that this code was nested in an Agent class. I had two Agents and it was running the method twice, once for each agent (producing double the objects). When I moved this code to the main model class (since technically it doesn't have anything to do with the agents), it worked perfectly.
You have a targetbox with an object in it.
Box targetbox = boxlist.get(i);
You also get the context of the targetbox that has an object in it.
Context context = ContextUtils.getContext(targetbox);
You then add another object to that same context. Whatever BoxObject does, as you pass it the context, it should remove previous objects from the context so that you only have the newly created object(s) in the result.
This question is regarding libGDX, but I think it's in fact more Java/algorithm related.
Part of my game includes placing 20 elements out of predefined 30 elements list on a screen (so effectively a coordinate system) in 20 partially-predefined places.
By partially predefined I mean that they are predefined for each screen, but there can be dozens of screens, so they can be as well treated as random.
The elements will be selected randomly, but the elements close to each other must be unique. By close I mean in range of some arbitrary defined distance X. Effectively each place will have around 3 'close neightbours'.
The best way I can think of so far is as follows:
Calculate the distance between all places. If a given distance between A and B is lower than X put two entries in a map - one (A,B) and one (B,A)
Now start filling the places with elements
For each place create a list with all neightbours using the map from point 1 (let's call it N-list)
For each place create a temporary list with all possible (30) elements (let's call it E-list)
Get a random element from E-list
Iterate through N-list. For each place from the list get an element currently there (if there's any). For this a (place, element) map is needed, so it will be filled as the algorithm progresses.
If the found element is equal to the current random element remove this element from E-list and this place from N-list and come back to point 5
Proceed until all places are filled
Step 1 is in fact a separate algorithm, that probably can be tweaked, ex. if we calculated the A->B distance we don't need to calculate B->A, but that needs an additional map to store calculation info, etc.
I would like to know what you think of this way and if you have any ideas for a better one.
Thanks in advance for your answers.
P.S. Perhaps the terms I used could be better chosen, but I'm not a native speaker and I don't know English math terms :-)
Ok, I think I understood your solution and this is what I thought of initially. But I think it can be slightly optimized by eliminating extra pairs and maps (or maybe not :)
First, create a map of locations where key is location position (or the location itself) and value is a list of location's parents who fall within the close range. Yes it will have multiple parents, not children, it is actually the same but parents are more fitting here as we'll see.
ArrayList<Place> place_list; // your list of places here
ArrayList<Element> element_list; // your list of elements here
HashMap<Place,ArrayList<Place>> parent_map = new HashMap<Place,ArrayList<Place>>;
ArrayList<Place> a;
for (int i = 0; i < place_list.size() - 1; i++) {
Place place1 = place_list.get(i);
for (int j = i + 1; j < place_list.size(); j++) {
Place place2 = place_list.get(j);
int dist = getDistance(place1, place2);
if (dist > DISTANCE_THRESHOLD) continue;
// if this place is within range,
// add parent place to its list and put/update it to the map
a = parent_map.get(place2);
if (a == null) a = new ArrayList<Place>();
a.add(place1);
parent_map.put(place2, a);
}
}
Now we have a map of all places that have parents. Next we do the following: if place does not have parents, it can choose any random element freely. If it does have parents, it checks what elements parents own and reduces the available set of elements. After the set was reduced, any random element can be chosen from it.
HashMap<Place,Element> used_place_map = new HashMap<Place,Element>(); // key is place, value is assigned element
ArrayList<Element> tmp_element_list;
for (i = 0; i < place_list.size(); i++) {
Place place = place_list.get(i);
a = parent_map.get(place);
if (a == null) { // this place has no parents, use elements freely
tmp_element_list = element_list;
} else { // if it has parents, they have already registered their elements in used_place_map
tmp_element_list = new ArrayList<Element>();
// create list of available elements, lame
for (j = 0; j < element_list.size(); j++) tmp_element_list.add(element_list.get(j));
// now reduce it, very lame, sorry
for (Place pl : a) {
Element used_element = used_place_map.get(pl);
for (j = 0; j < tmp_element_list.size(); j++) {
if (used_element.equals(tmp_element_list.get(j)) {
tmp_element_list.remove(j);
break;
}
}
}
}
// finally, get the random index on (probably reduced) array
int element_id = Random.nextInt(tmp_element_list.size());
Element element = element_list.get(element_id);
// store our choice as future parent
used_place_map.put(place, element);
}
Given a matrix filled in with all its values, there's the need of pulling out data randomly in order to create a random matrix (intialized with null values each position). The issue lies while checking if a position (within the randomMatrix) is different from null, as shown below:
public void randomLogic(String[][] givenMatrix){
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
int positioni = this.randInt(0, 1);
int positionj = this.randInt(0, 1);
int x = this.randInt(0, 3);
int y = this.randInt(0, 2);
/*In here lies the reported issue while checking if empty. */
while (!this.randomMatrix[x][y].isEmpty()) {
x = this.randInt(0, 3);
y = this.randInt(0, 2);
this.randomMatrix[x][y] = givenMatrix[positioni][positionj];
}
}
}
}
I've also tried with the following: while(this.randomMatrix[x][y] != null) and the code breaks down right away. All the solving-logic work out as expected (because if I ommit that part it works with flaws but works) the only problem is that validation. Regardless of what position is being evaluated it always stops working.
Is there any other way of checking a matrix position value?
are you trying to pull random values (and consequently, some will be repeated) from a givenMatrix OR do you want to specifically randomize the givenMatrix?
If it's the latter, I would approach it differently.
First of all, gather all values of the givenMatrix in one linear-array or list.
Then, you can randomize this array, and you'll be left with a big array of rows*columns items, with all the values from the original matrix already randomized.
Then, you can systematically fill the new randomized matrix, taking each element of the array in order, till you complete each row and column of the new matrix.
I would choose this approach, because it's easier, and it will finish in a fixed number of steps; rather than filling random positions, because maybe you land 2 times in the same place to fill, and you'll have to randomize until you hit all the spots.
(Also, if you don't care of repeating the values for the new matrix, then instead of taking each element of the randomized array, you can simply pick a random position of this array each time)
Have you declared String[][] randomMatrix as a class level member variable? If you have declared the randomMatrix correctly then the isEmpty() and != null checks should work.
I am trying to write a 3x3 square-shift puzzle solver in Java. However, I'm stuck on the part where I shift the blocks around - I kept ending up with a bunch of new empty spaces with the algorithm I was using. After some testing I determined that it was because, in spite of my use of the clone() command, v's array is still being affected when I change "current". Does anyone know why this is and how I can fix it? I thought that after using clone, I could change the new array without affecting the old one.
if (!rightwall)
{
int[][] current = v.state.clone();
current[x][y] = current[x][y + 1];
current[x][y + 1] = 0;
State w = new State(current);
w.distance = v.distance + 1;
w.path = v;
System.out.println("Right Shift:");
w.print();
q.insert(w);
}
State is a class that represents a two-dimensional array along with some properties - the first part of the code for State is
public class State {
int[][] state = new int[3][3];
int distance = 0;
boolean known = false;
State path = null;
State(int[][] newstate){
state = newstate.clone();
}
v is the state representing the current position. w would then be an "adjacent" position created after switching the empty space with the space next to it.
q is a queue.
In your State class, you need to make sure that all properties are deep copied.