This discussion is archived
12 Replies Latest reply: Dec 17, 2007 5:33 PM by 807603 RSS

Removing objects from an ArrayList remotely

3004 Newbie
Currently Being Moderated
I need to remove objects from an arraylist remotely, meaning that I need to send a command from one class to another to remove an object from an arraylist. I am in the Soldier class, trying to remove another soldier from the main soldierList if they lose a fight. Here's the problem: when I try to remove otherSoldier from the main soldierList in the main model class, it won't go. What should I do?
     public void fight(){
          if (strength >= otherSoldierStrength ) {
               model.soldierList.remove(otherSoldier);//error
               move();
          }
  • 1. Re: Removing objects from an ArrayList remotely
    jschellSomeoneStoleMyAlias Expert
    Currently Being Moderated
    "error" tells us nothing.

    "it won't go." tells us nothing either.

    Try explaining what actually does happen rather than telling us that it doesn't work.
  • 2. Re: Removing objects from an ArrayList remotely
    3004 Newbie
    Currently Being Moderated
    Ok, let me see if I can explain this more clearly. THere is a main model that generates soldiers that populate a soldierList arrayList. The soldiers fight, and the losers need to be removed from the arrayList. Here's the method inside the Soldier class:
         public void fight(){
              if (strength >= otherSoldierStrength ) {
                   model.soldierList.remove(otherSoldier);
                   move();
              }
              else if (strength < otherSoldierStrength ) {
                   model.soldierList.remove(this);
              }
              else {
                   System.out.println("Something is wrong.");
              }
         }
    The second command to remove(this) works fine--it's the first command to remove (otherSoldier) that doesn't work. From WITHIN the Soldier class, it doesn't work to command another Soldier to remove itself from the main model's soldierList, and I cannot figure out how to either write a method in the main model to call in the Soldier class to call here to remove the otherSoldier or to do so from within this Soldier.
  • 3. Re: Removing objects from an ArrayList remotely
    807603 Newbie
    Currently Being Moderated
    This design smells funny to me. I don't like the idea of a soldier trying to directly play with the soldierList. It seems to be breaking some OOP rule, perhaps encapsulation.

    I may be totally off base here, and sorry if I am, but in a game such as this, I picture a class that controls the battle, perhaps class Battle whose object, battle "knows" which soldier is fighting which. Then soldiers can pass messages to the battle object, and it does the removing of soldiers off of the list.

    Again, sorry if this doesn't help.

    Edited by: petes1234 on Dec 17, 2007 3:22 PM
  • 4. Re: Removing objects from an ArrayList remotely
    3004 Newbie
    Currently Being Moderated
    The problem is that I don't know how to write a method that will remove the soldier objects in the main model; I already have the "Battle" class, as it were. What would a method like that look like? It would go in the main model like this:
         public void removeSoldierFromList() {
              do stuff
         }
    and I would call it here:
         public void fight(){
              if (strength >= otherSoldierStrength ) {
                   model.soldierList.remove(otherSoldier);//do stuff here instead of this line, something like removeSoldierFromList();
                   move();
              }
              else if (strength < otherSoldierStrength ) {
                   model.soldierList.remove(this);
              }
              else {
                   System.out.println("Something is wrong.");
              }
         }
    But I don't know how to write it...
  • 5. Re: Removing objects from an ArrayList remotely
    807603 Newbie
    Currently Being Moderated
    First off, realize that this is only opinion, and second off, realize that this is your program, so use or don't use this opinion as you see fit. But if I were doing this, I'd change from fight to attack and defend, because usually in a game like this it's one initially attacking another. The main thing is, one of the players has to be able to know who the other player is, so an attack method would work well. In this method, I'd pass a reference to the attacked player. Next if this were my program, I'd have an element of randomness in the amount of strength available, kind of like in the game of risk. Here the mightier army usually wins, but not always. Finally, if one player defeats the other, I'd pass this info to a controller class, such as battle, and have it deal with the List as it sees fit:
        public void attack(Soldier s2)
        {
            int thisStrength = extractRandomStrength();
            int s2Strength = s2.defend(); //get his strength here
            if (thisStrength - s2Strength >= 0)
            {
                battle.remove(s2); // each soldier needs a battle variable that holds a reference to the battle object
            }
            else
            {
                battle.remove(this);
            }
        }
  • 6. Re: Removing objects from an ArrayList remotely
    3004 Newbie
    Currently Being Moderated
    I appreciate the input, but what I really need is a way to remove the other soldier from the main soldierList. How do I write that method?
  • 7. Re: Removing objects from an ArrayList remotely
    807603 Newbie
    Currently Being Moderated
    my guess is that you don't have a valid reference to the other soldier. I can't tell because you never show us that code. It is for this reason that in my attack method I consciously get the reference to the attacked soldier at the time of the attack. Then I assume that battle has the List of soldiers, and so I pass the reference to the soldier to be removed to battle. I believe that your problem is that you need to understand references to objects better, but that's just a guess.
  • 8. Re: Removing objects from an ArrayList remotely
    3004 Newbie
    Currently Being Moderated
    I think you're right, that I don't have a valid reference to the other soldier. I'm going to do something terrible and post both classes here so that you can see it. Forgive me in advance. You can see the Soldier in the fight method.

    Here's the Soldier class:
    //Tarah M. Wheeler
    //University of Michigan
    //Center for the Study of Complex Systems
    //Department of Political Science
    //begun October 16th, 2007
    
    //Tyranny
    
    package tyranny;
    
    import java.awt.BasicStroke;
    import java.awt.Color;
    import java.awt.Point;
    import java.util.ArrayList;
    import java.util.Vector;
    import cern.jet.random.Normal;
    import uchicago.src.sim.gui.Drawable;
    import uchicago.src.sim.gui.SimGraphics;
    import uchicago.src.sim.space.Object2DTorus;
    import uchicago.src.sim.util.Random;
    import uchicago.src.sim.util.SimUtilities;
    
    public class Soldier implements Drawable {
    
         public static int nextID = 0;
         int ID;
         int x, y;
         public double strength; 
         public double strengthValue;
         public double otherSoldierStrength;
         public boolean greenFights = false;
         public boolean greenHasNeighbor;
         public boolean greenCanMove = false;
         public Soldier otherSoldier;
         public Color myColor;
         public Color myBorder;
         public Vector soldierNeighbors;
         public Vector neighborList;
         public static Object2DTorus world;
         public static Model model;
    
         public Soldier () {
              double strengthValue = strength;
              ID = nextID++;
              x = 0;
              y = 0;
              greenHasNeighbor = false;
              myColor = Color.magenta;
              myBorder = Color.black;
              strength = Normal.staticNextDouble(50.00, 5); 
              if (strength >= 100 ){
                   strength = 100;
              }
              if (strength <= 0 ) {
                   strength = 0;
              }
              
         }
    
         public void step () {
              strength = strengthValue;
              move();
              getMyNeighbor();
         }
    
         public void getMyNeighbor () {
              neighborList = new Vector();
              soldierNeighbors = new Vector();
              neighborList = world.getMooreNeighbors(x, y, false);
              for (int i = 0; i < neighborList.size(); i++){
                   Object o= neighborList.get (i);
                   if (o instanceof Soldier) {
                        Soldier otherSoldier = (Soldier)o; 
                        otherSoldier.getID();
                        otherSoldier.getMyColor();
                        otherSoldier.getStrength();
                        if (otherSoldier.getMyColor() == this.getMyColor()){
                             strength = strength + 5; 
                        }
                        if (otherSoldier.getMyColor() == Color.green) {
                             greenFights = true;
                             greenHasNeighbor = true;
                        }
                        otherSoldierStrength = otherSoldier.getStrength();
                        doIFight();
                   }
                   else {
                        //System.out.println( "this guy might not have any neighbors");
                   }
              }
         }
         public void doIFight() {
              if (this.getMyColor() == Color.green && greenFights == true ){
                   fight();//Green won't fight when it doesn't have backup.
                   System.out.println("Green will fight");
              }
              else if (this.getMyColor() == Color.magenta && greenHasNeighbor == false ) {
                   fight();//Magenta won't fight when green has backup.
                   System.out.println("Magenta will fight.");
              }
         }
         
         public void fight(){
              if (strength >= otherSoldierStrength ) {
                   model.soldierList.remove(otherSoldier);
                   move();
              }
              else if (strength < otherSoldierStrength ) {
                   model.soldierList.remove(this);
              }
              else {
                   System.out.println("Something is wrong.");
              }
         }
         
         // step
         // select a random 1-step (Moore) neighbor cell
         // if the cell is open, move there.
         // If its not better, just pick a random open neighbor cell and move there.
         // If no open neighbor, don't move.
    
         public void move() {
              int moved = 0;  //not moved this step
              // pick a random neighbor cell, and if it is open, 
              Point pt =  findRandomOpenNeighborCell ();
              if ( pt != null ) {  // we got one!
                   int newX = (int) pt.getX();
                   int newY = (int) pt.getY();
                   moved = moveTo( newX, newY );
              }
    
              // if didn't move to better cell, then try to find any open neighbor.
              if ( moved == 0 ) { 
                   pt = findRandomOpenNeighborCell();
                   if ( pt != null ) {
                        moved = moveTo( (int) pt.getX(), (int) pt.getY() );
                   }
              }
         }
    
         ////////////////////////////////////////////////////////////////////////////
         // findRandomOpenNeighborCell
         // pick random open Moore neighbor cell and return its 
         // coordinates in a Point,
         // Return null if no open cell found.
              
         public Point findRandomOpenNeighborCell () {
                   ArrayList openPts = new ArrayList();  // list of open points
                   int           minx = x - 1;  // we could change the "neighborhood radius" here
                   int           maxx = x + 1;
                   int           miny = y - 1;
                   int           maxy = y + 1;
    
                   for ( int tx = minx; tx <= maxx; ++tx ) {
                        for ( int ty = miny; ty <= maxy; ++ty ) {
                             if ( world.getObjectAt( tx, ty ) == null ) { // its open 
                                  openPts.add( new Point( tx, ty ) );       // add to list
                             }
                        }
                   }
              // now pick a random open point, if any to pick from
              int numOpenPts = openPts.size();
              Point  openP = null;                 // the one we return
              if ( numOpenPts == 1 )               // only one to pick!
                   openP = (Point) openPts.get( 0 );
              else if ( numOpenPts > 1 )      // pick one at random
                   openP = (Point) openPts.get( Random.uniform.nextIntFromTo( 0, numOpenPts-1 ) );
    
              return openP;
         }
         
         ////////////////////////////////////////////////////////////////////////////
         // moveTo newX, newY
         // check to see if the new location is open, and if so move to it:
         // - tell world it moved
         // - change bug's own x,y values
         // - return 1 to indicate move was succesful
         // if that location not open, return 0
         //
         // NOTE: assumes we are on a torus (eg Object2DTorus object)
    
         public int moveTo( int newX, int newY ) {
              if (  world.getObjectAt( newX, newY ) != null )
                   return 0;             // oops, something is there!
              world.putObjectAt( x, y, null );          // leaving that cell empty now
              world.putObjectAt( newX, newY, this );  // move into new location
              x = SimUtilities.norm( newX, world.getSizeX() ); // normalize for torus
                 y = SimUtilities.norm( newY, world.getSizeY() ); // normalize for torus     
                 return 1;     
         }
    
         public void draw (SimGraphics g) {
              g.drawFastRoundRect(myColor);
              g.drawRectBorder(new BasicStroke(2), myBorder);
         }
    
         /////////////////////////////////////////////////////////////////////
    
         public void setID(int i) {ID = i;}
         public int getID() {return ID;}
    
         public int getX() { return x; }
         public void setX( int i ) { x = i; }
    
         public int getY() { return y; }
         public void setY( int i ) { y = i; }
         
         public boolean getGreenHasNeighbor() { return greenHasNeighbor; }
         public void setGreenHasNeighbor ( boolean i ) { greenHasNeighbor = i; }
    
         public double getStrength() { return strength; }
         public void setStrength( double i ) { strength = i; }
    
         public Color getMyColor() { return myColor; }
         public void setMyColor( Color i ) { myColor = i; }
    
         public Color getMyBorder() { return myBorder; }
         public void setMyBorder( Color i ) { myBorder = i; }
         
         public Soldier getOtherSoldier () { return otherSoldier; }
         public void setOtherSoldier( Soldier i ) { otherSoldier = i; } 
    
         public static void setModel( Model m ) { model = m; }
         
         public static void setWorld( Object2DTorus world ) {     Soldier.world = world;}
    
    }
    and here's the Main Model:
    package tyranny;
    
    import java.awt.Color;
    import java.util.ArrayList;
    import java.util.Collections;
    import uchicago.src.sim.engine.BasicAction;
    import uchicago.src.sim.engine.Schedule;
    import uchicago.src.sim.engine.SimModelImpl;
    import uchicago.src.sim.gui.DisplaySurface;
    import uchicago.src.sim.gui.Object2DDisplay;
    import uchicago.src.sim.space.Object2DTorus;
    import uchicago.src.sim.util.Random;
    import uchicago.src.sim.analysis.DataRecorder;
    
    public class Model extends SimModelImpl {
    
         public int numSoldiers = 200;
         public int xSize = 21;
         public int ySize = 21;
         public DisplaySurface dsurf;
         public Schedule schedule;
         public ArrayList soldierList;
         public ArrayList greenColorStorage;
         public ArrayList magentaColorStorage;
         public Object2DTorus world;
         public Object2DDisplay display;
         public DataRecorder dRecorder;
         
         public void buildModel () {
              //System.out.println("Model.buildModel() beginning.");
              world = new Object2DTorus(xSize, ySize);
              Soldier.setModel(this);
              Soldier.setWorld( world );
              soldierList = new ArrayList();
              //System.out.println("creating people now");
              for (int i = 0; i < numSoldiers; i++) {
                   int x, y;
                   Soldier soldier = new Soldier();
                   soldierList.add (soldier);
                   do {
                        x = Random.uniform.nextIntFromTo( 0, 20 );
                        y = Random.uniform.nextIntFromTo( 0, 20 );
                   } while ( world.getObjectAt( x, y ) != null );
                   world.putObjectAt(x, y, soldier);
                   soldier.setX( x );
                   soldier.setY( y );
                   int a = Random.uniform.nextIntFromTo(0,1);
                   if (a == 0 ) {
                        soldier.setMyColor(Color.green);
                   }
                   if (a == 1) {
                        soldier.setMyColor(Color.magenta);
                   }
                   soldier.setMyBorder(Color.black);
              }
              initDataRecorder();
              //System.out.println("Model.buildModel() finished with " + soldierList.size() + " number of soldiers");
         }
    
         public void buildDisplay () {
              //System.out.println("Model.buildDisplay() beginning.");
              Object2DDisplay display = new Object2DDisplay(world);
              dsurf.addDisplayableProbeable (display, "Tyrant View");
              dsurf.setBackground (java.awt.Color.black);
              addSimEventListener (dsurf);
              //System.out.println("Model.buildDisplay() finished.");
         }
         
         public void initDataRecorder() {
              dRecorder = new DataRecorder("./blah.txt", this);
    
              dRecorder.createNumericDataSource("soldierListSize", this, "getSoldierListSize");
              dRecorder.createNumericDataSource("greenColorStorage", this, "getGreenColorStorage");
              dRecorder.createNumericDataSource("magentaColorStorage", this, "getMagentaColorStorage");
         }
         
         private void buildSchedule () {
              //System.out.println( "Model.buildSchedule() beginning" );
              schedule.scheduleActionBeginning(0, this, "step");
              schedule.scheduleActionBeginning(0, new BasicAction() {
                   public void execute() {dRecorder.record(); }});
              schedule.scheduleActionAtEnd(dRecorder, "writeToFile");
              //System.out.println( "Model.buildSchedule() finished" );
         }
         
         public void removeSoldierFromList() {
              
         }
    
         public void step() {
              greenColorStorage = new ArrayList();
              magentaColorStorage = new ArrayList();
              //System.out.println( "==> Model step " + getTickCount() );// Checking step #
              for (int i = 0; i < soldierList.size (); i++) {
                   Soldier s = (Soldier) soldierList.get (i);
                   s.step();
              }
              Collections.shuffle(soldierList);
              //System.out.println("Shuffling collection now.");
              dsurf.updateDisplay ();
              //System.out.println("Model.step() finished.");
              for (int i = 0; i < soldierList.size (); i++) {
                   Soldier s = (Soldier) soldierList.get (i);
                   if (s.getMyColor() == Color.green ) {
                        greenColorStorage.add(s);
                   }
                   if (s.getMyColor() == Color.magenta ) {
                        magentaColorStorage.add(s);
                   }
              }
              if (magentaColorStorage.size() == 0 || greenColorStorage.size() == 0 ) {
                   stop();
              }     
              if (getTickCount() >= 300 ) {
                   stop();
              }
         }
    
         public void begin () {
              //System.out.println("Model.begin() beginning...");
              buildModel ();
              buildDisplay ();
              buildSchedule ();
              dsurf.display ();
              //System.out.println("Model.begin() finished...");
         }
    
         public void setup () {
              //System.out.println("Model.setup() beginning...");
              Random.createUniform ();
              if (dsurf != null)
                   dsurf.dispose ();
              dsurf = null;
              schedule = null;
              System.gc ();
              dsurf = new DisplaySurface (this, "StandingOvation");
              registerDisplaySurface ("StandingOvation", dsurf);
              schedule = new Schedule (1);
              numSoldiers = 200;
              soldierList = new ArrayList (numSoldiers);
              xSize = 21;
              ySize = 21;
              //System.out.println("Model.setup() finished.");
         }
    
         public String[] getInitParam () {
              String[] params = { "numSoldiers",
                        "xSize", "ySize"};
              return params;
         }
    
         public Schedule getSchedule () {return schedule;}
         public String getName () {return "Tyranny";}
    
         public static void main (String[] args) {
              //System.out.println("Model.main() beginning...");
              uchicago.src.sim.engine.SimInit init = new uchicago.src.sim.engine.SimInit ();
              Model model = new Model ();
              init.loadModel (model, null, false);
              //System.out.println("Model.main() finished...");
         }
    
         public int getNumSoldiers () {return numSoldiers;}
         public void setNumSoldiers (int n) {numSoldiers = n;}
         
         public int getSoldierListSize () {return soldierList.size();}
         public int getGreenColorStorage () {return greenColorStorage.size();}
         public int getMagentaColorStorage () {return magentaColorStorage.size();}
         
         public int getXSize () {return xSize;}
         public void setXSize (int size) {xSize = size;}
    
         public int getYSize () {return ySize;}
         public void setYSize (int size) {ySize = size;}
    }
  • 9. Re: Removing objects from an ArrayList remotely
    3004 Newbie
    Currently Being Moderated
    I tried adding that getter and setter for otherSoldier at the bottom of the Soldier class to try to fix the non valid reference for the otherSoldier to fix the problem, but without using it (or knowing how to use it), it didn't do any good.
  • 10. Re: Removing objects from an ArrayList remotely
    807603 Newbie
    Currently Being Moderated
    Nquirer101 wrote:
    I think you're right, that I don't have a valid reference to the other soldier. I'm going to do something terrible and post both classes here so that you can see it.
    I'm not going to wade through all of that code. It isn't quite fair to ask me and the other volunteers here to do so. You need to post an SSCCE: a small compilable program that demonstrates your problem. This takes more work than just posting the complete code, as you have to think on what must stay and what can leave without preventing compilation and without losing the error, but the important point is the work in making this problem digestible needs to be your work, not our work. You will have to remove all references to packages not in the standard java library, you will need to strip everything down to the bare minimum.

    Remember, ultimately, this is your problem and that we are all volunteers here. Our time is valuable.

    Edited by: petes1234 on Dec 17, 2007 5:31 PM
  • 11. Re: Removing objects from an ArrayList remotely
    807603 Newbie
    Currently Being Moderated
    OK I lied. I did wade through some of it, but there is no way that I can run any of this code to try it out with the non-standard packages present. Anyway, I do see two problems:

    The immediate but small problem: you are declaring "otherSoldier" twice, once as a class variable (the appropriate declaration), and once in the getMyNeighbor method. You realize that these two otherSoldier objects are two separate and distinct objects bearing absolutely no relationship to the other. The one in getMyNeighbor effectively "shadows" the class variable preventing the class variable from receiving the proper reference.

    To fix it change the method to this:
         public void getMyNeighbor () {
              neighborList = new Vector();
              soldierNeighbors = new Vector();
              neighborList = world.getMooreNeighbors(x, y, false);
              for (int i = 0; i < neighborList.size(); i++){
                   Object o= neighborList.get (i);
                   if (o instanceof Soldier) {
    
                        //Soldier otherSoldier = (Soldier)o; //** this is no good and shadows the class variable
                        otherSoldier = (Soldier)o; // this is correct
    
                        otherSoldier.getID();
                        otherSoldier.getMyColor();
                        otherSoldier.getStrength();
                        if (otherSoldier.getMyColor() == this.getMyColor()){
                             strength = strength + 5; 
                        }
  • 12. Re: Removing objects from an ArrayList remotely
    807603 Newbie
    Currently Being Moderated
    The second, and I think major problem is (sorry about being blunt): your program structure is not very good. You have two huge classes which may almost be considered to be god-classes:

    http://en.wikipedia.org/wiki/God_class

    And if not god-classes, they're at least major-deity classes. You really need to refactor this program, probably creating more classes with better division of labor, with better encapsulation.

    Edited by: petes1234 on Dec 17, 2007 6:04 PM