This site requires JavaScript, please enable it in your browser!
Greenfoot back
blairtch
blairtch wrote ...

2014/9/27

Trying to Use Boolean to Recognize Occupied Cells

1
2
blairtch blairtch

2014/9/27

#
My assignment is to find a way to alter the program so that when the world is populated the leaves and wombats won't spawn on top of each other. I am supposed to create two methods: findEmptyCell() and isOccupied(), the second of which returns a boolean value. Been working on it for a while now and I can't seem to get it to work right. Can anyone point me in the right direction? Thank you! Here is my code:
import greenfoot.*;  // imports Actor, World, Greenfoot, GreenfootImage
import java.util.Random;
import java.util.List;

/**
 * A world where wombats live.
 * 
 * @author
 * @version 
 */
public class WombatWorld extends World
{
    //Private class member variables can be declared here
    int x;
    int y;
    
    
    /**
     * Create a new world with 8x8 cells & with a cell size of 60x60 px
     * Set the background of the world to "cell.jpg" which is located in
     * the scenario's image folder. Finally, populate the world.
     */
    public WombatWorld() 
    {
        super(8, 8, 60);        
        setBackground("cell.jpg");
        populate();
    }

    /**
     * Populates world with a random arrangement of wombats and leaves
     */    
    public void populate()
    {
        addObject(new Wombat(), 1, 7);
        addObject(new Wombat(), newX(), newY());
        randomLeaves(getNumLeaves());

    }

    /**
     * Place a pre-determined number of leaves into the world in random
     * cells. Each leaf can only be placed in an unoccupied cell.
     * @param howMany Number of leaves to be placed randomly in cells.
     */
    public void randomLeaves(int howMany)
    {
        for(int i=0; i<howMany; i++)
        {
            addObject(new Leaf(), newX(), newY());
            if (isOccupied(x,y))
            {
                findEmptyCell();
            }
        }
    }

    /**
     * Get a random coordinate value for x
     * @return a random integer value to be used as a new x-coordinate
     */
    public int newX()
    {
        return Greenfoot.getRandomNumber(getWidth());
        // getWidth() is a method defined in the World class. 
        // Since WombatWorld "is a" World it has this method as well.

    }

    /**
     * Get a random coordinate value for x
     * @return a random integer value to be used as a new y-coordinate
     */
    public int newY()
    {
        return Greenfoot.getRandomNumber(getHeight());
        // getHeight() is a method defined in the World class.
        // Since WombatWorld "is a" World it has this method as well.

    }

    /**
     * Get a random number of leaves that will be placed in the world
     * @return a random int; represents number of leaves to be placed
     */
    public int getNumLeaves()
    {
        return Greenfoot.getRandomNumber(getHeight() * getWidth());
    }

    // -------- NEW METHODS TO BE CREATED ---------- //
    
    /**
     * findEmptyCell() - Randomly locate a currently unoccupied cell
     * in the world. Use the class member variables to hold the x and y
     * coordinates once an empty cell has been found. No parameters
     * are needed, and the return type is void.
     */
    public void findEmptyCell()
    {
        x = newX();
        y = newY();
        if (isOccupied(x, y)==true)
        {
            x = newX();
            y = newY();
        }
    }


    /**
     * isOccupied - Used to determine if a space is occupied by another
     * Actor object.
     * @param x int for the x-coordinate of the target cell to inspect
     * @param y int for the y-coordinate of the target cell to inspect
     * @return boolean true if target cell has one or more Actor objects
     */
    public boolean isOccupied(int x, int y)
    {
        if (getObjectsAt(x, y, null) != null) 
        {
            return false;
        } else {
            return true;
        }
    }
    
}
danpost danpost

2014/9/27

#
It appears your 'isOccupied' method is returning the opposite of what it should. In 'findEmptyCell' if you use 'while' instead of 'if', it should set the 'x' and 'y' fields on one call. In your 'randomLeaves' method, if you call 'findEmptyCell' before adding a new leaf, then you can use 'x' and 'y' as the location coordinates to place the leaf in the world instead of calling 'newX' and 'newY' which could end up to be a non-empty cell.
danpost danpost

2014/9/27

#
I also noticed that your 'getNumLeaves' method could return any value from zero to 63 (determined by your world size -- 8*8 = 64). If 63 is returned, you will end up stuck in your 'getEmptyCell' method in an infinite loop because you already placed two object into the world before calling 'randomLeaves'. That is, it will not find an empty cell for the 63rd leaf. You should modify what 'getNumLeaves' returns so that it does not exceed 62 (you can also set some minimum value greater than zero).
blairtch blairtch

2014/9/27

#
I made the changes you suggested and eliminated the newX, newY methods, but still having the same issue?
public class WombatWorld extends World
{
    //Private class member variables can be declared here
    int x;
    int y;
    
    
    /**
     * Create a new world with 8x8 cells & with a cell size of 60x60 px
     * Set the background of the world to "cell.jpg" which is located in
     * the scenario's image folder. Finally, populate the world.
     */
    public WombatWorld() 
    {
        super(8, 8, 60);        
        setBackground("cell.jpg");
        populate();
    }

    /**
     * Populates world with a random arrangement of wombats and leaves
     */    
    public void populate()
    {
        addObject(new Wombat(), 1, 7);
        addObject(new Wombat(), Greenfoot.getRandomNumber(getWidth()), Greenfoot.getRandomNumber(getHeight()) );
        
        randomLeaves(getNumLeaves());

    }

    /**
     * Place a pre-determined number of leaves into the world in random
     * cells. Each leaf can only be placed in an unoccupied cell.
     * @param howMany Number of leaves to be placed randomly in cells.
     */
    public void randomLeaves(int howMany)
    {
        for(int i=0; i<howMany; i++)
        {
                findEmptyCell();
                addObject(new Leaf(), x, y);
        }
    }


    /**
     * Get a random number of leaves that will be placed in the world
     * @return a random int; represents number of leaves to be placed
     */
    public int getNumLeaves()
    {
        return (Greenfoot.getRandomNumber(getHeight() * getWidth())) - 2;
    }

    // -------- NEW METHODS TO BE CREATED ---------- //
    
    /**
     * findEmptyCell() - Randomly locate a currently unoccupied cell
     * in the world. Use the class member variables to hold the x and y
     * coordinates once an empty cell has been found. No parameters
     * are needed, and the return type is void.
     */
    public void findEmptyCell()
    {
        x = Greenfoot.getRandomNumber(getWidth());
        y = Greenfoot.getRandomNumber(getHeight());    
        
        if (isOccupied(x, y)== true)
        {
            x = Greenfoot.getRandomNumber(getWidth());
            y = Greenfoot.getRandomNumber(getHeight());
        }
        
    }


    /**
     * isOccupied - Used to determine if a space is occupied by another
     * Actor object.
     * @param x int for the x-coordinate of the target cell to inspect
     * @param y int for the y-coordinate of the target cell to inspect
     * @return boolean true if target cell has one or more Actor objects
     */
    public boolean isOccupied(int x, int y)
    {
        if (getObjectsAt(x, y, null) != null) 
        {
            return true;
        } else {
            return false;
        }
    }
    
}
danpost danpost

2014/9/28

#
You did not change 'if' to 'while' in the 'findEmptyCell' method. Also, the '-2' in the getNumLeaves should be inside the parenthesis as part of the argument for 'getRandomNumber'.
blairtch blairtch

2014/9/28

#
When I change the if to while in the findEmptyCell method I'm getting an infinite loop?
blairtch blairtch

2014/9/28

#
/**
 * A world where wombats live.
 * 
 * @author 
 * @version 
 */
public class WombatWorld extends World
{
    //Private class member variables can be declared here
    int x;
    int y;
    
    
    /**
     * Create a new world with 8x8 cells & with a cell size of 60x60 px
     * Set the background of the world to "cell.jpg" which is located in
     * the scenario's image folder. Finally, populate the world.
     */
    public WombatWorld() 
    {
        super(8, 8, 60);        
        setBackground("cell.jpg");
        populate();
    }

    /**
     * Populates world with a random arrangement of wombats and leaves
     */    
    public void populate()
    {
        addObject(new Wombat(), 1, 7);
        addObject(new Wombat(), Greenfoot.getRandomNumber(getWidth()), Greenfoot.getRandomNumber(getHeight()) );
        
        randomLeaves(getNumLeaves());

    }

    /**
     * Place a pre-determined number of leaves into the world in random
     * cells. Each leaf can only be placed in an unoccupied cell.
     * @param howMany Number of leaves to be placed randomly in cells.
     */
    public void randomLeaves(int howMany)
    {
        
        for(int i=0; i<howMany; i++)
        {
            
            findEmptyCell();
            addObject(new Leaf(), x, y); 

        }
    }


    /**
     * Get a random number of leaves that will be placed in the world
     * @return a random int; represents number of leaves to be placed
     */
    public int getNumLeaves()
    {
        return (((Greenfoot.getRandomNumber(7)+1) * Greenfoot.getRandomNumber(getWidth())) - 2);
    }

    // -------- NEW METHODS TO BE CREATED ---------- //
    
    /**
     * findEmptyCell() - Randomly locate a currently unoccupied cell
     * in the world. Use the class member variables to hold the x and y
     * coordinates once an empty cell has been found. No parameters
     * are needed, and the return type is void.
     */
    public void findEmptyCell()
    {
        x = Greenfoot.getRandomNumber(getWidth());
        y = Greenfoot.getRandomNumber(getHeight());    
        
        while (isOccupied(x, y)== true)
        {
            x = Greenfoot.getRandomNumber(getWidth());
            y = Greenfoot.getRandomNumber(getHeight());
            addObject(new Leaf(), x, y);
        }
        
    }


    /**
     * isOccupied - Used to determine if a space is occupied by another
     * Actor object.
     * @param x int for the x-coordinate of the target cell to inspect
     * @param y int for the y-coordinate of the target cell to inspect
     * @return boolean true if target cell has one or more Actor objects
     */
    public boolean isOccupied(int x, int y)
    {
        if (getObjectsAt(x, y, null) != null) 
        {
            return true;
        } else {
            return false;
        }
    }
    
}
blairtch blairtch

2014/9/28

#
I think something is wrong with my boolean method.
danpost danpost

2014/9/28

#
What is wrong is your 'findEmptyCell' method. It is not supposed to add a leaf into the world -- it is only supposed to locate an empty cell.
blairtch blairtch

2014/9/28

#
Maybe I am missing something, but when I do that it doesn't work anymore. The source code compiles okay but nothing appears in the greenfoot enviornment. It says "The constructor is loading..." or "The world is being constructed..." and then it times out and says The constructor for the world is taking a long time, you may have an infinite loop.
danpost danpost

2014/9/28

#
You still have the '-2' in the 'getRandomNumber' call of the 'getNumLeaves' in a bad location. It must be put inside the parenthesis of the method call. You originally had something like this:
return Greenfoot.getRandomNumber(getWidth()*getHeight());
which produced return values of from zero to 63. You need to maximum value to be at least one less than that. So:
return Greenfoot.getRandomNumber(getWidth()*getHeight()-1);
would produce return values of from zero to 62. If you wanted to add a minimum limit also -- say 10, then:
return Greenfoot.getRandomNumber(getWidth()*getHeight()-11)+10;
decreasing the random part and adding an absolute part.
davmac davmac

2014/9/28

#
The main problem, I think, is in your isOccupied method:
        if (getObjectsAt(x, y, null) != null)   
The 'getObjectsAt' method can never return null. It always returns a List (which might be empty).
danpost danpost

2014/9/28

#
@davmac, nice catch (I had overlooked that).
blairtch blairtch

2014/9/28

#
So it will always return false value and the code inside the if statement will never execute? Is there a way I can fix this or should I try an entirely different approach? Maybe something like:
 public boolean isOccupied(int x, int y)
    {
        if (getObjectsAt(x, y, null).isEmpty())) 
        {
            return false;
        } else {
            return true;
        }
    }
davmac davmac

2014/9/28

#
Maybe something like:
Exactly (except you have an extra ')'). Also, If you wanted to make it simpler, you could just do:
    public boolean isOccupied(int x, int y)  
       {  
           return ! getObjectsAt(x, y, null).isEmpty();
       }  
The '!' inverts the boolean - so that true becomes false and false becomes true.
There are more replies on the next page.
1
2