#### Archived

This topic is now archived and is closed to further replies.

# Ants from totwgpg

This topic is 5672 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I''ve been playing with example 12.3 from Lamothe''s book (Tricks of the Windows GPG) and am trying to figure out what''s wrong with the code. This example is showing off AI memory using a set number of ants and piles of food. The ants wander around randomly until they get hungry, then they mosey on over to the food for some mnm''s (they update their memory of where the food is as they wander). If they don''t get to the food in time, they die. Now, the example seems to work fine, except that eventually, one (usually many) of the ants wanders over to a food pile and gets in a state loop between substates ANT_SEARCH_FOOD_S3_VECTOR_2CELL and ANT_SEARCH_FOOD_S4_VECTOR_2FOOD Basically the first tells them to go to the center of the cell with the food, the second tells them to go to the highest value mnm, but then it kicks back. here''s some code (switch off of ant op):

case ANT_SEARCH_FOOD:    // hungry and searching for food

{
// in this state the ant is looking for food based on its memory

// if the memory is blank then random walks

// if the ant gets to a location and cant find any food where its

// memory found some then the memory for that food location is degraded by 1

// searching takes 2 units of energy per cycle

#if 0
ants[index].varsI[ANT_INDEX_AI_STATE]    = ANT_SEARCH_FOOD;

// start off by scanning for food

ants[index].varsI[ANT_INDEX_AI_SUBSTATE] = ANT_SEARCH_FOOD_S1_SCAN;

// initialize targets tp 0

ants[index].varsI[ANT_INDEX_FOOD_TARGET_X] = 0;
ants[index].varsI[ANT_INDEX_FOOD_TARGET_Y] = 0;

#endif

// test substate

switch(ants[index].varsI[ANT_INDEX_AI_SUBSTATE])
{

case ANT_SEARCH_FOOD_S1_SCAN:
{
// this state is transient and doesn''t persist, so

// no energy expended by it

// scan for a "hot" cell

float max_energy = 0;
int cell_x = 0, cell_y = 0;

for (int index_x = 0; index_x < 16; index_x++)
for (int index_y = 0; index_y < 16; index_y++)
// does this cell have more food?

if (ants_mem[index].cell[index_x][index_y] > max_energy)
{
// update new max

max_energy = ants_mem[index].cell[index_x][index_y];
cell_x = index_x; cell_y = index_y;

} // end if

// test max and see if we have a winner?

if (max_energy > 0)
{
// vector to this cell

ants[index].varsI[ANT_INDEX_AI_SUBSTATE] = ANT_SEARCH_FOOD_S3_VECTOR_2CELL;

// send to cell center

ants[index].varsI[ANT_INDEX_FOOD_TARGET_X] = 30*cell_x+15;
ants[index].varsI[ANT_INDEX_FOOD_TARGET_Y] = 30*cell_y+15;

// set counters to 0

ants[index].counter_1 = ants[index].counter_2 = 0;

} // end if

else
{
// go into wander mode, no knowledge of food

// vector to this cell

ants[index].varsI[ANT_INDEX_AI_SUBSTATE] = ANT_SEARCH_FOOD_S2_WANDER;

// set counters

ants[index].counter_1 = RAND_RANGE(100,150);
ants[index].counter_2 = 0;

} // end else

} break;

case ANT_SEARCH_FOOD_S2_WANDER:
{
// wander and look for food, when done wandering go back and scan

// burn food

ants[index].varsI[ANT_INDEX_HUNGER_LEVEL]+=1;

// move the ant

ants[index].x+=ant_movements_x[ants[index].varsI[ANT_INDEX_DIRECTION]];
ants[index].y+=ant_movements_y[ants[index].varsI[ANT_INDEX_DIRECTION]];

// test if ant is done with direction and needs a new one

if (--ants[index].counter_2 < 0)
{
// set direction

ants[index].varsI[ANT_INDEX_DIRECTION] = RAND_RANGE(ANT_ANIM_UP, ANT_ANIM_LEFT);

// time in this new direction

ants[index].counter_2 = RAND_RANGE(10, 100);

// start animation

Set_Animation_BOB(&ants[index], ants[index].varsI[ANT_INDEX_DIRECTION]);

} // end if new direction

// update memory with presence of food

int ant_cell_x = ants[index].x / 30;
int ant_cell_y = ants[index].y / 30;

// this updates the i,jth memory cell in ant with info about food

float food_near_ant = Food_Near_Ant(ant_cell_x, ant_cell_y);

ants_mem[index].cell[ant_cell_x][ant_cell_y] =
ANT_MEMORY_RESIDUAL_RATE*ants_mem[index].cell[ant_cell_x][ant_cell_y] +
(1-ANT_MEMORY_RESIDUAL_RATE)*food_near_ant;

// test if we just bumped into some food

if (food_near_ant > 0)
{
// find highest source of food

int food_x = -1;
int food_y = -1;

// find the highest food source in cell

int food_id = Max_Food_In_Cell(ant_cell_x, ant_cell_y, &food_x, &food_y);

// pre-empt into vector 2 food

ants[index].varsI[ANT_INDEX_AI_SUBSTATE] =
ANT_SEARCH_FOOD_S4_VECTOR_2FOOD;

// send to exact position

ants[index].varsI[ANT_INDEX_FOOD_TARGET_X] = food_x;
ants[index].varsI[ANT_INDEX_FOOD_TARGET_Y] = food_y;

// set target id of food

ants[index].varsI[ANT_INDEX_FOOD_TARGET_ID] = food_id;

// set counters to 0

ants[index].counter_1 = ants[index].counter_2 = 0;

} // end if

// test if we are done with this state and need to go back to scan

else
if (--ants[index].counter_1 < 0)
{
// go back to scan state

ants[index].varsI[ANT_INDEX_AI_SUBSTATE] = ANT_SEARCH_FOOD_S1_SCAN;

} // end if

} break;

case ANT_SEARCH_FOOD_S3_VECTOR_2CELL:
{
// this substate vectors the ant to the center of the cell, once

// there the ant "looks" to see if there actually is any food, if so

// vectors to it, else goes back and scans

// burn food

ants[index].varsI[ANT_INDEX_HUNGER_LEVEL]+=2;

// pick direction

int dx = ants[index].varsI[ANT_INDEX_FOOD_TARGET_X] - ants[index].x;
int dy = ants[index].varsI[ANT_INDEX_FOOD_TARGET_Y] - ants[index].y;

// pick maxium delta to move in

if (abs(dx) >= abs(dy))
{
// x dominate

if (dx > 0)
{
// move right

if (ants[index].varsI[ANT_INDEX_DIRECTION] != ANT_ANIM_RIGHT)
{
// start animation right

ants[index].varsI[ANT_INDEX_DIRECTION] = ANT_ANIM_RIGHT;
Set_Animation_BOB(&ants[index], ants[index].varsI[ANT_INDEX_DIRECTION]);
} // end if

ants[index].x+=ant_movements_x[ants[index].varsI[ANT_INDEX_DIRECTION]];
} // end if

else
if (dx < 0)
{
// move left

if (ants[index].varsI[ANT_INDEX_DIRECTION] != ANT_ANIM_LEFT)
{
// start animation left

ants[index].varsI[ANT_INDEX_DIRECTION] = ANT_ANIM_LEFT;
Set_Animation_BOB(&ants[index], ants[index].varsI[ANT_INDEX_DIRECTION]);
} // end if

ants[index].x+=ant_movements_x[ants[index].varsI[ANT_INDEX_DIRECTION]];

} // end else

} // end if x

else
{
// y dominate

if (dy > 0)
{
// move down

if (ants[index].varsI[ANT_INDEX_DIRECTION] != ANT_ANIM_DOWN)
{
// start animation down

ants[index].varsI[ANT_INDEX_DIRECTION] = ANT_ANIM_DOWN;
Set_Animation_BOB(&ants[index], ants[index].varsI[ANT_INDEX_DIRECTION]);
} // end if

ants[index].y+=ant_movements_y[ants[index].varsI[ANT_INDEX_DIRECTION]];
} // end if

else
if (dy < 0)
{
// move up

if (ants[index].varsI[ANT_INDEX_DIRECTION] != ANT_ANIM_UP)
{
// start animation down

ants[index].varsI[ANT_INDEX_DIRECTION] = ANT_ANIM_UP;
Set_Animation_BOB(&ants[index], ants[index].varsI[ANT_INDEX_DIRECTION]);
} // end if

ants[index].y+=ant_movements_y[ants[index].varsI[ANT_INDEX_DIRECTION]];
} // end else

} // end else

// update memory image ????

// update memory with presence of food

int ant_cell_x = ants[index].x / 30;
int ant_cell_y = ants[index].y / 30;

// this updates the i,jth memory cell in ant with info about food

float food_near_ant = Food_Near_Ant(ant_cell_x, ant_cell_y);

ants_mem[index].cell[ant_cell_x][ant_cell_y] =
ANT_MEMORY_RESIDUAL_RATE*ants_mem[index].cell[ant_cell_x][ant_cell_y] +
(1-ANT_MEMORY_RESIDUAL_RATE)*food_near_ant;

// now test if target reached

if (abs(ants[index].x - ants[index].varsI[ANT_INDEX_FOOD_TARGET_X]) < 4 &&
abs(ants[index].y - ants[index].varsI[ANT_INDEX_FOOD_TARGET_Y]) < 4)
{
// center of cell reached, now find the biggest piece of food and

// vector to it, if none exist then go back to scan

// compute cell position

int ant_cell_x = ants[index].x / 30;
int ant_cell_y = ants[index].y / 30;

// this updates the i,jth memory cell in ant with info about food

float food_near_ant = Food_Near_Ant(ant_cell_x, ant_cell_y);

// test if we just bumped into some food

if (food_near_ant > 0)
{
// find highest source of food

int food_x = -1;
int food_y = -1;

// find the highest food source in cell

int food_id = Max_Food_In_Cell(ant_cell_x, ant_cell_y, &food_x, &food_y);

// pre-empt into vector 2 food

ants[index].varsI[ANT_INDEX_AI_SUBSTATE] =
ANT_SEARCH_FOOD_S4_VECTOR_2FOOD;

// send to exact position

ants[index].varsI[ANT_INDEX_FOOD_TARGET_X] = food_x;
ants[index].varsI[ANT_INDEX_FOOD_TARGET_Y] = food_y;

// set target id of food

ants[index].varsI[ANT_INDEX_FOOD_TARGET_ID] = food_id;

// set counters to 0

ants[index].counter_1 = ants[index].counter_2 = 0;

} // end if

else
{
// set mode to scan

ants[index].varsI[ANT_INDEX_AI_SUBSTATE] = ANT_SEARCH_FOOD_S1_SCAN;
} // end else

} // end if

} break;

case ANT_SEARCH_FOOD_S4_VECTOR_2FOOD:
{
// this substate vectors the ant to the exact x,y of the food

// once there, tests to see if there is food there, if so eats it,

// else go to scan

// burn food

ants[index].varsI[ANT_INDEX_HUNGER_LEVEL]+=2;

// pick direction

int dx = ants[index].varsI[ANT_INDEX_FOOD_TARGET_X] - ants[index].x;
int dy = ants[index].varsI[ANT_INDEX_FOOD_TARGET_Y] - ants[index].y;

// pick maxium delta to move in

if (abs(dx) >= abs(dy))
{
// x dominate

if (dx > 0)
{
// move right

if (ants[index].varsI[ANT_INDEX_DIRECTION] != ANT_ANIM_RIGHT)
{
// start animation right

ants[index].varsI[ANT_INDEX_DIRECTION] = ANT_ANIM_RIGHT;
Set_Animation_BOB(&ants[index], ants[index].varsI[ANT_INDEX_DIRECTION]);
} // end if

ants[index].x+=ant_movements_x[ants[index].varsI[ANT_INDEX_DIRECTION]];

} // end if

else
if (dx < 0)
{
// move left

if (ants[index].varsI[ANT_INDEX_DIRECTION] != ANT_ANIM_LEFT)
{
// start animation left

ants[index].varsI[ANT_INDEX_DIRECTION] = ANT_ANIM_LEFT;
Set_Animation_BOB(&ants[index], ants[index].varsI[ANT_INDEX_DIRECTION]);
} // end if

ants[index].x+=ant_movements_x[ants[index].varsI[ANT_INDEX_DIRECTION]];

} // end else

} // end if x

else
{
// y dominate

if (dy > 0)
{
// move down

if (ants[index].varsI[ANT_INDEX_DIRECTION] != ANT_ANIM_DOWN)
{
// start animation down

ants[index].varsI[ANT_INDEX_DIRECTION] = ANT_ANIM_DOWN;
Set_Animation_BOB(&ants[index], ants[index].varsI[ANT_INDEX_DIRECTION]);
} // end if

ants[index].y+=ant_movements_y[ants[index].varsI[ANT_INDEX_DIRECTION]];

} // end if

else
if (dy < 0)
{
// move up

if (ants[index].varsI[ANT_INDEX_DIRECTION] != ANT_ANIM_UP)
{
// start animation down

ants[index].varsI[ANT_INDEX_DIRECTION] = ANT_ANIM_UP;
Set_Animation_BOB(&ants[index], ants[index].varsI[ANT_INDEX_DIRECTION]);
} // end if

ants[index].y+=ant_movements_y[ants[index].varsI[ANT_INDEX_DIRECTION]];

} // end else

} // end else

// update memory image ????

// update memory with presence of food

int ant_cell_x = ants[index].x / 30;
int ant_cell_y = ants[index].y / 30;

// this updates the i,jth memory cell in ant with info about food

float food_near_ant = Food_Near_Ant(ant_cell_x, ant_cell_y);

ants_mem[index].cell[ant_cell_x][ant_cell_y] =
ANT_MEMORY_RESIDUAL_RATE*ants_mem[index].cell[ant_cell_x][ant_cell_y] +
(1-ANT_MEMORY_RESIDUAL_RATE)*food_near_ant;

// now test if target reached

if (abs(ants[index].x - ants[index].varsI[ANT_INDEX_FOOD_TARGET_X]) < 4 &&
abs(ants[index].y - ants[index].varsI[ANT_INDEX_FOOD_TARGET_Y]) < 4)
{
// food reached, now find the biggest piece of food and

// vector to it, if none exist then go back to scan

// is there any food left?

if (ants[index].varsI[ANT_INDEX_FOOD_TARGET_ID] > 0)
{
// thank god!

Set_New_State(ANT_EATING, index, ants[index].varsI[ANT_INDEX_FOOD_TARGET_ID],0);
} // end if

else
{
// go back to scan

ants[index].varsI[ANT_INDEX_AI_SUBSTATE] = ANT_SEARCH_FOOD_S1_SCAN;

} // end if

} // end if

} break;

case ANT_SEARCH_FOOD_S5: break;
case ANT_SEARCH_FOOD_S6: break;
case ANT_SEARCH_FOOD_S7: break;

default: break;
} // end switch

} break;

anyone know what''s happening here? I want to help these ants!

##### Share on other sites
It is highly unlikely that anyone is going to wade through your code to work out what it''s doing. You would be far better served by writing out the algorithm that your code implements. That way we can check the algorithm for errors that might produce the errant behaviour. If the algorithm is not at fault, then the problem is one of debugging, and there are more appropriate places to get help with that.

Cheers,

Timkin

##### Share on other sites
quote:
Original post by Timkin
It is highly unlikely that anyone is going to wade through your code to work out what it''s doing. You would be far better served by writing out the algorithm that your code implements. That way we can check the algorithm for errors that might produce the errant behaviour. If the algorithm is not at fault, then the problem is one of debugging, and there are more appropriate places to get help with that.

Cheers,

Timkin

Well I figured out what was wrong, and it wasn''t the algorithm. In one of the checks to see if food was existent, the code author (not I) had done a check off of the food morsel''s id rather then the energy value of the food. So everytime an ant wanted to eat food_id 0, he got confused and looped until he died (poor little guy). I''m sorry for the huge code dump, but I thought that the algorithm was the problem and didn''t know what I should put up to give an idea of what I was working with. I was really hoping that someone who had read this book may have noticed the same problem and knew what was causing it. But the ants have been debugged now so no worries.

Pun intended.

"I''ve never seen that. I''ve never seen anybody drive their garbage down to the side of the street and bang the hell out of it with a stick. I''ve never seen that."