#include <solver.h> #include <stdbran.h> Node *CurrentBaseNode; /* base from which path is calculated */ Path *PathFromBase; /* path from base node */ int X; int Y; /* Current co-ords */ int SearchX; int SearchY; /* Coordinates to aim for */ Maze *TheMaze; /* Store for all maze info */ int FactorToFinish; /* Current Inconvenience Factor to Finish */ Node *FinishNode; /* Finish node or NULL if not found */ int MazeCompleted; Exits CurExits; void Solver_Go() { X=0; Y=0; Maze_MAKE(&TheMaze); Maze_SetFirstNode(TheMaze,0,0,EXIT_N); CurrentBaseNode=Maze_NodePtr(TheMaze,0,0); FinishNode=NULL; FactorToFinish=IF_VERY_FAR; MazeCompleted=0; Maze_BeenAt(TheMaze,0,0,EXIT_N); SearchX=7; SearchY=7; while (!MazeCompleted) { int OldFactor; Path *P; OldFactor=FactorToFinish; while (((OldFactor-FactorToFinish)<=(FactorToFinish >> 5))&& !MazeCompleted) Solver_Explore(); P=Maze_BestPathBetween(TheMaze,CurrentBaseNode,Maze_NodePtr(TheMaze,0,0)); Solver_MovePath(P); Path_KILL(&P); /* cout << "Making Run:" << endl; */ P=Maze_BestPathBetween(TheMaze,Maze_NodePtr(TheMaze,0,0),FinishNode); Solver_MovePath(P); Path_KILL(&P); /* cout << "(Factor = " << FactorToFinish << " )" << endl; */ CurrentBaseNode=FinishNode; } Maze_KILL(&TheMaze); } Exits Solver_ExitDirs(){ return CurExits; } void Solver_Move(Dir d) { Path *P; P=Path_PathOf(d); Solver_MovePath(P); Path_KILL(&P); } void Solver_MovePath(Path *P) { Path *P1; int i; CurExits=MC_Move(P); P1=Path_ADD(PathFromBase,P); Path_KILL(&PathFromBase); PathFromBase=P1; for (i=0;i<Path_NumberOfMoves(P);i++) { Move M; M=Path_MoveNo(P,i); X+=DX[DIRNUM(M)]*(M&MOVE_LENMASK); Y+=DY[DIRNUM(M)]*(M&MOVE_LENMASK); } Maze_BeenAt(TheMaze,X,Y,Solver_ExitDirs()); } void DumpMaze(Maze *); void Solver_Explore() { if (Debug) DumpMaze(TheMaze); Maze_LinkNeighbours(TheMaze); if (PathFromBase) { Path_KILL(&PathFromBase); Path_MAKE(&PathFromBase); } switch (Node_Status(CurrentBaseNode)) { case NODE_FINISH: { Maze_KillUseless(TheMaze,NULL); if (!FinishNode) { FinishNode=CurrentBaseNode; SearchX=4; SearchY=4; } else { Path *P; P=Solver_PathToNode(); if (Path_NumberOfMoves(P)) Solver_MovePath(P); else MazeCompleted=1; Path_KILL(&P); } break; } case NODE_TERMINAL: { Path *P; P=PathFromBase; PathFromBase=Path_REVCOPY(Node_ExploredPath(CurrentBaseNode)); Path_KILL(&P); Maze_KillNodeAt(TheMaze,X,Y); P=Path_REVCOPY(PathFromBase); Solver_MovePath(P); Path_KILL(&P); break; } case NODE_DEAD: { Path *P1; Path *P2; Dir D; P1=PathFromBase; P2=Path_REVCOPY(Node_ExploredPath(CurrentBaseNode)); PathFromBase=Path_ADD(P1,P2); Path_KILL(&P1); Path_KILL(&P2); D=Node_UnexploredDir(CurrentBaseNode); CurrentBaseNode=Node_AGoodLink(CurrentBaseNode); Maze_KillNodeAt(TheMaze,X,Y); Solver_Wander(D); break; } case NODE_COMPLETED: { Path *P; P=Solver_PathToNode(); if (Path_NumberOfMoves(P)) Solver_MovePath(P); /* move to chosen uncompleted node */ else MazeCompleted=1; Path_KILL(&P); break; } case NODE_UNCOMPLETED: { int dx; int dy; Dir d1; Dir d2; /* perform maze simplification if possible */ while (Maze_Simplify(TheMaze,FinishNode)); /* find an unexplored direction + go that way */ dx=(X<8 ? 8 : 7)-X; dy=(Y<8 ? 8 : 7)-Y; if ((dx<0 ? -dx : dx)>(dy<0 ? -dy : dy)) { d1=(dx<0 ? DIR_W : DIR_E); d2=(dy<0 ? DIR_S : DIR_N); } else { d1=(dy<0 ? DIR_S : DIR_N); d2=(dx<0 ? DIR_W : DIR_E); } if (!Node_IsUnexplored(CurrentBaseNode,d1)) d1=d2; if (!Node_IsUnexplored(CurrentBaseNode,d1)) d1=Node_UnexploredDir(CurrentBaseNode); Solver_Wander(d1); } } CurrentBaseNode=Maze_NodePtr(TheMaze,X,Y); if (FinishNode) { Path *P; P=Maze_BestPathBetween(TheMaze,Maze_NodePtr(TheMaze,0,0),FinishNode); FactorToFinish=Path_IncFactor(P); Path_KILL(&P); } } void Solver_Wander(Dir StartDir) { Dir D; Path *P; Exits E; Solver_Move(StartDir); /* continue until node or dead end */ D=StartDir; while (Exits_NumExits(E=Solver_ExitDirs())==2) { Dir d1,d2; FOREACH_DIR(d1) if ( d1!=(D^DIR_REVERSE) && Exits_IsExitTo(E,d1) ) { d2=d1; } D=d2; Solver_Move(D); } P=Path_REVCOPY(PathFromBase); if (!Maze_IsNode(TheMaze,X,Y)) { /* unseen node */ Maze_AddNode(TheMaze,X,Y,Solver_ExitDirs(),CurrentBaseNode,P); } else { Node_LinkTo(Maze_NodePtr(TheMaze,X,Y),CurrentBaseNode,P); } Path_KILL(&P); } Path *Solver_PathToNode() { /* Looks in a spiral path for the nearest uncompleted node to SearchX,SearchY */ Path *P; Node *N; int x; int y; int dx; int dy; x=SearchX; y=SearchY; dx=0; dy=1; P=NULL; while ((dx<=16)&&!P) { if (x>=0&&x<=15&&y>=0&&y<=15) N=Maze_NodePtr(TheMaze,x,y); x+=dx; y+=dy; if (!dx) { dx=dy; dy=0; } else { dy=(dx<0?1-dx:-1-dx); dx=0; } } if (N) P=Maze_BestPathBetween(TheMaze,CurrentBaseNode,N); return P; }