#include <stdio.h>
#include <ctype.h>
#include <direct.h>

#ifndef _WIN32
#		define OUTPUT_TEXT
#		define CLEAR_SCREEN			system("clear")
#else
#		ifdef OUTPUT_GRAPHICS
#			define CLEAR_SCREEN			
#		else
#			define CLEAR_SCREEN			system("cls")
#		endif
#endif

#ifdef OUTPUT_SOUND
#		include "afxwin.h"
#		include <MMSYSTEM.h>
#endif

#ifdef OUTPUT_GRAPHICS
#		include "VisionDev.h"
#		include "ImageTypes.h"
#else
#		define THE_APP_OUTPUT printf
#endif

#include "main.h"
#include "Points.h"
#include "GV.h"

//------------------------------------------------------------
typedef G0double ZDouble;
typedef GV<ZDouble>	VDouble;
typedef GV<VDouble>	MDouble;
typedef GV<MDouble>	TDouble;
typedef GV<TDouble>	QDouble;
GVStaticData VDouble::StaticData;
GVStaticData MDouble::StaticData;
GVStaticData TDouble::StaticData;
GVStaticData QDouble::StaticData;

typedef G0byte ZByte;
typedef GV<ZByte>	VByte;
typedef GV<VByte>	MByte;
typedef GV<MByte>	TByte;
GVStaticData VByte::StaticData;
GVStaticData MByte::StaticData;
GVStaticData TByte::StaticData;

typedef G0char ZChar;
typedef GV<ZChar>	VChar;
typedef GV<VChar>	MChar;
typedef GV<MChar>	TChar;
GVStaticData VChar::StaticData;
GVStaticData MChar::StaticData;
GVStaticData TChar::StaticData;

//typedef G0bool ZBool;
//typedef GV<ZBool,101,FALSE>	VBool;
//GVStaticData VBool::StaticData;

typedef G0<int> ZInt;
typedef GV<ZInt>	VInt;
typedef GV<VInt>	MInt;
typedef GV<MInt>	TInt;
typedef GV<TInt>	QInt;
GVStaticData VInt::StaticData;
GVStaticData MInt::StaticData;
GVStaticData TInt::StaticData;
GVStaticData QInt::StaticData;


template <class LLType> class LL : public LinkedList
{
	LLType *m_pLLType;
public:
	LL<LLType>(LL<LLType> *ll)	: LinkedList (ll)
	{ m_pLLType=NULL;}
	LL<LLType>(LL<LLType> *ll, LLType lltype)	: LinkedList (ll)
	{ m_pLLType=new LLType; *m_pLLType=lltype;}
	LL<LLType>(LL<LLType> *ll, LLType *plltype)	: LinkedList (ll)
	{ m_pLLType=plltype;}
	~LL<LLType>()	{ delete m_pLLType;}

public:
	LLType &Data(){return *m_pLLType;}
	const LLType &Data() const {return *m_pLLType;}
	
	LL<LLType> *Next() const { return (LL<LLType> *)LinkedList::Next();}
	LL<LLType> **HNext() { return (LL<LLType> **)LinkedList::HNext();}

	void Print() { m_pLLType->Print(); Next()->Print();}

};

typedef LL<TByte> LLTByte;
typedef LL<double> LLDouble;
typedef LL<unsigned char> LLByte;

typedef G0<unsigned char> Byte;

/*
class LLByte2 : public LinkedList, public Byte
{
public:
	LLByte(LLByte *LLByte)	: LinkedList (LLByte){ };
	LLByte(LLByte *LLByte, unsigned char b)	: LinkedList (LLByte), Byte(b){ };
	
	LLByte *Next() const { return (LLByte *)LinkedList::Next();}
	LLByte **HNext() { return (LLByte **)LinkedList::HNext();}
};
*/

template <class LLType>	void Advance(LLType *&ll)
{ 	LLType *llTemp=ll;	ll=ll->Next();	delete llTemp;	}

#define NUM_SYMBOLS 8
#define NUM_CREATURES 2
#define SYMBOL_PACMAN 0
#define SYMBOL_PWRDOT 5
#define SYMBOL_DOT 4
#define SYMBOL_WALL 6
#define SYMBOL_GHOSTGEN 7
char vchSym[]={'c','A','C','a','.','*','#','G'};


void MMapToTMap(const MChar &mchMap, TByte &tbMap, int *vptLoc, int *ptGhost, int &cDot)
{
	cDot=0;
	int nX,nY,nSym;
	for (nX=mchMap[0].Size()-1; nX>=0; nX--)
		for (nY=mchMap.Size()-1; nY>=0; nY--)
			for (nSym=0; nSym<NUM_SYMBOLS; nSym++)
	{
		char ch=mchMap[nY][nX];

				if ((BYTE)mchMap[nY][nX]==vchSym[nSym])
				{
					tbMap[nY][nX][nSym]=1;
					char ch2=tbMap[nY][nX][nSym];
					if (nSym<NUM_CREATURES)
					{
						vptLoc[nSym*2]=nX;
						vptLoc[nSym*2+1]=nY;
					}
					else if (nSym==SYMBOL_GHOSTGEN)
					{
						ptGhost[0]=nX;
						ptGhost[1]=nY;
					}
					else if (nSym==SYMBOL_DOT || nSym==SYMBOL_PWRDOT)
					{
						cDot++;
					}
				}						
				else
					tbMap[nY][nX][nSym]=0;
	}
}

void MakeInput(const TByte &tbMap, TByte &tb, int nXCenter, int nYCenter)
{
	for (int nX=tb[0].Size()-1; nX>=0; nX--)
		for (int nY=tb.Size()-1; nY>=0; nY--)
			for (int nSym=tb[0][0].Size()-1; nSym>=0; nSym--)
				tb[nY][nX][nSym] = 
					tbMap[(nY+nYCenter-tb.Size()/2+5*tbMap.Size())%tbMap.Size()]
							 [(nX+nXCenter-tb[0].Size()/2+5*tbMap[0].Size())%tbMap[0].Size()]
							 [nSym];
}

template <class GVst> void Rotate(const GV<GVst> &gv, int nRot)
{
	(nRot+=8)%=4;

	if (nRot==0)
		return;

	int cY=gv.Size();
	int cX=gv[0].Size();

	GV<GVst> *pgvR=new GV<GVst>(gv);
	GV<GVst> &gvR=*pgvR;

	int nX,nY;

	switch(nRot)
	{
	case 1:
		for (nX=0; nX<cX; nX++)
			for (nY=0; nY<cY; nY++)
				gvR[nX][cX-nY-1]=gv[nY][nX];
		break;
	case 2:
		for (nX=0; nX<cX; nX++)
			for (nY=0; nY<cY; nY++)
				gvR[cY-nY-1][cX-nX-1]=gv[nY][nX];
		break;
	case 3:
		for (nX=0; nX<cX; nX++)
			for (nY=0; nY<cY; nY++)
				gvR[cY-nX-1][nY]=gv[nY][nX];
		break;
	}

	for (nX=0; nX<cX; nX++)
		for (nY=0; nY<cY; nY++)
		{
			gv[nY][nX]=gvR[nY][nX];
			gvR[nY][nX]=NULL;
		}

	//delete pgvR;
}

		

void UpdateWeights(TDouble &tr, LLTByte *lltb, LLByte *llb, LLDouble *llrScore)
{

	int nX,nY,nSym;
	int cY=lltb->Data().Size()-1;
	int cX=lltb->Data()[0].Size()-1;
 
	double rScore=0;

	// NOTE llb CAN BE SHORTER THAN lltb BECAUSE FINAL MOVE MAY NOT
	// ALWAYS BE TAKEN BY SOME CREATURES
	for (;llb; 		llb=llb->Next()		)
	{
		rScore+=llrScore->Data();
		switch(llb->Data())
		{
		case 0:
			for (nY=tr.Size()-1; nY>=0; nY--)
				for (nX=tr[0].Size()-1; nX>=0; nX--)
					for (nSym=tr[0][0].Size()-1; nSym>=0; nSym--)
						if (lltb->Data()[nY][nX][nSym])
							tr[nY][nX][nSym]=tr[nY][nX][nSym]+rScore;
			break;
		case 1:
			for (nY=tr.Size()-1; nY>=0; nY--)
				for (nX=tr[0].Size()-1; nX>=0; nX--)
					for (nSym=tr[0][0].Size()-1; nSym>=0; nSym--)
						if (lltb->Data()[nY][nX][nSym])
							tr[cY-nX][nY][nSym]=tr[cY-nX][nY][nSym]+rScore;
			break;
		case 2:
			for (nY=tr.Size()-1; nY>=0; nY--)
				for (nX=tr[0].Size()-1; nX>=0; nX--)
					for (nSym=tr[0][0].Size()-1; nSym>=0; nSym--)
						if (lltb->Data()[nY][nX][nSym])
							tr[cY-nY][cX-nX][nSym]=tr[cY-nY][cX-nX][nSym]+rScore;
			break;
		case 3:
			for (nY=tr.Size()-1; nY>=0; nY--)
				for (nX=tr[0].Size()-1; nX>=0; nX--)
					for (nSym=tr[0][0].Size()-1; nSym>=0; nSym--)
						if (lltb->Data()[nY][nX][nSym])
							tr[nX][cX-nY][nSym]=tr[nX][cX-nY][nSym]+rScore;
			break;
		}
		lltb=lltb->Next(); 
		rScore/=2;
		llrScore=llrScore->Next();
	}
}

template <class GVst1, class GVst2> double GVRotateProduct(GV<GVst1> &gv1, GV<GVst2> &gv2, int nRot)
{
	double rT=0;
	int nX,nY;
	int cY=gv1.Size()-1;
	int cX=gv1[0].Size()-1;

	switch(nRot)
	{
	case 0:
		for (nY=cY;  nY>=0; nY--)
			for (nX=cY; nX>=0; nX--)
					rT+=GVProduct(gv1[nY][nX], gv2[nY][nX]);
		break;
	case 1:
		for (nY=cY;  nY>=0; nY--)
			for (nX=cY; nX>=0; nX--)
				rT+=GVProduct(gv1[nY][nX], gv2[cY-nX][nY]);
		break;
	case 2:
		for (nY=cY;  nY>=0; nY--)
			for (nX=cY; nX>=0; nX--)
				rT+=GVProduct(gv1[nY][nX], gv2[cY-nY][cX-nX]);
		break;
	case 3:
		for (nY=cY;  nY>=0; nY--)
			for (nX=cY; nX>=0; nX--)
				rT+=GVProduct(gv1[nY][nX], gv2[nX][cX-nY]);
		break;
	}

	return rT;
}

#ifdef OUTPUT_GRAPHICS
void LoadImages(ColorImage *vi)
{
	char vsICONNAMES[][50]={
		"Blank.bmp",
		"PacMan0.bmp",
		"PacMan1.bmp",
		"PacMan2.bmp",
		"PacMan3.bmp",
		"GhostA0.bmp",
		"GhostA1.bmp",
		"GhostA2.bmp",
		"GhostA3.bmp",
		"PacMan0v.bmp",
		"PacMan1v.bmp",
		"PacMan2v.bmp",
		"PacMan3v.bmp",
		"GhostA0v.bmp",
		"GhostA1v.bmp",
		"GhostA2v.bmp",
		"GhostA3v.bmp",
		"Dot0.bmp",
		"Dot1.bmp",
		"Dot2.bmp",
		"Dot3.bmp",
		"PwrDot0.bmp",
		"PwrDot1.bmp",
		"PwrDot2.bmp",
		"PwrDot3.bmp",
		"Wall0.bmp",
		"Wall1.bmp",
		"Wall2.bmp",
		"Wall3.bmp",
		"Wall4.bmp",
		"Wall5.bmp",
		"Wall6.bmp",
		"Wall7.bmp",
		"Wall8.bmp",
		"Wall9.bmp",
		"Wall10.bmp",
		"Wall11.bmp",
		"Wall12.bmp",
		"Wall13.bmp",
		"Wall14.bmp",
		"Wall15.bmp",
	};

	for (int n=0; n<sizeof(vsICONNAMES)/sizeof(vsICONNAMES[0]); n++)
	{
		char s[200];
		sprintf(s,"Icons\\%s", vsICONNAMES[n]);
		if (!vi[n].Load(s))
			PRINTF("FAILED TO LOAD ICON %d, %s\n", n, s);
		vi[n].FlipVertically();
	}
}

void MapToImage(const MChar &mch, ImageImage &i, ColorImage *vi)
{
	static int cT=0;
	for (int nX=i.Width()-1; nX>=0; nX--)
		for (int nY=i.Height()-1; nY>=0; nY--)
		{
			i[nY][nX]=&vi[0];	
			for (int nSym=0; nSym<NUM_SYMBOLS-1; nSym++) // NO GENERATOR PIC
				if (mch[nY][nX]==vchSym[nSym])
				{
					if (nSym==SYMBOL_WALL)
					{
						int n=0;
						n+=1*(nY>0 && mch[nY-1][nX]==vchSym[SYMBOL_WALL]);
						n+=2*(nX>0 && mch[nY][nX-1]==vchSym[SYMBOL_WALL]);
						n+=4*(nX<i.Width()-1 && mch[nY][nX+1]==vchSym[SYMBOL_WALL]);
						n+=8*(nY<i.Height()-1 && mch[nY+1][nX]==vchSym[SYMBOL_WALL]);

						i[nY][nX]=&(vi[SYMBOL_WALL*4+n+1]);	

						if (SYMBOL_WALL*4+n+1 >= 41) PRINTF("OUT OF RANGE: FAILED TO POINT TO ICON\n");
					}
					else
					{
						i[nY][nX]=&(vi[nSym*4+cT+1]);	
						if (nSym*4+cT+1 >= 41) PRINTF("OUT OF RANGE: FAILED TO POINT TO ICON\n");
					}
					continue;
				}
			}
	cT++;
	cT%=4;
}

template <class G0st> void TensorToImages(const GV< GV< GV< G0< G0st > > > > &t, GrayImage *vi)
{
	for (int nSym=t[0][0].Size()-1; nSym>=0;  nSym--)
	{
		vi[nSym].GetMemory(t[0].Size(), t.Size());
		GrayImage &i=vi[nSym];

		double rMax=-10e100, rMin=10e100;
		int nY,nX;

		for (nY=t.Size()-1; nY>=0; nY--)
			for (nX=t[0].Size()-1; nX>=0; nX--)
		{
			if (rMin>t[nY][nX][nSym])
					rMin=t[nY][nX][nSym];
			if (rMax<t[nY][nX][nSym])
					rMax=t[nY][nX][nSym];
		}
		for (nY=t.Size()-1; nY>=0; nY--)
			for (nX=t[0].Size()-1; nX>=0; nX--)
				i[nY][nX]=(BYTE)((t[nY][nX][nSym]-rMin)/(rMax-rMin)*255);
	}
}

#endif
			
void PlaySound(const char *s)
{
#ifdef OUTPUT_SOUND
	char sOut[200];
	sprintf(sOut,"Sounds\\%s",s);
	sndPlaySound(sOut,SND_ASYNC);
#endif
}

#define SIZE_LEARNING_WINDOW 9

void main ()
{

	PRINTF("TESTING%s", "INPUT_STRING\n");

	// SET UP VARS FOR WORLD STATE
	int cDot=0;
	int vptLoc[NUM_CREATURES][2];
	int ptGhost[2];
	int n, nOut, cPowerDot;
	BOOL fGameOver;
	LLDouble *vllrScore[NUM_CREATURES];

#ifdef OUTPUT_GRAPHICS
	ColorImage vi[41], iOut;
	LoadImages(vi);
	ImageImage ii;
	ImageImage iiTensor;
	GrayImage viTensor[NUM_SYMBOLS],
		viWeightsOut[NUM_CREATURES],
		viWorldView[NUM_CREATURES];

	iiTensor.GetMemory(
						(int)sqrt(NUM_SYMBOLS),
						(NUM_SYMBOLS+1)	/ (int)sqrt(NUM_SYMBOLS));

	for (n=iiTensor.Size()-1; n>=0; n--)
		iiTensor.Data()[n]=&viTensor[n];

#endif


	// PREPARE STORAGE FOR NETWORK 
	int vcWeights[4];
	vcWeights[0]=NUM_CREATURES; // PM & GHOSTS
	vcWeights[1]=SIZE_LEARNING_WINDOW;
	vcWeights[2]=SIZE_LEARNING_WINDOW;
	vcWeights[3]=NUM_SYMBOLS;

	QDouble qrWeights(vcWeights);
	qrWeights.Randomize(0,0);

	// PREPARE STORAGE FOR HISTORY
	int *vcInput=&vcWeights[1];
	LLTByte *vlltbyte[NUM_CREATURES]; // WORLD
	LLByte *vllbyte[NUM_CREATURES]; // MOVE
	for (n=0; n<NUM_CREATURES; n++)
	{
		vllrScore[n]=NULL;
		vlltbyte[n]=NULL;
		vllbyte[n]=NULL;
	}

	// STATISTICS
	int		stat_cWins=0,stat_cMovesWins=0,	stat_cLoss=0, stat_cMovesLoss;

	// MAIN GAME LOOP
#define NUM_ITERATIONS_PER_LEVEL 300
#define NUM_GAMES 10
#define NUM_MAX_MOVES 300

#define NUM_START_LEVEL 0

#define TIME_POWERDOT_LASTS 20

#define SCORE_GHOSTKILL		5
#define SCORE_PACMANKILL	10
#define SCORE_PACMANDIE		-10
#define SCORE_COMPLETED		10
#define SCORE_POWERDOT		4
#define SCORE_DOT					2
#define SCORE_EXIST				0
#define SCORE_STATIONARY	-3
#define SCORE_OUTOFTIME		-10

#define RECORD_BOARDS 0

	for (int cGame=0;cGame<NUM_GAMES*NUM_ITERATIONS_PER_LEVEL;cGame++)
	{
		int cLevel=cGame/NUM_ITERATIONS_PER_LEVEL+NUM_START_LEVEL;
		int cIteration=cGame%NUM_ITERATIONS_PER_LEVEL;
		int cMoves=0;
		fGameOver=FALSE;
		cPowerDot=0;

		PlaySound("theme.wav");
		// LOAD MAP
		char s[100];
		sprintf(s, "h:\\projects\\pacman\\PacManMap%d.gv2b", cLevel);
		MChar *pmchMap=new MChar(s);
		MChar &mchMap=*pmchMap;
		
		// CONVERT INTO A TENSOR
		int vcMap[3];
		vcMap[0]=mchMap.Size();
		vcMap[1]=mchMap[0].Size();
		vcMap[2]=NUM_SYMBOLS;
		TByte *ptbMap=new TByte(vcMap);
		TByte &tbMap=*ptbMap;

		MMapToTMap(mchMap, tbMap, (int *) vptLoc, ptGhost,  cDot);

		do
		{
#ifdef OUTPUT_TEXT
				CLEAR_SCREEN;
				if (stat_cWins && stat_cLoss)
					PRINTF("PAC-MAN WINS: %d (%lf mpg)\t	GHOST WINS: %d (%lf mpg)\n",
						stat_cWins,
						(double)stat_cMovesWins/stat_cWins,
						stat_cLoss,
						(double)stat_cMovesLoss/stat_cLoss
						);

				PRINTF("* GAME %d] LEVEL=%d  ITER/LEVEL=%d  MOVE=%d\n", 
					cGame, 
					cLevel,
					cIteration,
					cMoves);

				PRINTF("====================================\n");
#endif

				double mrOutput[NUM_CREATURES][4];

			// BUILD INPUT TENSOR
			for (n=0; n<NUM_CREATURES; n++)
			{
				vlltbyte[n] = new LLTByte(vlltbyte[n], new TByte(vcInput));
				MakeInput(tbMap, (vlltbyte[n])->Data(),
					vptLoc[n][0], vptLoc[n][1]);

				for (nOut=0; nOut<4; nOut++)
					mrOutput[n][nOut]=GVRotateProduct(qrWeights[n],vlltbyte[n]->Data(),nOut);

				// INITIALIZE ROUND SCORE ACCUMULATOR
				vllrScore[n]=new LLDouble(vllrScore[n], 0.);
			}	

			// CHOOSE BEST MOVE
			for (n=0; n<NUM_CREATURES && !fGameOver; n++)
			{
				double rOutMax=-10e100;
				int nOutMax=-1;
				const int vdX[]={0, 1, 0,-1};
				const int vdY[]={-1, 0, 1, 0};

				double rOutMin=10e100;
				for (nOut=0; nOut<4; nOut++)
					if (rOutMin>mrOutput[n][nOut])
						rOutMin=mrOutput[n][nOut];
				double rOutTotal=0;
				for (nOut=0; nOut<4; nOut++)
					rOutTotal+=(mrOutput[n][nOut]-rOutMin);
				double rExplore=.1;
				double rRand=((double)rand()/RAND_MAX)*(rOutTotal+rOutTotal*4*rExplore+4);
				for (nOut=0; nOut<4 && rRand>0; nOut++)
					rRand-=(mrOutput[n][nOut]-rOutMin+rOutTotal*rExplore+1);
	
				nOutMax=nOut-1;
				
#ifdef OUTPUT_TEXT
				// OUTPUT STUFF
				char sDirs[]="URDL";
				for (nOut=0; nOut<4; nOut++)
					PRINTF("Cost %d %c] %.0lf\n",n,sDirs[nOut], mrOutput[n][nOut]);
				for (nOut=0; nOut<4; nOut++)
					PRINTF("Relative Costs %d %c] %.0lf\n",n,sDirs[nOut], mrOutput[n][nOut]-rOutMin);
				for (nOut=0; nOut<4; nOut++)
					PRINTF("Exploration Costs %d %c] %.0lf\n",n,sDirs[nOut], mrOutput[n][nOut]-rOutMin+rOutTotal*rExplore+1);
				PRINTF("Best %d %c] %.0lf\n",nOutMax,sDirs[nOutMax], mrOutput[n][nOutMax]);
#endif

				// SET UP VARS
				int nPwrDot=NUM_CREATURES * (cPowerDot!=0);
				int n2;

				// MAKE CHOSEN MOVE 
				// UPDATE CHARACTER MAP
				mchMap[vptLoc[n][1]][vptLoc[n][0]]=	
						tbMap[vptLoc[n][1]][vptLoc[n][0]][SYMBOL_DOT] != 0
							? vchSym[SYMBOL_DOT] 
							:	tbMap[vptLoc[n][1]][vptLoc[n][0]][SYMBOL_PWRDOT] != 0
							? vchSym[SYMBOL_PWRDOT] 
							: (unsigned char)' '; 
				// CLEAR OLD POSITION
				tbMap[vptLoc[n][1]][vptLoc[n][0]][n+nPwrDot]=0;
				tbMap[vptLoc[n][1]][vptLoc[n][0]][n]=0;

				// CALCULATE NEW POSITION IF OK
				int dX=vdX[nOutMax];
				int dY=vdY[nOutMax];
				BYTE b=tbMap[(vptLoc[n][1]+dY+4*tbMap.Size())%tbMap.Size()]
					[(vptLoc[n][0]+dX+4*tbMap[0].Size())%tbMap[0].Size()][SYMBOL_WALL];
				if (!b)
				{
					vptLoc[n][1]=(vptLoc[n][1]+dY+4*tbMap.Size())%tbMap.Size();
					vptLoc[n][0]=(vptLoc[n][0]+dX+4*tbMap[0].Size())%tbMap[0].Size();
				}
				else
					vllrScore[n]->Data()+=SCORE_STATIONARY;

				// MOVE TO NEW POS
				tbMap[vptLoc[n][1]][vptLoc[n][0]][n+nPwrDot]=1;
				// UPDATE CHARMAP TO NEW POS				
				mchMap[vptLoc[n][1]][vptLoc[n][0]]=vchSym[n+nPwrDot];

				// OUTPUT DISPLAY STUFF
#ifdef OUTPUT_TEXT
				mchMap.Print();
#endif

#ifdef OUTPUT_GRAPHICS
				ii.GetMemory(mchMap[0].Size(),mchMap.Size());
				MapToImage(mchMap,ii,vi);
				ii.Draw(iOut);
				iOut.Show();
				iOut.SetName("learn, PacMAN, LEARN");

				TensorToImages(qrWeights[n],viTensor);
				iiTensor.Draw(viWeightsOut[n]);
				viWeightsOut[n].Show();
				sprintf(s,"Weighting Array Creature %d", n);
				viWeightsOut[n].SetName(s);

				TensorToImages(vlltbyte[n]->Data(),viTensor);
				iiTensor.Draw(viWorldView[n]);
				viWorldView[n].Show();
				sprintf(s,"World View %d", n);
				viWorldView[n].SetName(s);
#endif

				vllbyte[n]=new LLByte(vllbyte[n],nOutMax);

				//-------------- UPDATE WORLD & COMPUTE SCORES
				vllrScore[n]->Data()+=SCORE_EXIST;
				if (n==SYMBOL_PACMAN)
				{
					if (tbMap[vptLoc[SYMBOL_PACMAN][1]][vptLoc[SYMBOL_PACMAN][0]][SYMBOL_PWRDOT]==1)
					{
						cPowerDot=TIME_POWERDOT_LASTS;
						vllrScore[SYMBOL_PACMAN]->Data()+=SCORE_POWERDOT;
						tbMap[vptLoc[SYMBOL_PACMAN][1]][vptLoc[SYMBOL_PACMAN][0]][SYMBOL_PWRDOT]=0;
						cDot--;
						if (!cDot) 
							fGameOver=TRUE;

						PlaySound("Dot.wav");

					}
					if (tbMap[vptLoc[SYMBOL_PACMAN][1]][vptLoc[SYMBOL_PACMAN][0]][SYMBOL_DOT]==1)
					{
						vllrScore[SYMBOL_PACMAN]->Data()+=SCORE_DOT;
						tbMap[vptLoc[SYMBOL_PACMAN][1]][vptLoc[SYMBOL_PACMAN][0]][SYMBOL_DOT]=0;
						cDot--;
						if (!cDot) 
							fGameOver=TRUE;
						PlaySound("pwrDot.wav");
					}
				}

				// CHECK FOR COMPLETION
				if (n==SYMBOL_PACMAN && cDot==0)
				{
					vllrScore[SYMBOL_PACMAN]->Data()+=SCORE_COMPLETED;
					fGameOver=TRUE;
					stat_cWins++;
					stat_cMovesWins+=cMoves+1;
				}

				// CHECK FOR COLLISIONS
				for (n2=1; n2<NUM_CREATURES; n2++)
					if (tbMap[vptLoc[SYMBOL_PACMAN][1]][vptLoc[SYMBOL_PACMAN][0]][n2+nPwrDot]==1)
					{
						if (cPowerDot)
						{
							vllrScore[SYMBOL_PACMAN]->Data()+=SCORE_GHOSTKILL;
							tbMap[vptLoc[n2][1]][vptLoc[n2][0]][n2+nPwrDot]=0;
							vptLoc[n2][1]=ptGhost[1];
							vptLoc[n2][0]=ptGhost[0];
							tbMap[vptLoc[n2][1]][vptLoc[n2][0]][n2+nPwrDot]=1;
							PlaySound("ghostkill.wav");
						}
						else if (!fGameOver)
						{
							vllrScore[SYMBOL_PACMAN]->Data()+=SCORE_PACMANDIE;
							vllrScore[n2]->Data()+=SCORE_PACMANKILL;

							fGameOver=TRUE;
							PlaySound("pacmankill.wav");

							stat_cLoss++;
							stat_cMovesLoss+=cMoves+1;
						}
					}

#if OUTPUT_TEXT
			// OUTPUT SCORES
			PRINTF("Score %d: %lf.0\n", n, vllrScore[n]->Data());
#endif
			}

			// CHECK FOR TOO MANY MOVES
			cMoves++;
			if (cMoves>NUM_MAX_MOVES)
			{
				for (n=0; n<NUM_CREATURES; n++)
					vllrScore[SYMBOL_PACMAN]->Data()+=SCORE_OUTOFTIME;
				fGameOver=TRUE;
			}	

			// DECTREASE POWERDOT TIMER
			if (cPowerDot)
				cPowerDot--;
		// UPDATE WEIGHTS
		}	
		while (!fGameOver);

		for (n=0; n<NUM_CREATURES; n++)
			UpdateWeights(qrWeights[n], vlltbyte[n], vllbyte[n], vllrScore[n]);


		// CLEAN UP
		for (n=0; n<NUM_CREATURES; n++)
		{
			while (vllrScore[n])
				Advance(vllrScore[n]);
			while (vllbyte[n])
				Advance(vllbyte[n]);
			while (vlltbyte[n])
				Advance(vlltbyte[n]);
		}
		delete ptbMap;
		delete pmchMap;
		
		sprintf(s, "PacManWeights%d.gv4f", cGame/NUM_ITERATIONS_PER_LEVEL);
		qrWeights.Save(s);

	}
}













	
	


	

	





