//////////////////////////////////////////////////////////////// // *** Filbert_Einstein *** // // // // a.k.a. DoomsDray // // a.k.a. Trial_by_Scurry // // a.k.a. Cheek_Full_O_Nuts // // // // Copyright (C) 2004 - William Little // // Limited right to publish granted to Fred Hicinbothem. // // All other rights reserved. // //////////////////////////////////////////////////////////////// //Defines #define SWAP(x,y) { int temp=(y)-(x); y=(x); x+=temp; } //Swaps ints & ptrs #define ITERATION_LIMIT 1000000 #define TIME_LIMIT 58 #define NUT_VALUE 232792560 //The value of one nut #define RANDOM_FACTOR 100000 //The limit of random value skew //Includes #include #include #include #include #include #include #include //Random number code #define myrand() ((unsigned int)((myrandseed=myrandseed*1684056135+342964307)>>33)) #define myseed(x) myrandseed=((unsigned long long)(x))<<33; unsigned long long myrandseed=1ULL<<33; //Globals int NumNuts, *NutX, *NutY, NumSquirrels, *SquirrelX, *SquirrelY, StartX, StartY, BoardSize, *NutTime, *NutSplit, *NutActive, ActiveNuts; //Prototypes void SingleSquirrelGame(void); void MultiSquirrelGame(void); int Recurse(int x, int y, int held, int t, int depth); int Distance(int x1, int y1, int x2, int y2); int Evaluate(int x, int y, int *path); int InitializeBoard(FILE *fp); void CleanUp(void); int GeneratePath(int *result); void OutputMove(int x, int y); void WritePath(int *path); int ReadPath(int *path); int main(int argc, char *argv[]) { //Initialize the random number generator myseed(time(0)); //Read in the game board state, and initialize globals int rc; assert(argc==2); FILE *fp=fopen(argv[1],"rt"); assert(fp); rc=InitializeBoard(fp); assert(rc==0); rc=fclose(fp); assert(rc==0); //Call the appropriate engine for this game if(NumSquirrels==1) SingleSquirrelGame(); else MultiSquirrelGame(); //Clean up and shut down CleanUp(); return(0); } //The main routine for single squirrel games (POTM #1) void SingleSquirrelGame(void) { //Allocate variables int *path=new int[NumNuts]; assert(path); int *bestpath=new int[NumNuts]; assert(bestpath); int bestscore=INT_MAX; switch(NumNuts) { //Special case for 1 nut case 1: *bestpath=0; break; //Special case for 2 nuts case 2: if(Distance(StartX,StartY,NutX[0],NutY[0])<= Distance(StartX,StartY,NutX[1],NutY[1])) { bestpath[0]=0; bestpath[1]=1; } else { bestpath[0]=1; bestpath[1]=0; } break; //Normal case default: //Read previous best path from the temporary file, and adjust as needed if(!ReadPath(bestpath)) bestscore=Evaluate(StartX,StartY,bestpath); //Keep trying to make a better path until the time limit is reached while(clock()<(TIME_LIMIT*CLOCKS_PER_SEC)) { int score=GeneratePath(path); if(score0;s--) { for(int i=0;i0;ActiveNuts--) { int bestnut, bestscore=-1, bestdist; for(int i=0;ibestscore) { bestscore=score; bestdist=dist; bestnut=i; } } //Update various variables to reflect this squirrel's move x=NutX[bestnut]; y=NutY[bestnut]; t+=bestdist; NutActive[bestnut]=0; if(tbestscore) { bestscore=score; bestnut=i; } } //Output our move OutputMove(NutX[bestnut],NutY[bestnut]); //Clean up delete [] NutActive; delete [] NutSplit; delete [] NutTime; } //The recursion engine for the 3-ply move-tree search int Recurse(int x, int y, int held, int t, int depth) { if((!ActiveNuts) || (!depth)) return(held/t+(myrand()%RANDOM_FACTOR)); depth--; int bestscore=-1; for(int i=0;ix2)?(x-x2):(x2-x); y2=(y>y2)?(y-y2):(y2-y); eta=t+((x2>y2)?x2:y2); } //Calculate the probable gain for the nut in question int gain=0; if(eta<=NutTime[i]) { gain=NUT_VALUE; if(eta==NutTime[i]) gain/=NutSplit[i]+1; } //Combine these values along with future potential to form the score int score; if(depth>0) { //We are a branch NutActive[i]=0; ActiveNuts--; score=Recurse(NutX[i],NutY[i],held+gain,eta,depth); ActiveNuts++; NutActive[i]=1; } else { //We are a leaf score=(held+gain)/eta+(myrand()%RANDOM_FACTOR); } if(score>bestscore) bestscore=score; } assert(bestscore>=0); return(bestscore); } int Distance(int x1, int y1, int x2, int y2) { register int xd=(x1>x2)?(x1-x2):(x2-x1), yd=(y1>y2)?(y1-y2):(y2-y1); return((xd>yd)?xd:yd); } int Evaluate(int x, int y, int *path) { register int total=0; for(int i=0;ia)?(x-a):(a-x); b=(y>b)?(y-b):(b-y); total+=(a>b)?a:b; } x=NutX[*path]; y=NutY[*path]; path++; } return(total); } //Read in the game board state, and initialize globals int InitializeBoard(FILE *fp) { char buf[100]; int x, y, yous=0, sizes=0; NumNuts=NumSquirrels=0; while(!feof(fp)) { int rc=fscanf(fp,"%[a-zA-Z]=%d,%d\n",buf,&x,&y); if(rc!=3) break; if(strcasecmp(buf,"NUT")==0) NumNuts++; if(strcasecmp(buf,"SQUIRREL")==0) NumSquirrels++; } NutX=new int[NumNuts]; assert(NutX); NutY=new int[NumNuts]; assert(NutY); SquirrelX=new int[NumSquirrels]; assert(SquirrelX); SquirrelY=new int[NumSquirrels]; assert(SquirrelY); rewind(fp); int n=0, s=0; while(!feof(fp)) { int rc=fscanf(fp,"%[a-zA-Z]=%d,%d\n",buf,&x,&y); if(rc!=3) break; if(strcasecmp(buf,"NUT")==0) { NutX[n]=x; NutY[n]=y; n++; } else if(strcasecmp(buf,"SQUIRREL")==0) { SquirrelX[s]=x; SquirrelY[s]=y; s++; } else if(strcasecmp(buf,"YOU")==0) { StartX=x; StartY=y; yous++; } else if(strcasecmp(buf,"SIZE")==0) { assert(x==y); BoardSize=x+1; sizes++; } } assert(n==NumNuts); assert(s==NumSquirrels); assert(yous==1); assert(sizes==1); //Make sure we are the first Squirrel in the list for(s=0;s0;i--) { int newdistance=Distance(NutX[result[i-1]],NutY[result[i-1]], NutX[result[j]],NutY[result[j]])+ Distance(NutX[result[j]],NutY[result[j]], NutX[result[i]],NutY[result[i]])- Distance(NutX[result[i-1]],NutY[result[i-1]], NutX[result[i]],NutY[result[i]]); if(newdistance=(TIME_LIMIT*CLOCKS_PER_SEC)) break; } iterations++; memcpy((void *)path,(void *)result,sizeof(int)*NumNuts); { //Mutate by reversing a section at random register int *first=path+(myrand()%NumNuts), *last=path+(myrand()%NumNuts); if(first>last) SWAP(first,last); //If the reversal's going to make things worse, skip it. { int x1=StartX, y1=StartY, x2=NutX[*first], y2=NutY[*first], x3=NutX[*last], y3=NutY[*last]; if(first>path) { x1=NutX[*(first-1)]; y1=NutY[*(first-1)]; } if((last+1)==(path+NumNuts)) { if(Distance(x1,y1,x2,y2)first) { SWAP(*first,*last); first++; last--; } } int score=Evaluate(StartX,StartY,path); assert(score<=resultscore); if(scoreStartX) x=StartX+1; else if(xStartY) y=StartY+1; else if(y0); } rc=fclose(fp); assert(rc==0); } //Read a path from the temporary file, and determine it's relevancy //Returns zero if successful int ReadPath(int *path) { int rc; int *nutuses=new int[NumNuts]; assert(nutuses); for(int i=0;i