Checking an object list with the same object list - java

I have a problem with checking objects in a list with the same objects. I have an object list with different type of objects like, bullets, enemies and random background objects.
Now I want to check if some objects collide with each other, like bullets with enemies.
The problem is that when I put the same for loop within the for loop with both the same objects, i don't get the behavior i was expecting... Anyone knows a better way to handle this?
The left image shows that bullets are not moving anymore, the right show the situation when i remove the loop within the loop.
https://www.dropbox.com/s/92tnxizxdneqgz3/ss1.png
EDIT: The different strings are read from a script, I am aiming for maximal flexibility. That is also the reason why I don't want different collections of each type of object. The collision was working when I did that.
for (Object o : objects) {
if (o.behavior.equals("aggressive")) {
o.aggressive(ship.x, ship.y, ship.z);
}
if (o.behavior.equals("missile")) {
o.missile();
if (o.type.equals("bullet_player")) {
for (Object n : objects) {
//doesn't matter what i put here
}
}
}
}
Solution:
I got it working, the problem appears to lie in nesting an for loop of an arraylist within an other. What i finally did is this: I cloned the arraylist, check the cloned list with the original object list, i check if the object is the same and if not I do the collision check.

The standard approach is this, which will compare each pairing once:
for(int i=0; i<objects.size(); i++)
for(int j=i+1; j<objects.size(); j++)
//.... compare objects[i] and objects[j] for collision etc
As your game world gets more complex, consider placing objects in a spatial index instead.

The nested loop shouldn't be a problem. The following example, where I have some iterators running on the same collection, works as expected:
public static void main(String a[]) {
List<String> strings = Arrays.asList("a", "b", "c");
for (String s: strings) {
for (String t:strings) {
System.out.println(s + "/" + t);
}
}
}
Looks to me like the problem is within your collision detection. You may have false positives (collisions detected where no collision happened)

Related

Including new elements in for:each

Before I start my question, i'd like to mention that i DID read up some other topics and i tried around a bit but im just really confused atm so i figured i'd just ask.
So what i wanna do is use for each through a Set and within that for each, add elements to that set and also iterate through those.
The solution I found elsewhere was the following:
for(Object obj : new HashSet<Object>(oldSet))
I tried that, however I keep missing some of the last elements i'd like to match so im not really sure if this is the right approach in the first place?
To be specific, this is basically what my code looks like:
for(Position pos : new HashSet<Position>(oldSet){
for(Delta delta : deltas){
if(board.getTokenAt(pos.plus(delta).equals(initial){
hitList.add(pos.plus(delta);
oldSet.add(pos.plus(delta);
}
}
oldSet.remove(pos);
}
Again, I'd just like to know if my approach is wrong or there must be an error elsewhere in my code so i know what to look at.
Thanks beforehand!
You can't really add to a data structure while iterating over it, that is almost guaranteed to have unexpected results.
However, there is a simple enough solution to your issue. Just process each item recursively when you find that it needs to be added, and add it to a separate List. At the end of iteration, add everything in the List to the main Set. This avoids the issue of adding during iteration while still allowing you to to process the newly added items.
It would look something like this:
List<Position> toAdd = new LinkedList<>();
for(Position pos : oldSet){
for(Delta delta : deltas){
addIfGoodAndRecurse(pos, delta, toAdd);
}
}
And then you can use this helper method to add the item if it meets your conditions and also recursively process added items. Note you will need to change the method signature to pass in your board, initial, and hitList if they are local variables. I didn't know their types or whether they were global variables or fields, so I couldn't really add them in the example.
private void addIfGoodAndRecurse(Position pos, Delta delta, List<Position> toAdd) {
Position toCheck = pos.plus(delta);
if(board.getTokenAt(toCheck.equals(initial))) {
hitList.add(toCheck);
toAdd.add(toCheck);
for (Delta recursionDelta : deltas) {
addIfGoodAndRecurse(toCheck, recursionDelta, toAdd);
}
}
}
I don't have your code, so I can't test this. The idea should work fine, but you may need to make slight modifications.
You can iterate through new elements added to a list that you're iterating if you add them to the end of the list and iterate through it using an index and the get() method, not through an Iterator. You can also use the Set as you are doing now, but only to make sure you only add unique items to your collection.
List<Position> list = new ArrayList<>(oldSet);
for (int i = 0; i < list.length; ++i) { // NB list.length could be different each time
Position pos = list.get(i);
for(Delta delta : deltas){
if(board.getTokenAt(pos.plus(delta).equals(initial){
hitList.add(pos.plus(delta));
if (oldSet.add(pos.plus(delta))) // Check if it already exists in the list
list.add(pos.plus(delta));
}
}
oldSet.remove(pos);
}

Struggling to understand how to loop over a list

I'm currently developing a POS till system as a university assignment and I'm completely stumped on a for loop that I need to implement to save any data that gets added to the system by the end user. The save() function is meant to save any data put into the program to 1 of 2 .txt files (stock or till).
I've currently built the save function for each of the different instance variables but when it runs through the save() method it'll only run once (obviously) and I'm having a hard time understanding how to implement a sample for loop as a solution.
Here's my current progress:
public void save() throws IOException {
// IMPLEMENTATION
PrintWriter outfileStock = new PrintWriter(new FileWriter(SHOP_STOCK_DATA_FILE));
outfileStock.println(barcode);
outfileStock.println(cost);
outfileStock.println(quantity);
outfileStock.close();
PrintWriter outfileTill = new PrintWriter(new FileWriter(SHOP_TILL_DATA_FILE));
outfileTill.println();
outfileTill.println();
outfileTill.println();
outfileTill.close();
}
The sample for loop we've been given (from a worksheet that lead up to this assignment is this:
public void save(String fileName) throws IOException {
PrintWriter outfile = new PrintWriter(new FileWriter(fileName));
outfile.println(type);
outfile.println(face);
outfile.println(hair);
outfile.println(powerPoints);
outfile.println(loot.size());
for (Treasure treasure : loot) {
outfile.println(treasure.getName());
outfile.println(treasure.getValue());
}
outfile.close();
While I'm not asking for the code to be written for me, it would be great if somebody to explain how the
for (Treasure treasure : loot) {
outfile.println(treasure.getName());
outfile.println(treasure.getValue());
}
loop works. I can provide some more info if needed, fairly new to Java so not sure how much is needed to understand.
loot is an ArrayList that contains Treasure objects.
for (Treasure treasure : loot) {
outfile.println(treasure.getName());
outfile.println(treasure.getValue());
}
loops over each one of the Treasure objects (each one of which are temporarily assigned to treasure) by this line of code:
for (Treasure treasure : loot) {
which means (for every Treasure object in loot which you call treasure)
and gets (for each) their name (treasure.getName()) and their values (treasure.getValue()).
:
stands for the enhanced for-loop which was introduced in Java SE 5.0. See more info here:
https://blogs.oracle.com/CoreJavaTechTips/entry/using_enhanced_for_loops_with
Basically, instead of
for (int i=0; i < array.length; i++) {
System.out.println("Element: " + array[i]);
}
you can now do
for (String element : array) {
System.out.println("Element: " + element);
}
loot seems to be a List of some sort. What the for loop will do is take each element of this list and return them to you as a single object called treasure. when you get this element back you can treat is as a normal Treasure object. In your case it seems to be writing the treasure name and value to a file.
For each loop
This is basic Java. The variable loot is something that can be iterated over. It's either an array or one of the container classes like ArrayList. It contains Treasure objects.
For each element in the loot array, those two lines of code are executed.
loot is a List. Therefore using this enhanced for loop it fetch the each element in each iteration and assign it to the treasure variable. But here you don't have access to the previous element of the list in a given time. If you use other for loop for(int x=0; x < size ; x++ ) in each iteration you can access previous or next element by coding `loot.get(x-1) or loot.get(x+1). Therefore it depends on your requirement.

Do static arraylists lose what the contain?

I have a program and its processing rather large amounts of data. It is comparing one static string arraylist to another checking whether a string is contained in it.
But what happens is after processing lets say 40k+ strings it begins to fail on the checking. By fail I mean it begins to not recognize that a string already exists in the other?
Is there a reason for this or is the arraylist simply too large?
Thanks
EDIT
for (int i = 0; i < arraylist1.size(); i++) {
boolean enter = true;
for (int x = 0; x < arraylist2.size() && enter; x++) {
if (arraylist1.get(i).getString().matches(arraylist2.get(x))) {
enter = false;
}
}
if (enter) {
//do something
}
}
EDIT****
Off-topic to the question but using .equals() instead of .matches() improves the performance MASSIVELY.
The simple answer is: no.
ArrayLists do not lose what is in them.
Your symptoms could be caused by a number of things, including threading/synchronization issues, subtle differences in the string, etc.
You should consider using a HashSet anyway though. It will make the "contains" check much much faster.
Using HashSet all your code above becomes:
List<String> list;
Set<String> set;
for (String str: list) {
if (!set.contains(str)) {
//do something
}
}
Much simpler and incredibly faster.
If you do need to use lists you can do the same thing but having both collections as List, the API doesn't change but performance will.

Monster object deletion

Short introduction:
I'm building a game, where monsters spawn at the top, and moves through a path, to the reach a point where they need to be removed/destroyed/deleted. But I can't seem to get the Monster Object deleted.
for (Monster i : Monstre)
{
this.add(i); //adds monster to JPanel
if(i.monstery > 50 && i.monsterx > 50){ //check if monster have reached end point
this.remove(i); //Should remove Object from the JPanel ?
i = null; //Sets object too null
Monstre.remove(i); //Removes object from arrayList "Monstre".
}else{
//Update the monsters bounds
The above removes the object from the JPanel, and it seems to be all good. But when i call System.out.println(Monstre.size()); I get an increasing amount of monsters spawned, and if increasing the monster spawn rate, the program starts to eventually slow down, because amount of monsters in the Monstre arraylist is over 9000, and never decreasing.
What I'm looking for, is a way to remove these objects while the game is running.
Remove the i = null; line. This is not C and you don't have to assign your variables to null. JVM will do that for you (google "java garbage collection"). Because of that line, you practically call Monstre.remove(null) which does not work.
Also, you cannot iterate over the collection in that manner and modify it (remove values). Save the monsters you want to delete in an array outside of the scope of the loop, and remove them after the loop finishes. Otherwise, use an iterator:
Iterator<Monster> it= Monstre.iterator();
while (it.hasNext()) {
Monster i= it.next();
//code code code
if (shouldDelete) {
this.remove(i);
it.remove();
}
}
In addition to the suggestion in the first answer, you should change your loop. Removing items from the Monstre list while using the for-each loop will cause problems.
Instead try :
Iterator<Monster> iter = Monstre.iterator ();
while (iter.hasNext())
{
i = iter.next();
this.add(i); //adds monster to JPanel
if(i.monstery > 50 && i.monsterx > 50){ //check if monster have reached end point
this.remove(i);
iter.remove();
}else{
EDIT :
Here's an explanation where you can't use the for-each loop :
So when should you use the for-each loop? Any time you can. It really
beautifies your code. Unfortunately, you cannot use it everywhere.
Consider, for example, the expurgate method. The program needs access
to the iterator in order to remove the current element. The for-each
loop hides the iterator, so you cannot call remove. Therefore, the
for-each loop is not usable for filtering. Similarly it is not usable
for loops where you need to replace elements in a list or array as you
traverse it. Finally, it is not usable for loops that must iterate
over multiple collections in parallel. These shortcomings were known
by the designers, who made a conscious decision to go with a clean,
simple construct that would cover the great majority of cases.
i = null; //Sets object too null
Monstre.remove(i); //Removes object from arrayList "Monstre".
Here you set the variable i to null then you request that i (i.e. null) is removed from your arraylist, the arraylist does not contain null so nothing happens. Setting things equal to null is very rarely nessissary.
As you have correctly said removing the i=null upsets the program, this is because you are iterating through the list and then changing the list while iterating, you have two options;
1) go through the Arraylist in a manor similar to an array
import java.util.*;
public class Test{
public static void main(String [] args){
ArrayList<Double> doubles=new ArrayList<Double>();
for(double i=0;i<10;i++){
doubles.add(i);
}
//remove 7.0s from doubles
for(int i=doubles.size()-1;i>=0;i--){
//must go through backwards - see http://stackoverflow.com/questions/12111210/java-arraylist-search-and-remove for why
if (doubles.get(i).equals(7.0)){
doubles.remove(i);
}
}
}
}
2) use an iterator and its remove method
import java.util.*;
public class Test{
public static void main(String [] args){
ArrayList<Double> doubles=new ArrayList<Double>();
for(double i=0;i<10;i++){
doubles.add(i);
}
//remove 7.0s from doubles
Iterator<Double> iterator=doubles.iterator();
while(iterator.hasNext()){
Double testDouble=iterator.next();
if (testDouble.equals(7.0)){
iterator.remove();
}
}
}
}
You cannot remove this element in a for-loop.
You need to use listIterator() method to retrieve an iterator that can be modified and loop with iterator-style. Otherwise you would always get java.util.ConcurrentModificationException

how do i use a hashmap keys to an array of strings?

im currently working on a multiple class assignment where i have to add a course based on whether the prerequisites exist within the program.
im storing my courses within the program class using a hashmap. (thought i would come in handy) however, im having a bit of trouble ensuring that these preReqs exist.
here is some code ive currently got going
public boolean checkForCourseFeasiblity(AbstractCourse c) throws ProgramException
{
AbstractCourse[] tempArray = new AbstractCourse[0];
tempArray= courses.keySet().toArray(tempArray);
String[] preReqsArray = new String[1];
preReqsArray = c.getPreReqs();
//gets all course values and stores them in tempArray
for(int i = 0; i < preReqsArray.length; i++)
{
if(courses.containsKey(preReqsArray[i]))
{
continue;
}
else if (!courses.containsKey(preReqsArray[i]))
{
throw new ProgramException("preReqs do not exist"); //?
}
}
return true;
}
ok so basically, tempArray is storing all the keySets inside the courses hashmap and i need to compare all of them with the preReqs (which is an array of Strings). if the preReqs exist within the keyset then add the course, if they dont do not add the course. return true if the course adds otherwise through me an exception. keep in mind my keysets are Strings e.g. a keyset value could be "Programming1" and the required prerquisite for a course could be "programming1". if this is the case add then add the course as the prereq course exists in the keyset.
i believe my error to be when i initialize mypreReqsArray with c.getPreReqs (note: getPreReqs is a getter with a return type String[]).
it would be really great if someone could aid me with my dilemma. ive tried to provide as much as possible, i feel like ive been going around in circles for the past 3 hours :(
-Thank you.
Try something like this, you don't need tempArray. The "for each" loop looks lots nicer too. If you want to throw an Exception I would put that logic in the place that calls this method.
public boolean checkForCourseFeasiblity(AbstractCourse c)
{
for(String each : c.getPreReqs())
{
if(! courses.containsKey(each))
{
return false;
}
}
return true;
}

Categories