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

2015/4/27

Greedy Behavior

1
2
wallace989 wallace989

2015/4/27

#
I need to make a Wombat move towards the closest leaf and eat it until they are all gone. Are there any good examples of this sort of greedy behavior I can look at?
danpost danpost

2015/4/27

#
The code you create for this would be an example of this sort of greedy behavior. Basically, what you stated was this: If the world is not empty of leaves, if can see leaf, eat leaf; else, turn and move toward closest leaf; The way I stated it should not be difficult to turn into code. The different parts of it ('can see', 'eat leaf', 'turn and move toward closest leaf') can be method calls ('canSeeLeaf', 'eatLeaf' and 'approachLeaf'), each which can be given its appropriate code (again, state what it should do, simply; convert into a basic statement and call methods on any parts that need further scrutiny).
danpost danpost

2015/4/27

#
I will give an example of how the first line is converted to code -- If the world is not empty of leaves:
if (leavesRemain())
{
    // rest of phrasing coded here
}

private boolean leavesRemain()
{
    return !getWorld().getObjects(Leaf.class).isEmpty(); // is world not empty of leaves
}
wallace989 wallace989

2015/4/28

#
import greenfoot.*;  // (World, Actor, GreenfootImage, and Greenfoot)
import java.util.List;
import java.awt.Font;

/**
 * A Wombat.
 */
public class GreedyWombat extends Actor
{
    private static final int EAST = 0;
    private static final int WEST = 1;
    private static final int NORTH = 2;
    private static final int SOUTH = 3;

    private int direction;
    private int moves;

    public GreedyWombat()
    {
        setDirection(EAST);
    }

    /**
     * The Wombat executes its assigned behavior, increases the number of
     * moves taken, and then checks if the last Leaf has been eaten.
     */
    public void act()
    {
        wombatBehavior();
        moves++;
        checkComplete();
    }

    /**
     * The Wombat behavior has to be implemented in this method.
     * The Wombat should always take one step in the direction of the closest Leaf.
     */
    public void wombatBehavior() {
        if(foundLeaf()) {
            eatLeaf();
        }
        else if(canMove()) {
            move();
        }
    }
    private boolean leavesRemain()
    {
        return !getWorld().getObjects(Leaf.class).isEmpty(); //is world not empty of leaves
    }
     
    /**
     * The method to check if the last Leaf has been eaten by the Wombat.
     * If the last Leaf has been eaten, the game stops and the number of moves
     * taken by the Wombat is shown on the screen.
     */
    public void checkComplete() {
        List<Leaf> leaves = getWorld().getObjects(Leaf.class);
        if(leaves.isEmpty()) {
            getWorld().getBackground().setFont(new Font("Arial", 0, 30));
            getWorld().getBackground().drawString("Number of moves: " + moves, 100, 175);
            Greenfoot.stop();
        }
    }

    /**
     * Check whether there is a leaf in the same cell as we are.
     */
    public boolean foundLeaf()
    {
        Actor leaf = getOneObjectAtOffset(0, 0, Leaf.class);
        if(leaf != null) {
            return true;
        }
        else {
            return false;
        }
    }

    /**
     * Eat a leaf.
     */
    public void eatLeaf()
    {
        Actor leaf = getOneObjectAtOffset(0, 0, Leaf.class);
        if(leaf != null) {
            getWorld().removeObject(leaf);
        }
    }

    /**
     * Move one cell forward in the current direction.
     */
    public void move()
    {
        switch(direction) {
            case SOUTH :
            setLocation(getX(), getY() + 1);
            break;
            case EAST :
            setLocation(getX() + 1, getY());
            break;
            case NORTH :
            setLocation(getX(), getY() - 1);
            break;
            case WEST :
            setLocation(getX() - 1, getY());
            break;
        }
    }

    /**
     * Test if we can move forward. Return true if we can, false otherwise.
     */
    public boolean canMove()
    {
        World myWorld = getWorld();
        int x = getX();
        int y = getY();
        switch(direction) {
            case SOUTH :
            y++;
            break;
            case EAST :
            x++;
            break;
            case NORTH :
            y--;
            break;
            case WEST :
            x--;
            break;
        }
        // test for outside border
        if (x >= myWorld.getWidth() || y >= myWorld.getHeight()) {
            return false;
        }
        else if (x < 0 || y < 0) {
            return false;
        }
        return true;
    }

    /**
     * Changes the direction the Wombat is facing.
     * This is relevant for the image shown and for the change in location
     * executed by the move() method.
     */
    public void setDirection(int direction)
    {
        this.direction = direction;
        switch(direction) {
            case SOUTH :
            setImage("wombat.gif");
            setRotation(90);
            break;
            case EAST :
            setImage("wombat.gif");
            setRotation(0);
            break;
            case NORTH :
            setImage("wombat-left.gif");
            setRotation(90);
            break;
            case WEST :
            setImage("wombat-left.gif");
            setRotation(0);
            break;
            default :
            break;
        }
        getImage().scale(29,24);
    }
}

here is what I have to work with, so far the wombat just moves to the edge and stops

danpost danpost

2015/4/28

#
I do not see anywhere that you call 'setDirection' in another method outside the constructor (which you may want to do if you are not eating AND you cannot move).
wallace989 wallace989

2015/4/28

#
The goal is to get the Wombat to eat the nearest leaf then move on to the next leaf until they are all gone. By moving toward the nearest leaf the Wombats direction shouldn't have to be set?
wallace989 wallace989

2015/4/28

#
    /**
     * The Wombat behavior has to be implemented in this method.
     * The Wombat should always take one step in the direction of the closest Leaf.
     */
    public void wombatBehavior() {

        if(foundLeaf()) {
            eatLeaf();
        }
        else if(canMove()) {
            move();
            //turn and move toward closest leaf?
        }
    }
danpost danpost

2015/4/28

#
If you are to have the wombat behave as you intend, you will have to expand on the 'else' part of the 'wombatBehavior' method (lines 10 though 13). You will not be saying "if can move, then move". Presuming that there are no obstacles to avoid (rocks, walls, or trees, for examples), then once you find the closest leaf, the 'canMove' method will not need to be called because no edge should be present between the wombat and the leaf (or one would be already outside the world bounds). So, it is just a matter of finding the closest leaf, turning toward it (so that moving will decrease the difference between the x or y coordinates of the leaf and the wombat) and moving.
wallace989 wallace989

2015/4/29

#
    /**
     * The Wombat behavior has to be implemented in this method.
     * The Wombat should always take one step in the direction of the closest Leaf.
     */
    public void wombatBehavior() {
        if(foundLeaf()) {
            eatLeaf();
        }
        else if(getObjectsInRange(2, "Leaf.class")) {
            //turn towards nearest leaf and move in that direction
        }
    }

Is this the correct way to start this? I am getting confused

danpost danpost

2015/4/29

#
wallace989 wrote...
Is this the correct way to start this?
That might return a List object containing the closest leaf; but what if there are no leaves that close (two cells away or less? Also, that particular method may not be the best one to use in a gridded world; better might be to use the 'getNeighbours' method (especially if your step count is important ; it is being counted; is it not?). Instead of using 'if', you should (since at least one leaf is guaranteed to be in the world) use a 'while' loop and increase the number of steps until the list returned is not empty. Then use the first (or only) element in the list as the one to move toward. As an alternative, you could get a list of ALL leaves in the world and compare the numbers of steps needed to move to each of their locations to determine the closest.
wallace989 wallace989

2015/4/29

#
    public void wombatBehavior() {
        if(foundLeaf()) {
            eatLeaf();
        }
        while(getNeighbours(2, 2, Leaf.class)) {
            //turn towards nearest leaf and move in that direction
        }
    }

Getting an error here how do you use this method?

wallace989 wallace989

2015/4/29

#
    public void wombatBehavior() {
        if(foundLeaf()) {
            eatLeaf();
        }
        while(getNeighbours(1, false, "Leaf.class")) {
            //turn towards nearest leaf and move in that direction
        }
    }

Also tried this still dosent work

danpost danpost

2015/4/29

#
For one thing, you are saying:
if (<List>)
where you need:
if (<Boolean>)
// or
if (<list is not empty>)
For another thing, the '1' needs to be in a variable so you can increase it inside the 'while' code block.
wallace989 wallace989

2015/4/29

#
    public void wombatBehavior() {
        if(foundLeaf()) {
            eatLeaf();
        }
        while(getNeighbours((1,false),(1,true) "Leaf.class")) {
            //turn towards nearest leaf and move in that direction
        }
    }

Something Like this? Or am I still missing the point entirely?

Super_Hippo Super_Hippo

2015/4/29

#
You are still missing the point, it seems. Now you use the method with even more complicated parameters which isn't possible. The parameters are 'int, int, class', so you have to use them. It returns a list, a list can't be an if condition, so you can check if the list isn't empty (which means that there is a leaf around you):
while(!getNeighbours(2, 2, Leaf.class).isEmpty())
There are more replies on the next page.
1
2