// Swarm library. Copyright � 1996-2000 Swarm Development Group.
// This library is distributed without any warranty; without even the
// implied warranty of merchantability or fitness for a particular purpose.
// See file LICENSE for details and terms of copying.
/*
Agent2d.h
Barry McMullin <mcmullin@eeng.dcu.ie>
26-SEP-1996
This class provides an object abstraction for the
idea of an "agent" embedded in a discrete, 2D
(toroidal), rectangular lattice. Agent2d objects are
things that can retain their individuality (more
specifically, their *state*) as they move around in a
DiscreteToroid space.
This class is not of much use in itself; it is rather
intended for subclassing to implement specific kinds
of agents.
An Agent2d object exists at a position in a
DiscreteToroid space. It has methods to move itself
to other positions in its "neighborhood" (defined in
more detail below). Agent2d objects won't share
positions in space - so if you tell one to move to
somewhere that is already occupied (i.e. by another
agent2d) this will cause an InternalError exception
to be raised, and terminate the program. An agent2d
also has methods for accessing or referencing other
agent2d's in its neighborhood.
If you want agents in a space that does *not* wrap
toroidially, the recommended way to do it is to
subclass from Agent2d to define a type of agent that
will be absolutely immobile (of course, this
immobility must also be coded into, or respected by,
whatever other kinds of agents you subclass from
Agent2d). Then position these around the periphery
of your space. (Of course, this technique allows for
more general obstacles or containers to be embedded
also.) The advantage of this technique is that you
can avoid overloading a nil return from
-getAgentAtNeighbor (i.e. disambiguating the cases
that there is no neighboring agent, and there is no
neighboring cell for an agent to be in).
Several of the Agent2d methods require an argument
specifying a "neighboring" position. This argument
should be a value of the enumerated type neighbor_t.
See "neighbor.h".
The Agent2d class was originally concepted (in part)
as an abstraction or generalisation of the original
"HeatBug" class.
*/
#import <objectbase.h>
#import "DiscreteToroid.h"
#import "neighbor.h"
@interface Agent2d: SwarmObject {
DiscreteToroid * world;
BOOL embedded; // if YES, then agent is currently embedded in world;
// if NO, agent is currently warped to
// "hyperspace"...
int x, y;
}
-setWorld: (DiscreteToroid *) inWorld;
-createEnd;
/*
-createEnd will fail (raising InternalError) if the
world has not first been initialised (via -setWorld).
Any attempt to use -setWorld: after createEnd will
fail (raising InternalError). agent2d's are created
with embedded == NO, i.e. they are not initially
embedded in world. Use the -unwarpToX:Y: method to
initially embed the agent into the space - but
only *after* -createEnd, and only to a vacant position...
*/
-(DiscreteToroid *) getWorld;
-(BOOL) getEmbedded;
-unwarpToX: (int) inX Y: (int) inY;
/*
This embeds the agent at the specified absolute
position in world. It will fail (raising InternalError)
if the agent is *already* embedded (embedded == YES),
or if the specified position is already occupied.
Its primary intended use is for setting initial agent
position immediately after creation; thereafter, motion
is most robustly accomplished using the -swap methods.
*/
-warp;
/*
This "pulls" the agent out of world - i.e. sets the
relevant pointer in world to nil and sets embedded to
NO. It will fail (raising InternalError) if embedded
is already NO.
*/
-(int) getX;
-(int) getY;
-(int) getNeighborX: (neighbor_t) neighbor;
-(int) getNeighborY: (neighbor_t) neighbor;
/*
All four of the above will fail (raising InternalError)
if embedded == NO.
*/
-moveToX: (int) inX Y: (int) inY;
-moveToNeighbor: (neighbor_t) neighbor;
/*
Both of the above will fail (raising InternalError) if
embedded == NO or the specified position is already
occupied.
*/
-swapWithAgent: (Agent2d *) agent;
/*
Will fail (raising InternalError) if
self:embedded == NO, or agent == nil, or
agent:embedded == NO, or if agent:world != self:world.
*/
-swapWithAgentAtX: (int) inX Y: (int) inY;
-swapWithAgentAtNeighbor: (neighbor_t) neighbor;
/*
Both of the above will fail (raising InternalError)
if embedded == NO.
Both will work regardless of whether the specified position
contains another agent or is nil.
*/
-(Agent2d *) getAgentAtNeighbor: (neighbor_t) neighbor;
/*
Will fail (raising InternalError) if embedded == NO.
*/
@end