/*******************************+
*
* Testfile for the FSL-Language
* Version 1.0.1-01
*
* Nr.1
*
*************************************/

/********************************
* This example shows a simple world
* which will be used as an environment
* for some simple cognitive agents
**********************************/

system sys1 (int COLs, int ROWs)[int INHABITANTS, int HISTORY days]{ 

// The world consists of a grid of COLs x ROWs many cells
// The input parameters have to be provided by a calling program

// It's not necessary but highly recommend to set some deafult
// values for the input parameters

if(isequ(COLs,0))[B]{COLs = 8;}
if(isequ(ROWs,0))[B]{ROWs = 8;}

struct CELL { //Every cell cas x-y-coordinates and a content

   int X;    // From left-to-right, start with 0
   int Y;    // From upper-to-lower, start with 0
   str content;  // "o" := obstacle "e" := eatable "_" := free

  //If an agent is positioned in a cell it is an obstacle with name "o:agent_name"

};


struct CELL World1[mul(COLs,ROWs)[NUM]]; 

// The world as a COLs x ROWs - 2D-Field is stored as a 1D-Array	

// In a more advanced version of this LModel can the LModel asked the
// user for some parameters by communication. Then it can change
// the actual states by system-calls.

// For the first version of this program we assume default values
// One has to set some values

// We will place 8 obstacles and 4 eatables...

/*****************************

________ <== 1-8
________ <== 9-16
__e_o___ <== 17-24 
____o___ <== 25-32
____o___ <== 33-40
______o_  <== 41-48
__oo__o_ <== 49-56
__e__o_e <== 57-64

*********************************/

// The 2D-field is considered with x-axis from left to right,
// y-axis from upper to lower
// Counting ist started with (X,Y) = (0,0)
// Arrays start counting with 1!

// Because only some of the elements of the array World1 will  
// explicitely be set it is recommended to give all elements
// some default value:

int Count = 1;

while(less(Count,65))[B]{ //loop for whole Array World1

int YCount = 0;

while(less(YCount,8))[B]{ //loop for Y-Counts

int XCount = 0;


while(less(XCount,8))[B]{ //loop for X-Counts


World1[Count].X = XCount;
World1[Count].Y = YCount;
World1[Count].Content = "_";

add(Count,1);
add(XCount,1);

}

add(YCount,1);

}

}

World1[19].X=2;
World1[19].Y=2;
World1[19].Content="e";

// Every element of the World1 is a struct of type CELL
// The elements of a struct are named by a DOT-Operator '.'

World1[21].X=4;
World1[21].Y=4;
World1[21].Content="o";

World1[29].X=4;
World1[29].Y=3;
World1[29].Content="o";

World1[37].X=4;
World1[37].Y=4;
World1[37].Content="o";

World1[47].X=6;
World1[47].Y=5;
World1[47].Content="o";

World1[51].X=2;
World1[51].Y=6;
World1[51].Content="o";

World1[52].X=3;
World1[52].Y=6;
World1[53].Content="o";

World1[55].X=6;
World1[55].Y=6;
World1[55].Content="o";

World1[59].X=2;
World1[59].Y=7;
World1[59].Content="e";

World1[62].X=5;
World1[62].Y=7;
World1[62].Content="o";

World1[64].X=7;
World1[64].Y=7;
World1[64].Content="e";

// After these assertions has the interpreter automatically generated
// an Array with 64 elements where only those elements explicitly 
// asserted above have special values

                              
/**********************************************************+
*
* Now is the basic data structure configured. 
* In what follows must the simulator of this world communicate 
* with possible inhabitants of this world.
* An inhabitant must have an 'identity', possibly a 'rank'
* within the group of possible inhabitants and he must
* communicate which kind of 'actions' he is intending
* to do. The following minimal list of possible actions
* is assumed:
*
* A possible inhabitant is sending the following login-action
* by a pes_sim_send-system call:
*
* pes_sim_send("ID:RANK:SENDTIME:login:x-pos:y-pos:dir")
*
* A possible SimWorld is receiving the following login-action
* by a pes_sim_receive-system call:
*
* pes_sim_receive("ID:RANK:SENDTIME:RECEIVETIME:login:x-pos:y-pos:dir")
*
* The possible inhabitant can 'want' to be located at a certain
* x-y-position headed in direction 'dir'; if not possible he will 
* receive another position 'nearby':
*
* pes_sim_send("ID:RANK:SENDTIME:login-response:x-pos:y-pos:dir")
*
* A logged in inhabitant is sending the following logout-action
* by a pes_sim_send-system call:
*
* pes_sim_send("ID:RANK:SENDTIME:logout")
*
* pes_sim_receive("ID:RANK:SENDTIME:RECEIVETIME:logout")
*
* The Simworld will answer:
*
* pes_sim_send("ID:RANK:SENDTIME:logout-response")
*
* A logged in inhabitant is sending the following move-action
* specifying a distance [0,1] and a direction [0-3]:
*
* pes_sim_send("ID:RANK:SENDTIME:move:distance:dir")
*
* pes_sim_receive("ID:RANK:SENDTIME:RECEIVETIME:move:distance:dir")
*
* The SimWorld will answer. If a move is not possible on account of 
* an obstacle the response will send a distance=0:
*
* pes_sim_send("ID:RANK:SENDTIME:move-response:distance:dir")
*
*  A logged in inhabitant is sending the following eat-action
*
* pes_sim_send("ID:RANK:SENDTIME:eat")
*
* pes_sim_receive("ID:RANK:SENDTIME:RECEIVETIME:eat")
*
* The SimWorld will answer and specifying the amount of energy
* which could be gained by eating:
*
* pes_sim_send("ID:RANK:SENDTIME:eat-response:energy")
*
******************************************************************/

while(true)[B]{ // This is the main SimWorld-Loop

// In this version it will not be possible to send an
// external command to force the system to stop

receive(NextItemIncomingQueue)[B];

if(findsubstr("login",NextItemIncomingQueue)[B])[B]{ // Process Login

loginsys(NextItemIncomingQueue)[LoginResponse];
}

elseif(findsubstr("eat",NextItemIncomingQueue)[B])[B]{ // Process Eat

logoutsys(NextItemIncomingQueue)[LogoutResponse];
}

elseif(findsubstr("move",NextItemIncomingQueue)[B])[B]{ // Process Move

movesys(NextItemIncomingQueue)[MoveResponse];
}

elseif(findsubstr("logout",NextItemIncomingQueue)[B])[B]{ // Process Logout

eatsys(NextItemIncomingQueue)[EatResponse];
}

else{ // Nothing to do }

}// End of while-Loop

}// End of root-system

/*******************************************************+
*
* Declarations of some subsystems
*
***********************************************************
*
* loginsys()
*
******************************************************************/

system loginsys(str NextItemIncomingQueue)[bool LoginResponse]{


struct LoginResult {

int ID;
int RANK;
int SENDTIME;
int RECEIVETIME;
int Xpos;
int Ypos;
int Dir;
};

// The different parts of the string have to be parsed

LoginResult = loginsys_parse(NextItemIncomingQueue)[ID,RANK,SENDTIME,RECEIVETIME,Xpos,Ypos,Dir];

// Then the request for login has to be converted into
// the action to locate a new inhabitant in the world
// If the intended position is already occupied an alternative
// position has to be found
// After that the request has to be answered

}

system logoutsys(str NextItemIncomingQueue)[boolLogoutResponse]]{

struct LogoutResult {

int ID;
int RANK;
int SENDTIME;
int RECEIVETIME;
};

// The different parts of the string have to be parsed


LogoutResult = logoutsys_parse(NextItemIncomingQueue)[ID,RANK,SENDTIME,RECEIVETIME];

// Then the request for logout has to be converted into
// the action to remove an registered inhabitant from the world
// After that the request has to be answered
}

system movesys(str NextItemIncomingQueue)[boolMoveResponse]]{

struct MoveResult {

int ID;
int RANK;
int SENDTIME;
int RECEIVETIME;
int Distance;
};

// The different parts of the string have to be parsed

MoveResult = movesys_parse(NextItemIncomingQueue)[ID,RANK,SENDTIME,RECEIVETIME,Distance];

// Then the request for a move has to be converted into
// the action to locate a registered inhabitant on a new position.
// If the intended position is already occupied this has to
// be communicated to the sender
// After that the request has to be answered

}

system eatsys(str NextItemIncomingQueue)[boolEatResponse]]{

struct EatResult {

int ID;
int RANK;
int SENDTIME;
int RECEIVETIME;
int Energy;
};

// The different parts of the string have to be parsed

EatResult = eatsys_parse(NextItemIncomingQueue)[ID,RANK,SENDTIME,RECEIVETIME,Energy];

// Then the request for an eat has to be converted into
// the action to eat that eatable 'ahead' of the actual position.
// After that the request has to be answered with the amount of gained
// energy
}