25 Years of Programming
An open source source for C, C++, OWL, BASIC, MDB, XLS, DOT, and more...
Home   Projects   Up   Sitemap   Search   Blog   Forum+Chat   About Us   Privacy   Terms of Use   Feedback   FAQ   Images   Services   Payments   Humor   Music

Artificial life evolution demonstration program, code for the agents (cells), Borland C++ ObjectWindows

This page shows additional code for the WAdapt.cpp artificial life evolution program that didn't fit on the project's main web page.

The listing shows code for

  • A dialog box
  • The Agent class which holds a single agent (cell) and defines its behavior
  • SColonyWindow, a class that manages a set (colony) of cells
  • A library module that pulls other needed routines into the program

The listings have links to other site pages that have additional code required for this large project. A more complete description of this program is on its home page (see link above).

agent.h

/*	agent.h			01-22-02
	This file is part of the WADAPT project.
	Copyright (C)1995-2002 Steven Whitney.

	Published under GNU GPL (General Public License) Version 3, with ABSOLUTELY NO WARRANTY.
	Initially published by http://25yearsofprogramming.com.

	Declarations for dialogs, agent, and SColonyWindow.

*/
#ifndef __AGENT_H
#define __AGENT_H

#include <owl\owlpch.h>
#include <owl\dialog.h>
#include <owl\point.h>
#include <classlib\arrays.h>
#include <classlib\time.h>
#include <complex.h>
#pragma hdrstop

#include "c:\bcs\my.h"
#include "c:\bcs\library\trigtabl.h"
#include "c:\bcs\library\ddemlapp.h"
#include "c:\bcs\library\sdibwin.h"
// Win32s has no serial communications abilities
#if !defined(__WIN32__)
	#include "c:\bcs\library\wserial.h"
#endif	//!defined(__WIN32__)

#define ALL				( 0UL)
#define WEAKER			( 1UL)
#define STRONGER		( 2UL)
#define SAMESPECIES		( 4UL)
#define DIFFSPECIES		( 8UL)
#define MORECHILDREN	(16UL)

#define TERMFREQ	5	// 1 opcode in this many is a terminating 0

//////////////////////////////////////////////////////////////////////////////
// transfer information for the Options dialog box
struct OpStruct
{
	OpStruct();
	OpStruct(const OpStruct& other);    				// copy
	OpStruct& operator = (const OpStruct& other);   	// assignment

	// order here MUST match order in SOptionsDialog constructor!
	BOOL trailon;		// whether to show trail as a point moves
	BOOL beepon;		// whether to use sound effects
	BOOL lookon;		// whether to show direction of sight
	BOOL displayon;		// whether to show cells at all
	BOOL fittowindow; 	// local copy of fittowindow

	char dibsize[20]; 		// text for dibwidth, dibheight
	char stepmax[10]; 		// text for # of steps agents run per run() call

	char maxpopedit[10];
	char optpopedit[10];
	char minpopedit[10];

	char passlimitedit[10];	// these must be char[], not strings
};
//////////////////////////////////////////////////////////////////////////////
// options dialog box
class SOptionsDialog : public TDialog
{
public:
	SOptionsDialog(TWindow*, TResId, OpStruct*);

protected:
	void CmHelp();

DECLARE_RESPONSE_TABLE(SOptionsDialog);
};
/////////////////////////////////////////////////////////////////////////
// entity, shown as a screen dot, that can move around, interact with others, etc.
class SColonyWindow;			// forward ref

class agent
{
public:
	agent(SColonyWindow&);         						// MUST be a colony member
	agent(const agent&);                                // copy
	~agent();					 						// destructor

	agent& operator = (const agent& other);                   	// assignment
	BOOL operator == (const agent& other) const;
	friend ostream& operator << (ostream& os, const agent& a);  // write
	friend istream& operator >> (istream& is, agent& a);	  	// read

	// functions
	int run();
	BOOL IsAlive();
	void play(int state);				// plays a sound
	int divide();						// cell division (identical copy)
	uint calcdistance(agent* other);	// distance from this to another agent
	BOOL samespecies(agent* other);		// test whether other is same species
	double SimilarityTo(const agent& other);
	void AddEnergy(double amount);		// add or subtract, and recalc Col->Strongest

	// when called with no args, this resets all the "nearest" variables
	void SetNearest(agent* nearest = 0, uint dist = MAXUINT,
					ulong lastOR = ALL, ulong lastAND = ALL)
	{ Nearest = nearest; NearestDist = dist; LastSelectOR = lastOR; LastSelectAND = lastAND; }


	// variables
	static int ICOUNT;					// NUMBER of instructions being used this run
	static int ABSICOUNT;				// total NUMBER of instructions in cell instruction set
	static int MAXPGMLENGTH;		 	// 1000 agents * 200 = 200k for pgms.
	static double STARTENERGY;			// amount of energy a cell is born/initialized with
	static int STEPMAX;					// agent executes STEPMAX instructions per run() entry
	static const char* opcodes[];
	static Trigtable t;                	// so they only have to be calculated once
	enum { DEAD, BORN, EATEN, RUN };	// states for sound effects

	SColonyWindow* Col;			   		// the Colony (group) this agent belongs to

	// must use doubles for true loc, or agent could only move in multiples of 45 degrees
	complex Loc;		// this cell's space location
	TPoint ScrLoc;		// screen location, used often
	int color;      	// dot leaves a TRAIL in this color (the dot itself is always white)
	double energy;		// dies when <= 1;  see IsAlive().  USE ADDENERGY() TO CHANGE VALUE.
	unsigned children;	// number of offspring this cell has produced
	unsigned ate;		// number of cells this one has eaten
	long id;			// i.e. this cell is the Nth cell born
	string pgm;			// holds the agent's program.  NEVER use pgm.c_str() (contains NULLS)
	double heading;		// direction of motion (and sight): 0=East, 90=North
	double ax;			// math & test register (accumulator)
	int ip;         	// instruction pointer: next instruction to execute
	int maxip;			// highest pgm loc it has ever executed
	uint segments;		// number of segments (0 terminators) in pgm
	agent* inview;		// pointer to the agent object currently in line of sight

	agent* Nearest;		// used in FindNearest, it can hold nearest OR neareststronger, etc.
	uint NearestDist;	// used in FindNearest, distance from the last found Nearest.
	ulong LastSelectOR;	// used in FindNearest, the flags from most recent FindNearest
	ulong LastSelectAND;// used in FindNearest, the flags from most recent FindNearest

protected:
	// functions
	void incrementip(BOOL);
	void decrementip();
	void jumpforward();
	void jumpbackward();

	int mate(agent* other);				// mate, using currently selected method
	int shuffle(agent* other);			// mate, shuffling all genes (my version)
	int ShuffleSegments(agent* other);	// mate, shuffling pgm SEGMENTS (my version)
	int crossover(agent* other);		// mate using crossover from book
	void mutate();						// mutates pgm

	void turntoward(complex loc);
	void turnawayfrom(complex loc);

	agent* move();
	agent* sense();						// update all sensors with current surroundings
	void eat(agent* other);
};
//----------------------------------------------------------------------------
// 							end agent
//////////////////////////////////////////////////////////////////////////////
// holds a colony of agents, maintains the set, and handles screen display.
// An agent (cell) is always one pixel of the SDib, and all drawing is done to
// the SDib. But since the SDib is scaled to the window size, the size of a
// cell can be enlarged to whatever is most convenient for viewing.
// But if you're not viewing it, the program's calculations run much faster
// if the Dib is not scaled to the window size or if drawing is turned off completely.
class SColonyWindow : public SDibWindow
{
public:
	SColonyWindow(TWindow *parent = 0);
	~SColonyWindow();

	friend ostream& operator << (ostream& os, const SColonyWindow& s);	// write
	friend istream& operator >> (istream& is, SColonyWindow& s);		// read

	// functions
	static uint logerror(string error = ""); // accessible thruout pgm by one means or another

	// array management
	agent* AddAgent();			// tries to add a generic agent, returns ptr to it, or 0
	int DestroyAgent(agent*);	// override base member
	void Flush();

	//
	BOOL IsOccupied(const TPoint&);			// whether there is an agent at that loc
	agent* Occupant(const TPoint&);			// ptr to agent at that loc, or 0
	ulong Compare(agent* first, agent* second);
	BOOL ScreenFor(agent* first, agent* second, ulong selectOR, ulong selectAND);
	agent* FindNearest(agent*, ulong selectOR = ALL, ulong selectAND = ALL);
	agent* FindMostSimilar(agent*);
	int mapneighbors(agent*, int& map);
	agent* pickadjacent(agent*);		  	// randomly choose an adjacent cell (if any)
	void Open(string filename);

	complex centerofmass();
	complex getcenterofmass();
	complex screencenter();

	// display handling
	void SetPixel(const TPoint& p, int palindex);
	BOOL screenwrap(complex& point);
	void ShowAgent(agent* a);
	void MoveAgent(agent*, const TPoint&, BOOL erase = TRUE);
	void Report();
	void drawagents();
	string viewcell(agent*);
	void PlaceAgent(agent*);	// assign screen location
	void PlaceAllAgents();		// assign screen locations

	void buildrep(agent& a);		// build a representative agent INTO a
	agent* FindStrongest();
	agent* FindMostProlific();
	void pgmstodisk(const char *title, unsigned maxcount = MAXINT);
	void getstrongestfromdisk();

	void setPGMLENGTH();
	void RunNext();
	void RunRandomOne();
	void RunEach();
	void Cull();
	void TopUp();
	void AutoSetPOPValues(int maxpop);

	// overridden TWindow
	virtual BOOL IdleAction(long idlecount);
	virtual BOOL CanClose();

	// public event handlers

	// variables
	TIArrayAsVector<agent> Ag;
	OpStruct ots;      			   	// Options Dialog transfer structure
	string fileroot;	// full path name of .AGS file, less the .AGS extension
	long childcount;	// total number of offspring produced
	long runloops;		// number of entries to the for loop that calls agent::run()
	long agentsran;		// total number of agents that have run their pgm
	unsigned lowpop;	// lowest population ever reached
	unsigned highpop;  	// highest population ever reached
	int passlimit;		// not used: could be made a time interval in seconds

	enum { CROSSOVER, SHUFFLE, SHUFFLESEGMENTS};
	int MATEMETHOD;
	int PGMLENGTH;		// length of an agent's randomly generated internal program
	int MUTATIONRATE;  	// 1 PGM STEP in this many has a mutation
						// in colony so effects of different rates can be compared
	BOOL drawing;		// whether automatically drawing
	agent* Strongest;   		// strongest agent in Colony
	agent* MostProlific;   		// agent with the most children
	static SDDEHandler* Dde;	// a copy of the app's handler, for local use

	// reserved colors, dib palette indexes.
	enum {BKCOLOR = 0, AGCOLOR, LOOKCOLOR};

	int MAXPOP;		// maximum size of colony
	int OPTPOP;		// optimum level.
	int MINPOP;     // it is topped up when it reaches this

protected:
	// variables
	TTime referencetime;		// used in IdleAction, for determining top-of-hour autosaves
	int piccount;				// used in IdleAction, for assigning BMP filenames
	BOOL AllowDirectToScreen;	// en/disables direct-to-screen pixels in SetPixel
	static int FracwinCount;	// # of SColonyWindows in existence
	complex loctotals;			// sum of all ScrLoc, used for calculating center of mass
								// using ScrLoc because I think ScrLoc and Loc sometimes
								// (MoveAgent) aren't coordinated, and it's ScrLoc that
								// is correct where we need it.
								// loctotals will be useful for boids.  currently its
								// usage is untested, since screen center is used instead.

#if !defined(__WIN32__)
	// KEEP this for later use, including a remote terminal option.
	// More recent Win32 versions certainly support serial communications.
	static SWinCommDev SerialCom;	// for status reports, all share
#endif	//!defined(__WIN32__)

	enum StatusReportModes { BYNONE, BYDDE, BYSERIAL };
	static int StatusReportMode;

	// functions
	static void SendStatusReport(const string& s);
	void EraseDib();					// erase to its background color, draw data area
	void draw(int drawcount = 0); 		// plot points

	// from Colony
	BOOL killweakest();

	// TWindow virtuals
	virtual void SetupWindow();
	virtual void CleanupWindow();

	// event handlers
	void EvSetFocus(HWND hWndLostFocus);
	void EvLButtonDown(UINT, TPoint&);
	void EvLButtonUp(UINT, TPoint&);
	void EvRButtonDown(UINT, TPoint&);
	void CmFileSave();
	void CmViewOptions();
	virtual void CmViewFitToWindow();		// overrides SDibwin's
	void CmPeek();
	void CmViewResize();
	void CmViewClrScr();

DECLARE_RESPONSE_TABLE(SColonyWindow);
};

//////////////////////////////////////////////////////////////////////////////

#endif			// __AGENT_H

agent.cpp

/*	agent.cpp		01-22-02
	This file is part of the WADAPT project.
	Copyright (C)1995-2002 Steven Whitney.
	Published under GNU GPL (General Public License) Version 3, with ABSOLUTELY NO WARRANTY.
	Initially published by http://25yearsofprogramming.com.

	Code for class agent.

*/
#include "agent.h"

//////////////////////////////////////////////////////////////////////////////
// agent members
//----------------------------------------------------------------------------
// static members
//
Trigtable agent::t;
int agent::MAXPGMLENGTH = 	200; 	// pgm cannot grow beyond this length
double agent::STARTENERGY =	1e6;	// amount of energy a cell is born/initialized with

// balance agent's need to accomplish something useful against acceptable system responsiveness
// minimum value should be the average pgm length.
int agent::STEPMAX = 50;			// agent executes STEPMAX instructions per run() entry

// English translations of numeric opcodes.  keep the most useful at list start,
// most common earlier.  Delete opcodes by moving to end, out of used portion.
// Remove from list only if certainly useless AND never useful for reference later.
const char* agent::opcodes[] =
{
/*  0 */	"NOP / SEGMENT DELIMITER",
/*  1 */	"RESTART PROGRAM",
/*  2 */	"CALL SBR[NEXT]",
/*  3 */	"RETURN FROM SBR, IF ANY",
/*  4 */	"IF(AX < 0)  CALL LABEL[NEXT], ELSE SKIP NEXT STEP",
/*  5 */	"IF(AX >= 0) CALL LABEL[NEXT], ELSE SKIP NEXT STEP",
/*  6 */	"IF(AX == 0) CALL LABEL[NEXT], ELSE SKIP NEXT STEP",
/*  7 */	"IF(AX != 0) CALL LABEL[NEXT], ELSE SKIP NEXT STEP",
/*  8 */	"HEADING += 90.",
/*  9 */	"HEADING += 180.",
/* 10 */	"RANDOMIZE HEADING (WANDER)",
/* 11 */	"TURN TOWARD CENTER (HERD)",
/* 12 */	"TURN TOWARD NEAREST WEAKER",
/* 13 */	"TURN TOWARD NEAREST",
/* 14 */	"TURN TOWARD NEAREST SAME SPECIES",
/* 15 */	"TURN TOWARD NEAREST STRONGER",
/* 16 */	"TURN TOWARD STRONGEST IN COLONY",
/* 17 */	"TURN TOWARD NEAREST STRONGER OF SAME SPECIES",
/* 18 */	"TURN TOWARD NEAREST WITH MORE CHILDREN THAN THIS",
/* 19 */	"TURN TOWARD THE ONE WITH THE MOST CHILDREN IN THE COLONY",
/* 20 */	"TURN AWAY FROM NEAREST",
/* 21 */	"MATCH HEADING TO NEAREST (FLOCK)",
/* 22 */	"MATE WITH RANDOM ADJACENT, IF ANY",
/* 23 */	"EAT RANDOM ADJACENT, IF ANY",
/* 24 */	"MOVE TO EAT",
/* 25 */	"MOVE TO MATE",
/* 26 */	"DIVIDE",
/* 27 */	"TURN TOWARD THE MOST SIMILAR ONE (NOP)",
/* 28 */    "JUST MOVE",
/* 29 */    "TURN AWAY FROM CENTER (DISPERSE)",
/* 30 */    "HEADING -= 90.",
/* 31 */    "HEADING -= 1.",
/* 32 */    "HEADING += 1.",
/* 33 */    "AX = FABS(AX)",
/* 34 */    "AX = -AX",
/* 35 */    "AX += THIS->ENERGY",                 	// delete next round?
/* 36 */    "IF(INVIEW) AX -= INVIEW->ENERGY",    	// delete next round?
/* 37 */    "JUMPFORWARD TO LABEL[NEXT]",
/* 38 */    "JUMPBACKWARD TO LABEL[NEXT]",
/* 39 */    "AX += 1",
/* 40 */    "AX -= 1",
/* 41 */    "AX = 0",
/* 42 */	"SKIP OVER THE NEXT STEP",
			""								// they all have commas except this placeholder

			// MAKE SURE ALL OPCODES APPEAR HERE!!!
			// IF YOU ADD OPCODES, UPDATE ICOUNT (below)
};
// TOTAL number of opcodes in cell instruction set (excluding the final "" placeholder)
int agent::ABSICOUNT = 43;

// opcodes up to ICOUNT-1 can be assigned as steps in NEW pgms,
// (random(ICOUNT) is used to generate the steps.)
// Set ICOUNT to < ABSICOUNT to prevent higher opcodes from being generated.
// see note in run() for why limit here is 28 (higher ones are deemed useless).
// (but higher ones in preexisting pgms WILL be processed in run() if their cases are
// not commented out in run().)
int agent::ICOUNT = 28;
//-----------------------------------------------------------------------
// constructor
agent::agent(SColonyWindow& c)
{
// although it takes c as its parent Colony, it does NOT add ITSELF to the Colony's array
// and thus is not a real member unless the Colony adds it.  So you CAN create a
// non-associated one.

Col = &c;					// reference so it can't be 0

heading = random(360);
ax = 0;
energy = STARTENERGY;    		           // all equal starting energy

// randomly assign pgm steps, and intersperse segment terminators (0)
// presence of segment terminators should not affect mate methods that don't use them.
uchar ch;
for(int i = 0 ; i < Col->PGMLENGTH ; i++)	// randomly assign (all same length)
{
	// set average 0 incidence here (1/TERMFREQ)
	ch = random(TERMFREQ) ? (uchar)random(ICOUNT) : (uchar)0;
	pgm += ch;
}
pgm[pgm.length() - 1] = (uchar)0;			// last char must be a 0
segments = countchr(pgm,0);

ip = 0;
maxip = 0;
children = 0;
ate = 0;
inview = 0;						// nothing in sight
Loc = complex(0,0);
ScrLoc = TPoint(0,0); 			// the Colony assigns it a location
color = 0;
SetNearest();
}
//----------------------------------------------------------------------------
// copy constructor
agent::agent(const agent& other) { *this = other; }
//-----------------------------------------------------------------------
// destructor
agent::~agent() {}
//----------------------------------------------------------------------------
// assignment operator
agent& agent::operator = (const agent& other)
{
if(this == &other)
	return(*this);

Col 		= other.Col;
Loc 		= other.Loc;
ScrLoc 		= other.ScrLoc;
color 		= other.color;
energy 		= other.energy;
children 	= other.children;
ate 		= other.ate;
id 			= other.id;
pgm 		= other.pgm;
heading 	= other.heading;
ax 			= other.ax;
inview 		= other.inview;
ip 			= other.ip;
maxip 		= other.maxip;
Nearest 	= other.Nearest;
NearestDist = other.NearestDist;

return(*this);
}                    		// assignment operator
//-----------------------------------------------------------------------
// must use &other, to uniquely distinguish between agents.
BOOL agent::operator == (const agent& other) const { return(this == &other); }
//----------------------------------------------------------------------------
// write an agent's persistent info to any ostream.
// setw(4) is more readable than 3 for both screen and file
ostream& operator << (ostream& os, const agent& a)
{
os << setw(8) << a.ate << " " << setw(8) << a.children << " " << setw(12) << a.energy << " ";
int count = a.pgm.length();
for(int i = 0 ; i < count ; i++)
	os << setw(4) << (uint)(a.pgm[i]);
return(os);
}
//-----------------------------------------------------------------------
// read an agent's persistent info from an istream.
// Some of the cell's data members will be unchanged from
// the values the constructor gave them, meaning they will be different from
// the values the original cell had when its data was written.
// #error check whether unread/unchanged members need default values set, for multiple reads
// into a reused agent.
istream& operator >> (istream& is, agent& a)
{
// allow 4 spaces for each pgm step (old files use that many), plus some extra
// remember lines from old file might exceed current MAXPGMLENGTH
// 4100 will accomodate pgm lengths of 1000, highest I've ever used.
int bufsize = max(4 * agent::MAXPGMLENGTH + 100, 4100);	// lines can be very long
char* buf = new char[bufsize];

// the getline() block below will produce a cell for every line read,
// even if the line is blank.  is >> ws eats up any imbedded or trailing
// blank lines to prevent this.  (An unreadable line will still produce an extra cell.)

is >> a.ate >> a.children >> a.energy;
if(is.getline(buf,bufsize))			// read LINE into buffer
{
	string oldpgm = a.pgm;			// save old pgm in case nothing is read.
	istrstream instr(buf);  		// make an input string we can read data from
	a.pgm.remove(0);				// empty the existing string
	int pgmstep;
	while(instr >> pgmstep) 		// while we can read data,
		a.pgm += (uchar)pgmstep;	// add corresponding chars to pgm
	if(a.pgm.length() == 0)	 		// not even one char read,
		a.pgm = oldpgm;				// so restore a.pgm to previous value
}
delete[] buf;

// check for old pgms.  in this situation, append the 0 if necessary, so pgm is preserved.
uchar z = 0;
if(a.pgm[a.pgm.length() - 1] != 0)
	a.pgm += z;
a.segments = countchr(a.pgm,0);

return(is);
}
//-----------------------------------------------------------------------
BOOL agent::IsAlive() { return(energy >= 1); }
//-----------------------------------------------------------------------
// add or subtract, and recalc Col->Strongest
void agent::AddEnergy(double amount)
{
energy += amount;
if(!Col->Strongest)
	Col->Strongest = this;
else
	if(amount >= 0.)
	{
		if(energy >= Col->Strongest->energy)
			Col->Strongest = this;
	}
	// if energy is subtracted from strongest, it may no longer be strongest
	else
		if(Col->Strongest == this)
			Col->FindStrongest();

// Col->TestAsStrongest(this);	// a possibility, but slower because it can't test amount
}   							//AddEnergy
//-----------------------------------------------------------------------
// test whether other is same species.  TRUE if their pgms are the same length.
BOOL agent::samespecies(agent* /* other */)
{
// newest test: none!  unsure if explicit species test is even desirable.
return TRUE;

// new test: same # of segments
// return(segments == other->segments);

// old: same pgm length
// if(pgm.length() != other->pgm.length()) 	// pgms must be the same length
// 	return(FALSE);
// return(TRUE);                               // for option below, remove this line

// This never-used version determines how many of the two cells's pgm[] locations are the same.
// Returns TRUE if 90% or more of the pgm[] chars match.
// pgms w/length < 10 can't meet this test unless identical
// 	int samecount = 0;
// 	int count = pgm.length();
// 	for(int i = 0 ; i < count ; i++)
// 		if(pgm[i] == other->pgm[i])
// 			samecount++;
// 	long percent = 100L * (long)samecount / (long)count;
// 	return(percent >= 90L ? TRUE : FALSE);
}                     	//samespecies
//----------------------------------------------------------------------------
// uses several comparisons to measure how similar two strings are.
// modified (not much) from tok.cpp (wtalk.cpp), where it also remains untested and
// its legitimacy as a measure unverified!
// returns a value between 0 (no similarity at all) and 1.0 (identical)
//
// The result of each method is adjusted by a multiplier so that 1.0 can only
// be attained by identical strings, and each lesser level of similarity
// has a lower maximum possible value than the one above it.  The original goal
// was a "percentage" measure of similarity, but the methods used aren't as precise
// as that would imply.
// The multipliers may require some experimenting and adjustments.
//
// if this measure proves useful, it could be moved to mystring.cpp as a general function.
// Measure is the same regardless of which string is "other".
double agent::SimilarityTo(const agent& other)
{
// new, hopefully quicker method finds length of match in starting chars:
uint N = min(pgm.length(),other.pgm.length());
for(uint i = 0 ; i < N ; i++)
	if(pgm[i] != other.pgm[i])
		break;
return i;

#if 0
// VERY time-consuming!
string shorter = pgm, longer = other.pgm;	// copy to local
if(shorter == longer)						// identical? (including if both are null)
	return(1.0);
if(!shorter.length() || !longer.length())	// require both to have length
	return(0.0);
if(shorter.length() > longer.length())		// comparisons easier if we know which is which
	swap(shorter,longer);

// contains is also a good match (maybe a variant)
// (convenient but unnecessary: duplicates are the best case of the next test)
if(longer.contains(shorter))
	return(.99);

// find what percent of the chars in shorter are found in the same order in longer.
// you must try starting at EACH position in shorter, and use the highest count found.
// the first nonmatching char does not abort the search.  internal nonmatches are allowed.
// e.g. run and ran match 2 chars in order.
uint highcount = 0;
for(uint i = 0 ; i < shorter.length() ; i++)
{
	uint j = longer.find(shorter[i]);
	if(j == NPOS)
		continue;
	uint count = 0;
	for(uint k = i ; (k < shorter.length()) && (j < longer.length()) ; k++, j++)
		if(shorter[k] == longer[j])
			count++;
	highcount = max(highcount,count);
}
// tentative return value
double inorder = (double)highcount / (double)shorter.length() * .99;

// find what percent of the chars in shorter are found in longer, regardless of order.
// this test destroys longer
highcount = 0;
for(i = 0 ; i < shorter.length() ; i++)
{
	uint j = longer.find(shorter[i]);
	if(j == NPOS)						// char not found
		continue;
	highcount++;              			// was found, increment count
	longer.remove(j,1);             	// remove the char so it doesn't get found again
}
// tentative return value
double anyorder = (double)highcount / (double)shorter.length() * .25;
return(max(inorder,anyorder));
#endif // 0
}							// SimilarityTo
//-----------------------------------------------------------------------
// mutate the agent's pgm, used by all the mate() functions.
void agent::mutate()
{
// this old method was to CALL mutate() for only 1 in MUTATIONRATE cells.
// now the call to here is unconditional, but enabling this would restore the same effect.
// test succeeds for only 1 in MUTATIONRATE cells.
// if(random(Col->MUTATIONRATE) == 0)
// 	{

// new method: "cosmic ray hits or misses DNA": falls outside pgm.
// if it hits it and mutates it, don't use this loc as the location for mutation;
// legal location depends on mutation type below, so you must recalculate one there.
// if pgm length ever routinely exceeds MUTATIONRATE, should modify this so
// there are multiple cosmic ray hits.

if(random(Col->MUTATIONRATE) < pgm.length())
{
	// maintain relative 0 frequency
	uchar ch = random(TERMFREQ) ? (uchar)random(ICOUNT) : (uchar)0;
	switch(random(3))
	{
		// step removal, internal or can be first or last char in string
		case 0:
			if(pgm.length() > 2)
				pgm.remove(random(pgm.length()),1);
			break;

		// step insertion, internal or can be at first or last pos in string
		case 1:
			pgm.insert(random(pgm.length() + 1),string(ch));
			break;

		// internal mutation w/no length change
		case 2:
			pgm[random(pgm.length())] = ch;
			break;

		// truncate string at a random location, but leave at least 1 char
		// this causes devastating reductions in pgm length.  Such short pgms
		// have too low a probability of containing at least 1 move or mate opcode.
		// with this possibility removed, 1-step insertion and removal offset each other,
		// meaning that if pgm lengths tend to grow, it means the new longer pgms
		// have some kind of selective advantage.
		// case 3:
		// 	if(pgm.length() > 1)	// can't truncate if only 1 char
		// 	{
		// 		int i;
		// 		do					// endless loop if length is 1
		// 		{
		// 			i = random(pgm.length());
		// 		}
		// 		while(i == 0);
		// 		pgm.remove(i);
		// 	}
		// 	break;
	}
}
// these tests are useful (and now required) even if no mutation was made

// keep below max in case written to file and read back in
if(pgm.length() > MAXPGMLENGTH)
	pgm.remove(MAXPGMLENGTH);

// last opcode must be segment terminator (0).  This is a central location to enforce it.
// Every fn that creates or modifies pgm calls it, except constructor.
pgm[pgm.length() - 1] = (uchar)0;			// last char must be a 0
segments = countchr(pgm,0);					// retally 
}							//mutate
//-----------------------------------------------------------------------
// create 2 children using "crossover" from book (Complexity, by Waldrop).
// Tends to copy longer identical pgm sequences from the parents.
// This may be the better way to produce offspring when the sequences are
// interpreted sequentially as a program (as here).
// This version allows agents with different length pgms to mate.
int agent::crossover(agent* other)
{
int newchildren = 0;				// # of children produced
// 2 passes = 2 children
for(int j = 0 ; j < 2 ; j++, newchildren++, children++, other->children++)
{
	agent* a = Col->AddAgent();	 	// create a new cell
	if(!a)
		break;
							// 1st pass: this genes first, 2nd pass: other's genes first
	agent *first, *second;
	if(j == 0)	{ first = this;  second = other; }
	else		{ first = other; second = this; }

	// determine crossover point, can be from 1 to first->length(), inclusive
	int cutpoint = 1 + random(first->pgm.length());

	// copy first->pgm from beginning to pos(cutpoint-1)
	// minimum 1 char, can result in entire string being copied.
	a->pgm = first->pgm;           		// first copy the whole string
	if(cutpoint < a->pgm.length())
		a->pgm.remove(cutpoint);		// then cut off the end

	// if second->pgm has a char at pos(cutpoint), append from there to end,
	// else append nothing.  second parent has its chance next (or previous) pass.
	// a->pgm may be very long, but gets truncated later.
	// min start point = pos(1) (2nd char).  if first and second were same length,
	// and entire first was copied, nothing gets copied from second.

	// With this method, pgm steps generally retain their absolute positions,
	// except for migrations 1 position at a time due to mutate() insertions.
	// They don't migrate wildly as they did before.
	if(cutpoint < second->pgm.length())
		a->pgm += second->pgm.substr(cutpoint);

	a->mutate();			    	// create random mutation(s)

	if(a->pgm.length() == 0)		// remove when sure it never happens
		Col->logerror("pgm length is zero");

}					//for(2 children)
if(newchildren)
	play(BORN);             			// at least one successfully added
return(newchildren);
}						//crossover
//-----------------------------------------------------------------------
// create 1 child, each pgm step randomly selected from 1 parent or the other.
// see complex.doc for discussion.
// returns # of children produced
int agent::shuffle(agent* other)
{
agent* a = Col->AddAgent();	 		// create a new cell
if(!a)
	return(0);
play(BORN);             			// successfully created, so
children++;            				// increment child tally
other->children++;

a->pgm.remove(0);			// empty the constructor-assigned pgm string

// when using max:
// if parent has data at the location, append it to child, else append nothing.
// thus, the longer parent's trailing data is appended, but with holes where
// the other parent was chosen, but it had no data to append.
// could change so longer parent's data is appended in its entirety, as a "tail"

// when using min:
// copying stops when length of shortest parent is reached.

agent* parent;                      		// for choosing one parent or the other
int count = max(pgm.length(),other->pgm.length());
for(int i = 0 ; i < count ; i++)			// give it pgm steps from parents.
{
	parent = random(2) ? this : other; 		// choose one of the parents
	if(i < parent->pgm.length())			// if it has data at this loc,
		a->pgm += parent->pgm[i];	// append it to child.
}
a->mutate();				// mutate
return(1);
}							//shuffle
//-----------------------------------------------------------------------
// create 1 child, each pgm SEGMENT randomly selected from 1 parent or the other.
// see complex.doc for discussion.
// returns # of children produced
// #error mate fns should take agent& param?
int agent::ShuffleSegments(agent* other)
{
agent* a = Col->AddAgent();	 		// create a new cell
if(!a)
	return(0);
play(BORN);             			// successfully created, so
children++;            				// increment child tally
other->children++;

a->pgm.remove(0);					// empty the constructor-assigned pgm string

// arrays for extracted pgm segments
TArrayAsVector<string>* first  = new TArrayAsVector<string>(10,0,10);
TArrayAsVector<string>* second = new TArrayAsVector<string>(10,0,10);

// cut this->pgm into its segments and store the whole segments in first
string temp;
int N = pgm.length();
for(int i = 0 ; i < N ; i++)
{
	temp += pgm[i];     		// also appends the terminators
	if(pgm[i] == 0)				// if this IS a terminator
// 		if(temp.length() > 1)	// (omit empty segments, replacing multiple 0s with one 0)
// 		if(temp.length() > 0)	// always true. better?: empty segments ARE copied,
		{						// and average terminator frequency is preserved.
			first->Add(temp);
			temp.remove(0);
		}
}
// cut other->pgm into its segments and store the whole segments in second
temp.remove(0);
N = other->pgm.length();
for(i = 0 ; i < N ; i++)
{
	temp += other->pgm[i];     	// also appends the terminators
	if(other->pgm[i] == 0)		// if this is a terminator
	{
		second->Add(temp);
		temp.remove(0);
	}
}
// give child pgm segments chosen from one parent's container or the other.
// max vs. min:  see shuffle()

TArrayAsVector<string>* parent;				// for choosing one parent or the other
N = max(first->GetItemsInContainer(),second->GetItemsInContainer());
for(i = 0 ; i < N ; i++)					// give it segments from parents.
{
	parent = random(2) ? first : second; 	// choose one of the parents
	if(i < parent->GetItemsInContainer())	// if it has data at this loc,
		a->pgm += (*parent)[i];				// append the segment.
}
delete first;
delete second;

a->mutate();				// mutate
return(1);
}							//ShuffleSegments
//-----------------------------------------------------------------------
// mate using currently selected default method.  returns # of children produced
int agent::mate(agent* other)
{
int count = 0;
if(samespecies(other))
{
	switch(Col->MATEMETHOD)
	{
		case Col->CROSSOVER: 		count = crossover(other);
		case Col->SHUFFLE:   		count = shuffle(other);
		case Col->SHUFFLESEGMENTS:  count = ShuffleSegments(other);
	}
	// note >= allows title to change on a tie, if these 2 are tied, title goes to this
	if(!Col->MostProlific || (other->children >= Col->MostProlific->children))
		Col->MostProlific = other;
	if(children >= Col->MostProlific->children)
		Col->MostProlific = this;
}
return(count);
}                          	// mate
//-----------------------------------------------------------------------
// mate: cell division.  Offspring is an identical copy, with possible mutation.
int agent::divide()
{
agent* a = Col->AddAgent();		// create a new cell
if(!a)
	return(0);
a->pgm = pgm;					// give child the same pgm string
a->mutate();					// mutate

play(BORN);             		// enable only if divide is an opcode

children++;            			// increment child tally
								// note >= allows title to change on a tie
if(!Col->MostProlific || (children >= Col->MostProlific->children))
	Col->MostProlific = this;

return(1);
}                   			//divide
//-----------------------------------------------------------------------
// play a sound
void agent::play(int state)
{
	if(!Col->ots.beepon)   						// not using sound at all
		return;
	switch(state)
	{
		case DEAD:
			MessageBeep(-1);
			break;
		case BORN:
			MessageBeep(-1);
			break;
		case EATEN:
			MessageBeep(-1);
			break;
		case RUN:
			MessageBeep(-1);
			break;
	}
}                    			//play
//-----------------------------------------------------------------------
// increment instruction pointer by one.  When at end of pgm,
// it wraps around to beginning.  Can update maxip (highest pgm step executed).
// NO update when it's called merely to jump or locate a program label.
// updates when it's called to get the next executable instruction.
void agent::incrementip(BOOL updatemax)
{
if(++ip >= pgm.length())	// if at program end (the > test just prevents disaster)
	ip = 0;                 // wrap to pgm beginning
if(updatemax)
	maxip = max(maxip,ip);	// update highest-step-reached counter
}                  		//incrementip
//-----------------------------------------------------------------------
// decrement ip by one
void agent::decrementip()
{
if(--ip < 0)      				// if below 0,
	ip = pgm.length() - 1;		// wrap back to last pgm step
}                    			//decrementip
//-----------------------------------------------------------------------
// FORWARD jump to label, i.e. the 2nd-next occurrence of the next opcode.  Any opcode
// can be a label.  You know the sought label WILL be found because its value
// is taken from the next opcode (so it's in pgm).  At worst, the "next" occurrence
// will be the same occurrence, after looping completely around through pgm.
// Remember that incrementip() is called AGAIN at end of switch in run().
// This function should leave ip at the step BEFORE the next one to be executed.
// i.e., ON the label.
void agent::jumpforward()
{
if(pgm.length() < 2)			// if the jumpforward is the only instruction, do nothing
	return;
incrementip(FALSE);       		// move to instruction specifying the label
uchar label = pgm[ip];			// get its value
do
{
	incrementip(FALSE);   		// do first, to get away from the current one
}
while(pgm[ip] != label);
}                   			//jumpforward
//-----------------------------------------------------------------------
// BACKWARDS jump to program label
// the eventual goal is to wind up with only 1 jump command, BUT that
// would require preventing duplicate labels, which for now is impossible.
// and jumpback now can delimit the end of a loop.
void agent::jumpbackward()
{
if(pgm.length() < 2)			// if the jump is the only instruction, do nothing
	return;
incrementip(FALSE); 			// move to instruction specifying the label
uchar label = pgm[ip];			// get its value
do
{
	decrementip();
}
while(pgm[ip] != label);
}                      			//jumpbackward
//-----------------------------------------------------------------------
// computes geometric distance between two cells
// #error still doesn't account for screen wrap (see paper notes)
uint agent::calcdistance(agent* other)
{
// accurate but slow, uses doubles
// return abs(Loc - other->Loc);

// this fn is used often: Manhattan using ScrLoc faster, but maybe not always correct
// there might be a TPoint operator - that effectively does this, but beware speed
return ( abs(ScrLoc.x - other->ScrLoc.x) + abs(ScrLoc.y - other->ScrLoc.y) );
}                    			//calcdistance
//-----------------------------------------------------------------------
// move a cell 1 unit along its heading.
// Can only move 1 pixel at a time so it knows whether next step will hit something.
// returns pointer to the cell that blocked this one's path, if any,
// or ZERO if path was clear.
agent* agent::move()
{
// most moves succeed, so it's more efficient to make it first, and undo if necessary
complex oldloc = Loc;

// must get away from current PIXEL, or it'll be shown as "occupied" (by itself),
while( TPoint(real(Loc),imag(Loc)) == ScrLoc )
	Loc += complex( t.cosines[(int)heading], t.sines[(int)heading] ); 

Col->screenwrap(Loc);			// wrap the raw values

// truncate to the actual screen values (tentative only).  you can't set ScrLoc
// yet, because if the new loc IS occupied by another agent, the search below
// might erroneously find THIS agent on the loc instead of the other one.

TPoint newpoint(real(Loc),imag(Loc));
// if((tx >= 640) || (tx < 0) || (ty >= 480) || (ty < 0))
// 	Col->logerror("tx or ty still out of range in move()");

// if new location is occupied, can't move there
// speed ok: tests the pixel before array search
if((inview = Col->Occupant(newpoint)) != 0)
{
	Loc = oldloc;					// restore old loc (ScrLoc didn't change)
	return(inview);
}
Col->MoveAgent(this,newpoint,TRUE);	// ScrLoc will be updated to the new pos
return(0);                       	// no cell blocked movement
}									//move
//-----------------------------------------------------------------------
// update all sensors with current surroundings
// determine if there is another cell in the current line of sight along our heading
// similar to move() except it just looks, doesn't go anywhere, and vision doesn't wrap
// beyond edge of screen.
// returns pointer to agent in line of sight, or 0 if none.
agent* agent::sense()
{
inview = 0;						// start with nothing in sight

// I think I commented this out because doing it every call was slow.
// int map;						// to build the neighborhood map in
// Col->mapneighbors(this,map);	// construct a map of the neighborhood

complex oldloc = Loc;			// use Loc for the imaginary moves, and undo when done.
TPoint lookpoint(ScrLoc);		// must use temporary; can't use ScrLoc

// because it returns, this loop must be last thing sense() does.
while(1)              	// returns if an object sighted or vision ran off screen
{
	// must get away from current PIXEL, or it'll be shown as "occupied" (by itself),
	while( TPoint(real(Loc),imag(Loc)) == lookpoint )
		Loc += complex( t.cosines[(int)heading], t.sines[(int)heading] );

	// if our "vision" ran off screen, we're through looking.
	if(Col->screenwrap(Loc))
	{
		Loc = oldloc;					// (ScrLoc didn't change)
		return 0;
	}
	lookpoint = TPoint(real(Loc),imag(Loc));		// translate to screen point

	// if new location is occupied, it is the object we're looking at.
	if((inview = Col->Occupant(lookpoint)) != 0)
	{
		Loc = oldloc;
		return inview;
	}
	// didn't sight anything or run off screen: (maybe) show where we're looking
	if(Col->ots.lookon)
		Col->SetPixel(lookpoint,Col->LOOKCOLOR);
}													// end while(1)
}								//sense
//-----------------------------------------------------------------------
// eat neighbor, or TRY to!.  Could fail and get eaten instead.
// If eat() never fails, (if someone always gets eaten)
// then you need to produce > 1 child in mate(), or population can't increase.
void agent::eat(agent* other)
{
if(other == this)				// disaster prevention
	return;
if(other->energy < 0)
	return;
play(EATEN);           			// one or the other will get eaten
if(energy >= other->energy)		// we're stronger, and get a meal
{                               // (a tie goes to this, the attacker)
	if(other == Nearest)
		SetNearest();
	AddEnergy(other->energy);	// add what was eaten

	// I know I studied it and decided it was ok to destroy other here, but it seems risky
	Col->DestroyAgent(other);   // ok to Destroy other
	ate++;						// tally
}
else                        	// attack failed,
{
	other->AddEnergy(energy);	// this gets eaten.
	other->ate++;				// tally
	AddEnergy(-energy);         // zero it, to be Destroyed immediately upon return
}
}								//eat
//-----------------------------------------------------------------------
// change heading to point at a given point
// Should only be called from run(), because heading isn't adjusted to 0-359.
void agent::turntoward(complex toward)
{
if(toward == Loc)							// already on the point
	return;
heading = arg(toward - Loc) * M_180_PI;		// if negative, run() will adjust it.
}                     			//turntoward
//-----------------------------------------------------------------------
void agent::turnawayfrom(complex point)
{
turntoward(point);
heading += 180;								// run() will adjust it.
}                     			//turnawayfrom
//-----------------------------------------------------------------------
// execute next program block of an agent's program.
// returns TRUE if cell survived, FALSE if not.
int agent::run()
{
if(!IsAlive())			// dead cell (probably eaten by another, but not yet Destroyed)
	return(FALSE);

int oldchildren = children;				// # of children it already has
// int childrenlimit = oldchildren + 4;	// when hit (or exceeded), no more allowed

double MinMateEnergy = 1.0 * STARTENERGY;	// must exceed before mating allowed

SetNearest(); 			// must start as unknown on each entry
double oldheading;		// used to determine whether cell turned
agent* other = 0;		// temporaries that can't be declared within a switch{}

sense();		// update all sensors for current surroundings/conditions
ax = 0.;		// cell is "unconscious" while the other cells are moving
ip = 0;			// so you have to start fresh
int ip2 = -1;   // saved ip for returning; invalid value for "no CALL in progress"

// each agent can run its pgm for a fixed interval.  test the 2 methods against each other.
// enable code for whichever you want to use
//
// STEP LIMIT: better for comparing strategies.  execute STEPMAX instructions per entry.
for(int stepcount = 0 ; stepcount < STEPMAX ; stepcount++)

// TIME LIMIT:  would seem realistic, but some good strategies are time-consuming for the
// computer, preventing the cell from benefiting much from them, and sometimes what is
// slow for the computer isn't slow for an animal.  it also interferes with debugging
// breakpoints, since the clock stays running.  limit is in 1/1000 sec. but only times to
// the nearest 1/20th.  that is, clock() jumps by 50ms each 1/20th.
// clock_t start = clock();			// reference time
// while((clock() - start) < 1) 	// normally 1

{
	oldheading = heading;
	switch((uint)(pgm[ip])) 		// each case is a basic cell instruction
	{
		// the text on each case line IS the text for opcodes[] descriptions
		// To build new opcodes[] array from them:
		// copy whole section to opcodes[] definition area.
		// remove all lines between the cases (code)
		// replace all "case" with "/*"
		// replace all "://" with " */"
case  0://	"NOP / SEGMENT DELIMITER",
			break;

case  1://	"RESTART PROGRAM",
			// this should be like re-entering run
			ip = pgm.length() - 1;	// last step: 1st step w/b next executed!
			ip2 = -1;               // clear sbr
			ax = 0;
			sense();
			break;

case  2://	"CALL SBR[NEXT]",
			ip2 = ip;      	// points at the CALL
			jumpforward();	// jmp to [next] (i.e. 2nd-next occurrence OF the next opcode)
			break;

case  3://	"RETURN FROM SBR, IF ANY",
			if(ip2 >= 0)
			{
				ip = ip2;          	// point at the CALL
				incrementip(FALSE);	// incr over it (auto-increment will skip over the label)
				ip2 = -1;			// now invalid
			}
			break;

case  4://	"IF(AX < 0)  CALL LABEL[NEXT], ELSE SKIP NEXT STEP",
			// modelled after the TI59 test instructions
			if(ax < 0) { ip2 = ip; jumpforward(); } else incrementip(FALSE); break;

case  5://	"IF(AX >= 0) CALL LABEL[NEXT], ELSE SKIP NEXT STEP",
			if(ax >= 0) { ip2 = ip; jumpforward(); } else incrementip(FALSE); break;

case  6://	"IF(AX == 0) CALL LABEL[NEXT], ELSE SKIP NEXT STEP",
			if(ax == 0) { ip2 = ip; jumpforward(); } else incrementip(FALSE); break;

case  7://	"IF(AX != 0) CALL LABEL[NEXT], ELSE SKIP NEXT STEP",
			if(ax != 0) { ip2 = ip; jumpforward(); } else incrementip(FALSE); break;

case  8://	"HEADING += 90.",
			heading += 90.; break;			// turn 90 degrees

case  9://	"HEADING += 180.",
			heading += 180.; break;		// turn 180 degrees


case 10://	"RANDOMIZE HEADING (WANDER)",
			heading = random(360); break;	// by a random amount

case 11://	"TURN TOWARD CENTER (HERD)",
			turntoward(Col->screencenter()); break;

case 12://	"TURN TOWARD NEAREST WEAKER",
			if((other = Col->FindNearest(this,WEAKER)) != 0)
				turntoward(other->Loc);
			break;

case 13://	"TURN TOWARD NEAREST",
			if((other = Col->FindNearest(this)) != 0)
				turntoward(other->Loc);
			break;

case 14://	"TURN TOWARD NEAREST SAME SPECIES",
			if((other = Col->FindNearest(this,SAMESPECIES)) != 0)
				turntoward(other->Loc);
			break;

case 15://	"TURN TOWARD NEAREST STRONGER",
			if((other = Col->FindNearest(this,STRONGER)) != 0)
				turntoward(other->Loc);
			break;

case 16://	"TURN TOWARD STRONGEST IN COLONY",
			// "alpha" individual
			if((other = Col->Strongest) != 0)
				if(other != this)
					turntoward(other->Loc);
			break;

case 17://	"TURN TOWARD NEAREST STRONGER OF SAME SPECIES",
			if((other = Col->FindNearest(this,ALL, STRONGER | SAMESPECIES)) != 0)
				turntoward(other->Loc);
			break;

case 18://	"TURN TOWARD NEAREST WITH MORE CHILDREN THAN THIS",
			if((other = Col->FindNearest(this,MORECHILDREN)) != 0)
				turntoward(other->Loc);
			break;

case 19://	"TURN TOWARD THE ONE WITH THE MOST CHILDREN IN THE COLONY",
			// chase queen bee, with propensity to produce (should show positive feedback)
			if((other = Col->MostProlific) != 0)
				if(other != this)
					turntoward(other->Loc);
			break;

case 20://	"FLEE NEAREST",
			if((other = Col->FindNearest(this)) != 0)
				turnawayfrom(other->Loc);
			break;

case 21://	"MATCH HEADING TO NEAREST (FLOCK)",
			// (although neighbor will probably turn)
			if((other = Col->FindNearest(this)) != 0)
				heading = other->heading;
			break;

case 22://	"MATE WITH RANDOM ADJACENT, IF ANY",
			ax = 0;
// 			if(children <= childrenlimit)
				if(energy > MinMateEnergy)		// min energy required ("maturity")
					if((other = Col->pickadjacent(this)) != 0)
						ax = mate(other);						// # children produced
			break;

case 23://	"EAT RANDOM ADJACENT, IF ANY",
			ax = energy;
			if((other = Col->pickadjacent(this)) != 0)
			{
				eat(other);     	// eat or get eaten
				sense();			// other may be gone now
				ax = energy - ax;	// will reflect net gain or loss, if any
			}
			break;

case 24://	"MOVE TO EAT",
			ax = energy;
			if((other = move()) != 0)				// if it hit another cell,
			{
				eat(other);     	// eat or get eaten
				sense();			// other may be gone now
				ax = energy - ax;	// will reflect net gain or loss, if any
			}
			break;

case 25://	"MOVE TO MATE",
			// other will still be there (blocking) after mating
			ax = 0;
			if((other = move()) != 0)				// if it hit another cell,
// 				if(children <= childrenlimit)
					if(energy > MinMateEnergy)			// min energy required ("maturity")
						ax = mate(other);         		// # children produced
			break;

case 26://	"DIVIDE",
			// parent loses 1/2 energy in divide(), PLUS step cost PLUS parenting cost.
			// but even if it dies, it creates an endless chain of new children,
			// and loops never complete.  So prevent from doing it: new cells,
			// and any cell that doesn't eat.
			// It should be a good escape strategy: if nearest energy > this
			// (sure to get eaten), half your energy escapes to some other location,
			// and pattern at least survives, even if poorly. (better than nothing)
			ax = 0;
// 			if(children <= childrenlimit)
				if(energy > MinMateEnergy)
					ax = divide();       			// # children produced
			break;

case 27://	"TURN TOWARD THE ONE MOST SIMILAR TO THIS ONE",
// #error not yet tested with the new SimilarityTo()
// (it was prohibitively slow with the old one)
// 			if((other = Col->FindMostSimilar(this)) != 0)
// 				turntoward(other->Loc);
			break;

case 28://	"JUST MOVE",
			// ax setting allows: move/if ax >= 0, it is safe to eat adjacent(if any)
			ax = -1;						// assume successful move
			if((other = move()) != 0)		// if it hit another cell,
				ax = energy - other->energy;
			break;

// SOME OF THESE ARE FUN TO WATCH (AND WORTH KEEPING), BUT USELESS TO THE AGENT

case 29://	"TURN AWAY FROM CENTER (DISPERSE)",
			 turnawayfrom(Col->screencenter()); break;

case 30://	"HEADING -= 90",
			heading -= 90; break;    		// turn 270 degrees

case 31://	"HEADING -= 1",
			heading -= 1; break;			// turn 1 degree counterclockwise

case 32://	"HEADING += 1",
			heading += 1; break;			// turn 1 degree clockwise

case 33://	"AX = FABS(AX)",
			ax = fabs(ax); break;      		// absolute value of (ax)

case 34://	"AX = -AX",
			ax = -ax; break;				// negative of (ax)

case 35://	"AX += THIS->ENERGY",
			ax += energy; break;						// energy

case 36://	"IF(INVIEW) AX -= INVIEW->ENERGY",
			if(inview) ax -= inview->energy; break;		// energy

case 37://	"JUMPFORWARD TO LABEL[NEXT]",
			// CALL without Return can do same thing
			jumpforward(); break;	// go to next label FORWARD or program start

case 38://	"JUMPBACKWARD TO LABEL[NEXT]",
			// CALL w/o ret + no matching label before pgm end can do same thing
			jumpbackward(); break;	// go to PREVIOUS label or program start

case 39://	"AX += 1",
			ax += 1; break;				// increment ax

case 40://	"AX -= 1",
			ax -= 1; break;    			// decrement ax

case 41://	"AX = 0",
			ax = 0; break;

case 42://	"SKIP OVER THE NEXT STEP",
			// looks completely useless (unsure)
			incrementip(FALSE); break;		// Skip over the next step

		// REMEMBER TO ADD ALL NEW CASES TO OPCODES[]!!!!

}                //end switch
	//-----------------------------------------------------------------------
	// the following steps are all performed after each opcode is executed

	if(heading != oldheading)
	{
		// heading is always USED as (int)heading, (for trig table lookup),
		// so this will cause rounding to NEAREST int, when truncated.
		if(heading > 0.) heading += .5;
		if(heading < 0.) heading -= .5;
		while(heading >= 360.) heading -= 360.;
		while(heading < 0.) heading += 360.;
		sense();                                // update inview
		if(inview)								// useful info after any turn opcode
			ax = energy - inview->energy;
	}
	// exact a cost for mating.  don't charge both parents: the passive one can't avoid mating
	// must do it after each step because it affects whether another child is allowed
	// during the next step.
	AddEnergy(-1.0 * (children - oldchildren) * 0.5 * STARTENERGY);
	oldchildren = children;

	if(!IsAlive())				// got eaten or is very weak
		break;
	incrementip(TRUE);			// increment instruction pointer
}								// end for(steplimit) or while(timelimit)
// deduct "aging" (per call) cost:
// old method: energy *= .933 energy depletes 1e6 to 1 in 200 calls,
// but prevented cells from ever getting very strong.
// with this, a weak cell loses less, but a strong cell CAN have a net gain
// if it ate.  i.e. if it ate a new cell with STARTENERGY, it offsets the loss here.
AddEnergy(-1.0 * min(.2 * energy, STARTENERGY));
return(IsAlive());				// TRUE if it survived alive
}	        	        		//run
//-----------------------------------------------------------------------
// 							end class agent
//////////////////////////////////////////////////////////////////////////////

library.cpp

/*	library.cpp		01-03-02
	This file is part of the WADAPT project.
	Copyright (C)1999-2002 Steven Whitney.
	Published under GNU GPL (General Public License) Version 3, with ABSOLUTELY NO WARRANTY.
	Initially published by http://25yearsofprogramming.com.

	Library file for wadapt.ide. It pulls in library routines required by the project.
	Make this an independent project node.
	
	You must include here all headers used anywhere in project, so the
	conditional includes in mylib.cpp know what is needed.

*/
#include <owl\owlpch.h>
#include <owl\chooseco.h>
#include <owl\opensave.h>
#include <owl\radiobut.h>
#include <owl\buttonga.h>
#include <owl\editsear.h>
#include <owl\statusba.h>
#include <owl\controlb.h>
#include <owl\inputdia.h>
#include <classlib\time.h>
#include <classlib\arrays.h>
#include <bwcc.h>					// IDHELP
#include <complex.h>
#include <float.h>       			// _fpreset()
#include <dir.h>                    // MAXPATH
#pragma hdrstop

#include "c:\bcs\my.h"
#include "c:\bcs\library\ddemlapp.h"
#include "c:\bcs\library\sdibwin.h"

#include "wadapt.rh"

#include "c:\bcs\mylib.cpp"
#include "c:\bcs\library\filearay.cpp"
#include "c:\bcs\library\stopwatc.cpp"
#include "c:\bcs\library\sdib.cpp"
#include "c:\bcs\library\doubrect.cpp"

#if !defined(__WIN32__)
	#include "c:\bcs\library\wserial.cpp"
#endif	//!defined(__WIN32__)

#include "wadapt.rh"

 

Valid HTML 4.01 Transitional Valid CSS
Yahoo! Search
Search the web Search this site
View content labeling at ICRA.