problem in synchronization
I'm working on my assignment.My task is to create a pasture with entities on it.The entities are sheep,grass.Every second I call method tick() of each entities then they start moving and eating or producing offspring.My problem is that when a "sheep" eat "grass" and remove it then that "grass" still able to call it's own method tick() .Sorry for my bad English,I'm not native speaker.
Btw,can someone show me how to use codetag.I'm totally noob at this.
Re: problem in synchronization
You might have a boolean value in the Grass class that stores whether or not it has been eaten. That would allow you to show a different image (assuming you're using a gui) for eaten grass, and you could allow the uneaten grass to grow back after time.
But without seeing an SSCCE that demonstrates what you're talking about, we can't really help you. Check out my signature for a link on using the code tags.
Re: problem in synchronization
here is the Pasture.
(of course it contains more methods than this but I think these only these methods can cause that error)
Code :
private int width = 20;
private int height = 20;
private int wolves = 0;
private int sheep = 20;
private int plants = 50;
private int fences;
private Set<Entity> world = new HashSet<Entity>();//store all entities
private Map<Point, List<Entity>> grid = new HashMap<Point, List<Entity>>();//store entities in a Point
private Map<Entity, Point> point = new HashMap<Entity, Point>();//store Point of each entities
private PastureGUI gui;
**
* Add a new entity to the pasture.
*/
public void addEntity(Entity entity, Point pos) {
world.add(entity);
List<Entity> l = grid.get(pos);
if (l == null) {
l = new ArrayList<Entity>();
grid.put(pos, l);
}
l.add(entity);
point.put(entity,pos);
//System.out.println("adding " + entity+" to " + pos);
gui.addEntity(entity, pos);
//if(!(entity instanceof Fence))
//System.out.println(entity + " HAS BEEN ADDED TO "+pos);
}
public void moveEntity(Entity e, Point newPos) {
Point oldPos = point.get(e);
List<Entity> l = grid.get(oldPos);
if (!l.remove(e))
throw new IllegalStateException("Inconsistent stat in Pasture");
/* We expect the entity to be at its old position, before we
move, right? */
l = grid.get(newPos);
if (l == null) {
l = new ArrayList<Entity>();
grid.put(newPos, l);
}
l.add(e);
point.put(e, newPos);
gui.moveEntity(e, oldPos, newPos);
}
/**
* Remove the specified entity from this pasture.
*/
public void removeEntity(Entity entity) {
Point p = point.get(entity);
world.remove(entity);
grid.get(p).remove(entity);
point.remove(entity);
gui.removeEntity(entity, p);
}
here is PastureGUI:
Code :
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
public class PastureGUI extends JFrame implements ActionListener {
private final ImageIcon II_UNKNOWN = new ImageIcon("unknown.gif");
private final ImageIcon II_EMPTY = new ImageIcon("empty.gif");
private final int SCALE = 30;
private Engine engine;
private JLabel[][] grid;
private Map<Point, java.util.List<ImageIcon>> icons =
new HashMap<Point, java.util.List<ImageIcon>>();
private JLabel clockLabel = new JLabel("Time: 0");
private JLabel entitiesLabel = new JLabel("Entities: 0");
private JButton startButton = new JButton("Start");
private JButton stopButton = new JButton("Stop");
private JButton exitButton = new JButton("Exit");
private int height;
private int width;
int size = 0;
/**
* Creates a new instance of this class with the specified
* settings for the pasture to display. */
public PastureGUI(int width, int height, Engine engine) {
this.height = height;
this.width = width;
this.engine = engine;
setSize(width * SCALE, height * SCALE);
startButton.addActionListener(this);
stopButton.addActionListener(this);
exitButton.addActionListener(this);
JPanel buttons = new JPanel();
buttons.setLayout(new GridLayout(1,5));
buttons.add(clockLabel);
buttons.add(entitiesLabel);
buttons.add(startButton);
buttons.add(stopButton);
buttons.add(exitButton);
JPanel field = new JPanel();
field.setBackground(new Color(27,204,89));
field.setLayout(new GridLayout(height, width));
grid = new JLabel[width][height];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
grid[x][y] = new JLabel(II_EMPTY);
grid[x][y].setVisible(true);
field.add(grid[x][y]);
}
}
Container display = getContentPane();
display.setBackground(new Color(27,204,89));
display.setLayout(new BorderLayout());
display.add(field,BorderLayout.CENTER);
display.add(buttons,BorderLayout.SOUTH);
startButton.setEnabled(true);
stopButton.setEnabled(false);
exitButton.setEnabled(true);
update();
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
/**
* This method is called when an action event has occured and
* carries out the correct actions depending on the event. In this
* class, this means that someone has pressed any of the buttons
* start, stop, or exit.
*/
public void actionPerformed(ActionEvent e) {
if (e.getSource() == startButton) {
startButton.setEnabled(false);
stopButton.setEnabled(true);
exitButton.setEnabled(true);
engine.start();
}
else if (e.getSource() == stopButton) {
startButton.setEnabled(true);
stopButton.setEnabled(false);
exitButton.setEnabled(true);
engine.stop();
}
else if (e.getSource() == exitButton) {
System.exit(0);
}
}
/**
* The method addEntity is called to notify the GUI that an entity
* has been added to a position. The icon of the added entity is
* displayed at the position.
*/
public void addEntity(Entity e, Point p) {
ImageIcon icon = e.getImage();
java.util.List<ImageIcon> l = icons.get(p);
if (l==null) {
l = new ArrayList<ImageIcon>();
icons.put(p, l);
}
if (e instanceof Grass) l.add(icon);
else l.add(0,icon);
int x = (int)p.getX();
int y = (int)p.getY();
grid[x][y].setIcon(icon);
size++;
}
public void moveEntity(Entity e, Point old, Point ny) {
removeEntity(e, old);
addEntity(e, ny);
}
/**
* The method removeEntity is called to notify the GUI that an
* entity has been removed from a position. One icon among the
* icons of the remaining entities is displayed at the position.
*/
public void removeEntity(Entity e, Point p) {
ImageIcon icon0 = e.getImage();
java.util.List<ImageIcon> l = icons.get(p);
l.remove(icon0);
ImageIcon icon;
if (l.isEmpty()) icon = II_EMPTY ;
else icon = l.get(0);
int x = (int)p.getX();
int y = (int)p.getY();
grid[x][y].setIcon(icon);
size--;
}
public void update() {
clockLabel.setText("Time: " + engine.getTime());
entitiesLabel.setText("Entities: " + size);
}
}
here is Sheep.
Code :
import javax.swing.*;
import java.util.*;
import java.awt.*;
public class Sheep implements Entity
{
private final ImageIcon image = new ImageIcon("sheep.gif");
protected Pasture pasture;
protected int moveDelay;
private int offspringDelay;
private int hungryDelay;
public Sheep(Pasture pasture) {
this.pasture = pasture;
this.moveDelay = 3;
this.offspringDelay = 25;
this.hungryDelay = 20;
}
public void eat(){
ArrayList<Entity> list = (ArrayList<Entity>)pasture.getEntitiesAt(pasture.getEntityPosition(this));
for(Entity x: list){
if(x instanceof Grass){
pasture.removeEntity(x);
this.hungryDelay = 20;
return ;
}
}
}
public void tick() {
try{
moveDelay--;
offspringDelay--;
hungryDelay--;
eat();
if(moveDelay == 0) {
Point neighbour = (Point)getRandomMember(pasture.getFreeNeighbours(this));
if(neighbour != null){
Point p = pasture.getPosition(this);
pasture.moveEntity(this, neighbour);
System.out.println(this + " move from" + p +" to " +neighbour);
}
this.moveDelay = 3;
}
if(offspringDelay == 0) {
Point neighbour = (Point) getRandomMember(pasture.getFreeNeighbours(this));
if(neighbour != null){
Sheep s = new Sheep(this.pasture);
pasture.addEntity(s, neighbour);
this.offspringDelay = 20;
}
}if(hungryDelay == 0) {
this.pasture.removeEntity(this);
}
}catch (Exception e){}
}
public ImageIcon getImage() { return image; }
public boolean isCompatible(Entity otherEntity) {
if(otherEntity instanceof Fence || otherEntity instanceof Sheep)
return false;
return true;
}
protected static <X> X getRandomMember(Collection<X> c) {
if (c.size() == 0)
return null;
Iterator<X> it = c.iterator();
int n = (int)(Math.random() * c.size());
while (n-- > 0) {
it.next();
}
return it.next();
}
}
here is Grass:
Code :
import javax.swing.*;
import java.util.*;
import java.awt.*;
//You must modify this class to make it work
public class Grass implements Entity
{
private final ImageIcon image = new ImageIcon("plant.gif");
protected Pasture pasture;
private int offspringDelay;
public Grass(Pasture pasture) {
this.pasture = pasture;
this.offspringDelay = 25;
}
/**
* Performs the relevant actions of this entity, depending on what
* kind of entity it is.
*/
public void tick() {
try{
offspringDelay--;
if(offspringDelay == 0) {
Point neighbour = (Point)getRandomMember(pasture.getFreeNeighbours(this));
if(neighbour != null){
Grass g = new Grass(pasture);
pasture.addEntity(g ,neighbour);
offspringDelay = 20;
}
}catch(Exception e){ pasture.getWorld().remove(this);}
}
/**
* Returns the icon of this entity, to be displayed by the pasture
* gui.
* @see PastureGUI
*/
public ImageIcon getImage()
{
return new ImageIcon("plant.gif");
}
/**
* Tests if this entity can be on the same position in the pasture
* as the given one.
*/
public boolean isCompatible(Entity otherEntity) {
if(otherEntity instanceof Fence || otherEntity instanceof Grass)
return false;
return true;
}
protected static <X> X getRandomMember(Collection<X> c) {
if (c.size() == 0)
return null;
Iterator<X> it = c.iterator();
int n = (int)(Math.random() * c.size());
while (n-- > 0) {
it.next();
}
return it.next();
}
}
When a Sheep eat Grass it will call method removeEntity() but later that Grass is still there.When I check that Grass's position it return null ?my friend told me to use try-catch block to catch the exception and ignore it but it seem to work wrong.The number of entities show on screen is not correct.
Re: problem in synchronization