0

Sorry for the slightly demented wording of this question, but I'm very new to agent-oriented thinking (are these 'patterns'?) and only slightly less new to java, and I'm struggling with what feels like a very basic problem.

I'm doing a lot of this 'intuitively' (i.e. blindly) rather than trying to understand someone else's code - partly because I struggle to understand code that's 'above my level', but also because I hope doing it 'my way' will help me appreciate the right way later.

Basically, I'm modelling an agent (a robot vacuum) in an environment (a House). A House contains a collection (HashMap) of Rooms. A House has a method getRoom(int key) that returns a Room matching the given key. The Agent has a State, which at this point keeps track of a room ID (which is also the key in the House), which is the room the robot is 'in' for the purposes of navigating the world; a State also describes whether or not the room is known to be dirty. When the agent is constructed, it's initialised with an ID (It must be created 'in a room'), but it is not given the dirty/clean status of the Room. I want the agent to check for dirt - this would involve invoking the getRoom() method in House. However, with the Java I've learned so far, I don't know how to do this. I know I could access that method by creating a House inside java, or by making the method static, but those won't work - the agent needs to know about the SPECIFIC house that is in memory, the one that has been initialised with Rooms.

tl;dr: How can an Agent object obtain a reference to an object that is stored in a HashMap inside another Environment object?

P.S here is my imagined model for the 'higher level' perspective enabled by this approach: I kind of intuitively wanted the Agent to be wholly responsible for its own precepts and behaviours, so that the code higher up would look more like:

agent.percieve()                           //agent checks the room it thinks its in for dirt and exits
if (agent.gotDirt()) agent.clean()         //agent activates its cleaning device if it found dirt in this room
if (agent.gotDirt() == false) agent.move() //agent picks an exit and leaves the room
Toadfish
  • 1,112
  • 1
  • 12
  • 22
  • I realize that one approach would be to do the logic about updating the Agent's state, and modelling the agent's actions, in another layer, eg World or Game, which creates a House object and an Agent object and thus has direct access to both. I'll probably end up doing this, but I was looking to see if there is another way – Toadfish Mar 28 '15 at 07:06
  • The first answer works brilliantly for my case, but [this question](http://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value) helped a lot in terms of my actual understanding of the pass-by-reference vs. pass-by-value dilemma that comes into play here. One of the top answers on that question references [this article](http://javadude.com/articles/passbyvalue.htm), which helped even more. If anyone somehow got here while trying to solve a similar problem where pass-by-reference vs. pass-by-value is relevant, those resources should prove invaluable. – Toadfish Mar 28 '15 at 09:15

1 Answers1

1

The vacuum cleaner (i.e. what you call an "Agent", but why name it like this since it's, in fact, a vacuum cleaner?) simply needs a reference to the House object it belongs to:

// a single House is constructed
House house = new House(); 
// omitted: add rooms to the house...

// create a first vacuum cleaner for the house. A reference to the house is given to this cleaner
VacuumCleaner vacuumCleaner = new VacuumCleaner(house);
System.out(vacuumCleaner.isRoomClean(2)); // prints false, because room 2 is full of dirt
vacuumCleaner.cleanRoom(2);
System.out(vacuumCleaner.isRoomClean(2)); // prints true, because the vacuum cleaner removed the dirt from room 2

// now let's create a second vacuum cleaner for the same house
VacuumCleaner vacuumCleaner2 = new VacuumCleaner(house);
System.out(vacuumCleaner2.isRoomClean(2)); // prints true, because room 2 has no dirt: it has previously been removed from the room by the first vacuum cleaner.

EDIT

And here's how the VacuumCleaner class would look like:

public class VacuumCleaner
    /**
     * The house that this vacuum cleaner cleans 
     */
    private House house;

    public VacuumCleaner(House houseToClean) {
        this.house = houseToClean;
    }

    public boolean isRoomDirty(int roomId) {
        // find the room in the house, and see if it contains dirt
    }

    public void cleanRoom(int roomId) {
        // find the room in the house, and remove dirt from it
    }
}
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • The only problem with this is that I wanted the house to exist independently of the vacuum, e.g. so that there could be multiple vacuum cleaners existing within the same house, or so that a particular vacuum could have incorrect information about the house (and appropriate ways of discovering and dealing with that case). At the same time I don't want the vacuum behavior to be the responsibility of the house (e.g creating the vacuum inside the House object and having methods in House to update the vacuum's state and determine behaviour etc). – Toadfish Mar 28 '15 at 07:39
  • So basically, I'm trying to create (intentional) redundancy: The world exists, and then a vacuum has to 'explore' (send and receive messages from the House object) to create its own internal model of that world - analogous to how a physical robot would have to behave in a real house. – Toadfish Mar 28 '15 at 07:42
  • 1
    Read the code again. The house doesn't have any knowledge of the vacuum cleaner. It's the reverse: the vacuum cleaner knows about the house. And you can perfectly create another vacuum cleaner for the same house. – JB Nizet Mar 28 '15 at 07:59
  • Ah, I thought `house` in this case was a property belonging to the vacuum cleaner, but instead you're giving an existing House to a constructor for the Vacuum? I can see why this would work, as each vacuum you created would be 'given' the same original house.... but would each vacuum cleaner be operating in the original house, or in a copy of it? If vacuum1 cleans room 100, is room 100 clean for vacuum2? – Toadfish Mar 28 '15 at 08:14
  • 1
    You pass a **reference** (a pointer, if you prefer) to a house to the vacuum cleaner constructor, so that the vacuum cleaner keeps this **reference** to the house. No copy is made. Two vacuum cleaners constructed with the same house both have a reference to the same house. So if one cleans the room of this house, the other will see the room as clean. – JB Nizet Mar 28 '15 at 08:17
  • Right! I am still super fuzzy on the finer points of pass by reference vs pass by value. I thought that in Java this would only pass the value of the house, eg its contents, which would then go into a new property inside the vacuum object itself. So just to get this 100% straight, when the constructor for the Vacuum class takes a house, how is the house referred to from then on by methods in the Vacuum class? Does the constructor store a new reference to that same house inside the new vacuum object? (By this i mean the vacuum has a property `house` of type House?) – Toadfish Mar 28 '15 at 08:25
  • 1
    See my edit. Objects are never passed in Java. **References** to objects are passed. So, the variable `house` in the main code, the field `house` in `vacuumCleaner`, and the field `house` in `vacuumCleaner2` are three references to the same House object, created by `new House()`. – JB Nizet Mar 28 '15 at 08:31