-1

I'm using a Map in my application to store each location within a fictional game map. The current implementation allows me to get the start node, ie Tiberius.

But I'm not sure how I can get to the next location on the map relative to the current location the player is at. For example when I create the map I am at "Tiberius" by default, so I'm wondering how I can create a method that will iterate to the next location, which would be "Desert" while a subsequent call to move() would bring the player to "Jerusalem".

The graph is wired up as shown below with each location having a child location.

From a quick search I see that a list can be iterated through by a field in the ID, like this get element by ID but in this implementation I need to get the next location relative to the current location.

Does anyone know how this method could be implemented?

This is how I've set up the map at the moment in my main class:

public class Main implements Commands{


    public static void main(String[] args)  {

        //Boolean to signify game state 
        boolean gameNotOver = true;

        //main game loop
        while (gameNotOver) {

            GameMap playerMap = new GameMap();
            playerMap.getStartNode();

            Main mainObj = new Main();

            //Take in user commands here
            //and parse commands
            String input = Input.getInput();
            if (input.equals("description")) {
                System.out.println("Description: " );
            } else if (input.equals("move")) {
                System.out.println("Moving to the next location in map.. " );
                mainObj.move();     
        }

        //Game over 
        System.out.println("Game Over!");
        System.exit(0);
    }

    //Game player commands inherited from GameCharacterInterface:

    public String move() {
         //want to create a method here that will call the next 
         //location based on the current location that the player is in.
        // TODO Auto-generated method stub
        return null;
    }

}

This is the Location class used to model the locations:

public class Location {

    private Location[] location;

    private int id;

    private String description;

    private String weight;

    private String name;

    private Item item;

    private Exit[] exit;

    private boolean visited = false;
    private boolean goalLocation;
    private int approximateDistanceFromGoal = 0;
    private Location parent;

    private Map<Location, Integer> children = new HashMap<Location, Integer>();

    public Location() {
        super();
    }

    public Location(String name){
        this.name = name;
    }

    public Location(String name, int goalDistance){
        this.name = name;
        this.approximateDistanceFromGoal = goalDistance;
    }



    public Location[] children(){
        return (Location[]) children.keySet().toArray(new Location[children.size()]);
    }

    public int getDistance(Location loc){
        if(children.get(loc) == null) System.out.println(this.name + ": " + loc.getName());
        return children.get(loc);
    }


    public int getChildLocationCount(){
        return children.size();
    }

    public void addChildLocation(Location child, int distance){
        children.put(child, distance);
    }

    public boolean isLeaf(){
        if (children.size() > 0){
            return false;
        }else{
            return true;
        }
    }


    public void removeChild(Location child){
        children.remove(child);
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getDescription ()
    {
        return description;
    }

    public void setDescription (String description)
    {
        this.description = description;
    }


    public String getWeight() {
        return weight;
    }

    public void setWeight(String weight) {
        this.weight = weight;
    }

    public String getName ()
    {
        return name;
    }

    public void setName (String name)
    {
        this.name = name;
    }

    public Exit[] getExit() {
        return exit;
    }

    public void setExit(Exit[] exit) {
        this.exit = exit;
    }


    public Location[] getLocation() {
        return location;
    }

    public void setLocation(Location[] location) {
        this.location = location;
    }

    public boolean isVisited() {
        return visited;
    }

    public void setVisited(boolean visited) {
        this.visited = visited;
    }

    public boolean isGoalLocation() {
        return goalLocation;
    }

    public void setGoalLocation(boolean goalLocation) {
        this.goalLocation = goalLocation;
    }

    public int getApproximateDistanceFromGoal() {
        return approximateDistanceFromGoal;
    }

    public void setApproximateDistanceFromGoal(int approximateDistanceFromGoal) {
        this.approximateDistanceFromGoal = approximateDistanceFromGoal;
    }

    public Location getParent() {
        return parent;
    }

    public void setParent(Location parent) {
        this.parent = parent;
    }

    public Item getItem() {
        return item;
    }

    public void setItem(Item item) {
        this.item = item;
    }


    @Override
    public String toString() {
        return "Location [location=" + Arrays.toString(location) + ", id=" + id
                + ", description=" + description + ", name=" + name + ", item="
                + item + ", exit=" + Arrays.toString(exit) + "]";
    }


}

And this is the GameMap showing each of the locations and the getStartNode():

public class GameMap {


private Location tiberius;

    public GameMap() {

        //Creating Locations
        tiberius = new Location("Tiberius", 200);
        tiberius.setDescription("You are in the city of Tiberius. There is a sword on the ground in front of you. You see a long street with high buildings and a castle.You see an exit to the south.");

        Location desert = new Location("Desert", 170);
        desert.setDescription("You are in hot dreary desert, surrounded by sand dunes and nothingness, you see an exit to the south.");
        Location jerusalem = new Location("Jerusalem", 270);
        jerusalem.setDescription("You are at battlefield of Jerusalem. You are in awe of your surroundings, you see an exit to the west.");
        Location hattin = new Location("Hattin", 120);
        hattin.setDescription("You are at battlefield of Hattin. You see the ruination of the battle and fallen comrades...You see an exit to the north.");
        Location damascus = new Location("Damascus", 130);
        damascus.setDescription("You are in Damascus. You see the some shady characters...you see an exit to the west.");
        Location tripoli = new Location("Tripoli", 80); 
        tripoli.setDescription("You are in Tripoli. You see the some more shady characters...you see an exit to the north.");
        Location antioch = new Location("Antioch", 60);
        antioch.setDescription("You are in the city of Antioch. You see a long street with high buildings and a castle.. You see the some more shady characters...you see an exit to the north.");
        Location sis = new Location("Sis", 100);
        sis.setDescription("You are in the city of Sis....exit ahead in the west.");
        Location tarsus = new Location("Tarsus", 20);
        tarsus.setDescription("You are in the city of Tarsus. ...you see an exit to the south.");
        Location cyprus = new Location("Cyprus", 0);
        cyprus.setDescription("You have reached the Byzantine Empire, your quest has finished!");
        cyprus.setGoalLocation(true);

        //Adding child locations
        tiberius.addChildLocation(desert, 105);
        desert.addChildLocation(jerusalem, 105);
        jerusalem.addChildLocation(hattin, 323);
        hattin.addChildLocation(damascus, 121);
        damascus.addChildLocation(tripoli, 121);
        tripoli.addChildLocation(antioch, 220);
        antioch.addChildLocation(sis, 126);
        sis.addChildLocation(tarsus, 121);  
        tarsus.addChildLocation(cyprus, 126);



    }



    public Location getStartNode(){
        System.out.println(tiberius.toString());
        return tiberius;

    }

}
Community
  • 1
  • 1
Brian Var
  • 6,029
  • 25
  • 114
  • 212
  • It seems like each location has multiple "next" locations. So how do you know which of the next locations is the one to go to? – satnam Apr 11 '15 at 23:38
  • What do you mean by `"next"`? Each `Location` has a map of children, but you only put one child into each of those `Location`'s map. Is it possible for a `children` map to have more than one child? If not, I'd get rid of the map, just store the child as a `Location`, and add a method to return the child. – ajb Apr 11 '15 at 23:38
  • In this implementation, each location only has one child, I need to keep it as a map as I'm performing a depth first search on it somewhere else in my code. – Brian Var Apr 11 '15 at 23:40
  • If you want a map of children in which there could be more than one child, but the order is important (i.e. the order in which you add the children), look at [`LinkedHashMap`](http://docs.oracle.com/javase/8/docs/api/java/util/LinkedHashMap.html). – ajb Apr 11 '15 at 23:40
  • @satnam in this app, each location only has one next location, so I'm wondering how I can create a method that will iterate to the child of the current location. Then when it is at the next location, iterate to the child of that location, and so on and so on, until the goal location is reached. – Brian Var Apr 11 '15 at 23:42
  • "I need to keep it as a map as I'm performing a depth first search" ... that doesn't make sense. If you can get the child node out of the parent node, you can use that to do your DFS. A map with one element gains you nothing. It's just a clunky way to store the one child. – ajb Apr 11 '15 at 23:43
  • Actually, now that I think of it, if each location has only one child then your structure is more like a list than a tree or graph, so just what do you mean by "depth-first search"? The concept doesn't make much sense. – ajb Apr 12 '15 at 00:03
  • I'm doing a depth first search on the map just to prove I can implement one, I know that doesn't make sense at the moment as there is only one child to each location, but I may add more children to the map further down the line. Just wanted to test first that I can iterate through each location from start to finish by calling the move() – Brian Var Apr 12 '15 at 00:12

2 Answers2

1

Brian, get rid of this field from Location:

Map<Location,Integer> children;

Replace it with two fields.

Location next;
int goalDistance;

Then, in your game controller, keep a reference to the current location of the character.

For example:

Location currentLoc = tiberius;

Then, each time move() is called, just say

currentLoc = currentLoc.next;

satnam
  • 10,719
  • 5
  • 32
  • 42
  • When I tried this, `Location currentLoc = tiberius;` I get tiberius cannot be resolved to a variable, i'm guessing the above is not correct? – Brian Var Apr 12 '15 at 00:18
1

I think you're saying you want a method on the Location class called next() that will return the next location. So why not just do this?

public Location next() {
    Location nextLocation = null;
    for (Location child : children.keySet()) {
        nextLocation = child;
        break;
    }
    return nextLocation;
}

This is based on your assertion that there will only ever be one entry in the children Map, of course. If this ever changes in future, you could add a test (of unknown design at this point) that the child is the one you want:

public Location next() {
    Location nextLocation = null;
    for (Location child : children.keySet()) {
        if (isCorrectChild(child)) {
            nextLocation = child;
            break;
        }
    }
    return nextLocation;
}
Richard Locke
  • 141
  • 1
  • 8
  • Tried the first method, and this error is thrown: "can only iterate over an array or an instance of java.lang.iterable" – Brian Var Apr 12 '15 at 00:05
  • That one took me by surprise! Shows what you get for not trying it out first... Should work now. :-) – Richard Locke Apr 12 '15 at 00:22
  • Okay I'll try that now, not 100% on how this should be called? you see how I am creating the graph in my main class above, do I just create a Location object and call the next method on it? If I call it like this, the next location isn't printed out, `GameMap playerMap = new GameMap(); playerMap.getStartNode(); Location locObj = new Location(); locObj.next();` – Brian Var Apr 12 '15 at 00:23
  • 1
    You probably want to do Location startNode = playerMap.getStartNode() and then do Location nextLocation = startNode.next() and so on. Nothing will be printed out unless you explicitly tell it to, with something like System.out.println(nextLocation.getName()). – Richard Locke Apr 12 '15 at 00:34
  • So I finally got it working but it only iterates to the next location, ie Desert, when I call move, a subsequent time it still loads Desert as the next, although the next from there should be Jerusalem, any ideas why that is? This is the main class as it stands: hastebin.com/ayadixudev.avrasm I'm thinking the next() isn't setting the next location as current after it has moved from the previous. – Brian Var Apr 12 '15 at 01:03
  • @BrianJ The first time you do this on Tiberius, you will get Desert. Make sure that the second time, you're using `next()` on the Desert object (the one returned by the first `next()`), not on the Tiberius object. `next()` on Tiberius will _always_ return Desert. – ajb Apr 12 '15 at 05:39
  • @ajb I'm not sure how I can implement that, calling next on the following object. Could you give a code example of how to do that? – Brian Var Apr 12 '15 at 10:07
  • `Location followingObject = tiberius.next();` then `followingObject.next()`. At some point, you're going need a loop and you will need a `Location` variable that changes values inside the loop to track the current location. – ajb Apr 12 '15 at 19:29