Ja, und ich bin mal nett und ls das Rtsel auf. ;) Alle folgenden
Angaben beziehen sich auf interne Koordinaten, fr Screenkoordinaten
is also durch 8 zu teilen.

Sei w das Winkelbyte (Bereich 0..255).

Sei astsin(w) = round(127*sin(angle/128*pi)).

Sei astcos(w) = round(127*cos(angle/128*pi)).

Sei (sx, sy) die Position des Schiffes, (vx, vy) die Geschwindigkeit
des Schiffes.

Dann ist die Starposition (bx, by) des Schusses:
bx = sx + floor(astcos(w)/2) + floor(floor(astcos(w)/2)/2) und
by = sy + floor(astsin(w)/2) + floor(floor(astsin(w)/2)/2)
oder in Nherung
bx = sx + 95 * cos(w/128*pi)
by = sy + 95 * sin(w/128*pi)

Die Geschwindigkeit (fx, fy) des Schusses ist:
fx = vx + floor(astcos(w)/2)
fy = vy + floor(astsin(w)/2)
oder in Nherung
fx = vx + 64 * cos(w/128*pi)
fy = vy + 64 * sin(w/128*pi)

Ist fx bzw. fy jedoch kleiner als -111 oder grer als 111, so wird
die Komponente auf -111 bzw. 111 begrenzt.



#if 0
int getHitData(
			/// my current position					
			const  vecIntC & p0,			
			/// this distance on which offset the shot starts from my position
			float fireOff,
			/// the speed of the object that we fire ..
			float fireSpeed,
			/// my target object position0 and position1
			const vecIntC & posTarget0,const vecIntC & posTarget1,
			/// my target object timing
			unsigned int t0,unsigned int t1,
			///
			int maxTime,
			/// minimal distance of object
			int minDist,
			/// max result that i want
			int maxResults,
			/// return return
			int * resultCount,
			/// return a array of angle and timing for a possible hit in center of object (angle is not in wb)
			float * resultArray)
{
	// init return value
	*resultCount=0;
	
	// idee find the timing to hit from my position the target
	vecDblC dblP0(convVec(p0));
	vecDblC dblPosTarget0(convVec(posTarget0));
	vecDblC dblPosTarget1(convVec(posTarget1));

	vecDblC headTarget(dblPosTarget1-dblPosTarget0);
	vecDblC headTargetNorm=headTarget.norm(1);

	float deltaT=t1-t0;
	float speedTarget=headTarget.len()/deltaT;

	// first try fire to original point

	

	while(42)
	{
		// last hitTime
		float hitTime=0;
		int    found  =0;
		float lastDist=1e10;

		vecDblC fireTargetPoint(dblPosTarget0);
		vecDblC headFire;
		
		while(42)
		{		
			
			// try to get a intersection point within 200 radius ..
			int		 hitCount;
			
			// bring vector in correct screen relation
			
			headFire=(fireTargetPoint-dblP0).norm(1);
			if (!intersectWrapLineLine(dblP0,dblP0+headFire*fireSpeed,dblPosTarget0,dblPosTarget1,t0,t0+1,t0,t1,maxTime,1024,1,&hitCount,&hitTime))
				break;

			if (t0+hitTime>maxTime)
				break;

			vecDblC targetCur=dblPosTarget0+headTargetNorm*speedTarget*(hitTime);
			vecDblC hitPoint =dblP0+headFire*fireSpeed*hitTime;

			vecScreenPositionMap(targetCur,hitPoint);

			float dist=(targetCur-hitPoint).len();
			if (fabs(dist-lastDist)<0.001)
			{ found=dist<0.01;
				break;
			}
			lastDist=dist;
			float addTime=dist/speedTarget;

			fireTargetPoint=fireTargetPoint+headTargetNorm*speedTarget*addTime;						
		}

		if (!found)
			break;
		// we found one point .. try the next ..
		resultArray[*resultCount*2+0]=t0;
		resultArray[*resultCount*2+1]=angle(headFire);
		if ((*resultCount)>=maxResults)
			break;

		(*resultCount)++;
		
		hitTime=1;
		dblPosTarget0=dblPosTarget0+headTargetNorm*speedTarget*(hitTime);
		dblPosTarget1=dblPosTarget0+headTargetNorm*speedTarget;
		vecScreenPositionMap(dblPosTarget0,dblPosTarget1);
		t0=t0+hitTime;
		t1=t0+deltaT;
		
	}

	return *resultCount;

}
#endif


/** methode to get timing for intersection of a two objects with a given angle 
    p0,dir0 is the object that fire
		p1,dir1 is the target object

		the timing is the wait time for p0,dir0
*/
int intersectWrapLineLineTiming(
    /// point for first and for second line				
		const vecDblC & p0,const vecDblC & dir0,
		///
		const vecDblC & p1,const vecDblC & dir1,					
		///
		int maxTimeWait,
		///
		int maxTimeWay,
		/// minimal distance which is accepted until we try to make "wait states"
		int minDist,
		/// per result item are two results !
		int maxResult,
		/// number of return results
		int * resultCount,
		/** return array for the times the return pairs are
		    resultArray[2*n+0]=offset;
				resultArray[2*n+1]=time of hit;		    
		*/
		float * resultArray
);

/** methode to get timing for intersection of a two objects with a given angle */
int intersectWrapLineLineTiming(    
		const vecDblC & p0,const vecDblC & dir0,		
		const vecDblC & p1,const vecDblC & dir1,
		int maxTimeWait,
		int maxTimeWay,
		int minDist,
		int maxResult,
		int * resultCountRet,
		float * resultArrayRet
)
{
	*resultCountRet=0;

	vecDblC dir1Full=dir1-dir0;

	if (dir1Full.len()<1e-5)
	{
		// the object will not move because the direction vector ads to zero ..
		
		return 0;
	}
	// so the new second line use p2Dbl as base and head2Full as direction

	// next step is to use this new line to intersect with our now "based" point	
	int resultCount;
	float resultArray[20];

	float dir1Len=dir1.len();

	// calc the angle between the direction and the corrected direction
	float beta=angle(dir1Full.norm(1),dir1.norm(1));

	//
	float scan=float(minDist)+float(maxTimeWait)*dir1Len;
		
	// we use here one result more because the first maybe behind us ..
	intersectWrapLinePoint(p1,dir1Full,p0,maxTimeWay+maxTimeWait,scan,maxResult+1,&resultCount,resultArray);
		
	for (int i=0;i<resultCount && (*resultCountRet)<maxResult;i++)
	{
		// calc the "next to target" position
		vecDblC pos(p1+dir1Full*resultArray[i]);

		vecScreenPositionNormalize<float>(p0,pos);
		
		vecDblC h(p0-pos);
		
		float hLen=h.len();

		/*
		if (hLen>float(minDist))
			break;
		*/

		if (hLen<float(minDist) || fabs(beta)<1e-6)
		{
			if (resultArray[i]<maxTimeWay)
			{
				resultArrayRet[*resultCountRet*2+0]=0;
				resultArrayRet[*resultCountRet*2+1]=resultArray[i];
				(*resultCountRet)++;				
			}

			continue;

		}
		// the point is before us .. we already miss 
		if (h.skalar(dir0)<0)
			continue;
		
		
		// this is "sinus-satz" to calc the missing length to target parallel to dir1
		float aorg=fabs(hLen/sin(beta));
		float a=aorg/dir1Len;

		if (a>maxTimeWait)
			continue;

		// we know that we need resultArray[i] time to get to the near distance
		// and we now know that we need a time to move to the shoot position
		// a^2 = hLen^2 + x^2 -> x=sqrt(a^2-hLen^2)
		float th=sqrt(aorg*aorg-hLen*hLen);

		
		if (beta>PI)
			th=-th;
		

		float tHit=(resultArray[i]*dir1Full.len()-th)/dir1Full.len();
				
		if (tHit>maxTimeWay || tHit<0)
			continue;
								
		resultArrayRet[*resultCountRet*2+0]=a;
		resultArrayRet[*resultCountRet*2+1]=tHit;
		(*resultCountRet)++;
		
	}

	return * resultCountRet;			
}

/**** code to create permutation */
vector<string> PHIL_Permutation(const char* input) 
{ 
    char a[32]; 
    strcpy(a, input); 
    int N = strlen(a);        // constant index ceiling (a[N] length) 
    int ax = N - 1;            // constant index ceiling (a[N] length) 
    int *p = new int[N+1];  // target array and index control array 
    int i, j, tmp;            // index variables and tmp for swap 

    for(i = 0; i < N+1; i++)    // p[N] > 0 controls iteration and the index boundary for i 
    p[i] = i; 

    vector<string> result; 
    result.insert(result.end(), a);       

    i = 1;   // setup first swap points to be ax-1 and ax respectively (i & j) 
    while(i < N) 
    { 
        p[i]--;                // decrease index "weight" for i by one 
        j = ax - i % 2 * p[i]; // IF i is odd then j = ax - p[i] otherwise j = ax 
        i = ax - i;            // adjust i to permute tail (i < j) 

        // set Scope 
        { 
            tmp = a[j];        // swap(a[i], a[j]) 
            a[j] = a[i]; 
            a[i] = tmp; 
            result.insert(result.end(), a);       
        } 

        i = 1;                 // reset index i to 1 (assumed) 
        while (!p[i])          // while (p[i] == 0) 
        { 
            p[i] = i;           // reset p[i] zero value 
            i++;                // set new index value for i (increase by one) 
        } 
    } 

    delete [] p; 
    return result; 
}


///////////////////////
#include "gameobj.h"

/// this methode will update our records with a forecast and all tx timings
void planHit(int currentTime,int currentRotationIndex,const gameObjListC & inputList,int & direction);

typedef constArrayT<50,unsigned int> hitListT;
typedef unsigned long long filterT;
/** this is out hitplan object
    it will supoprt us on the way to give information on possible hits and data
*/
class hitTableC {
	/// one entry in table
	struct tableLineEntryS {
		/// ctor
		tableLineEntryS() {updateTime=0;key=0;waitTime=0;flyTime=0;filter=0;}
		/// update time for entry
		unsigned int updateTime;
		/// key of object
		unsigned int key;
		/// waitTime to fire from here
		int waitTime;
		/// if we fire from here the runtime of shoot
		int flyTime;
		///
		filterT filter;
		/// the time we have to fire at target
		unsigned int getFireTime() const { return updateTime+waitTime;}
	};
	/// one list per table entry
	struct tableLineS : public constArrayT<50,tableLineEntryS> {				
		///
		void removeOld(int time);
		/// here with key ?
		int  existsKey(unsigned int key) const { for (int i=0;i<count();i++) if (item(i).key==key) return 1;return 0;}
		/// here with given wait time
		int  existsFireTime(unsigned int time,int maxWait,filterT filter) const
		{
			for (int i=0;i<count();i++) 
			{ const tableLineEntryS & obj=item(i);
				if ((obj.filter & filter)==obj.filter && 
					  obj.getFireTime()+maxWait>=time)
				return i;
			}
			return -1;
		}
	};
	/// object list for a given time 
	unsigned int inputListTime;
	gameObjListC inputList;
	/// the complete table
	constArrayT<256*3,tableLineS> table;
	///
	const tableLineS & updateSlot(const vecIntC & pos,int headIdx,filterT filter);
	/// recursive callback ..
	void recursiveSolve(unsigned int time,const vecIntC & pos,int headIdx,int & bestSol,unsigned long long filter,hitListT & hitList);
public:
	/// ctor
	hitTableC();
	/** update table with data */
	void updateTable(unsigned int  time,const gameObjListC & _inputList) { inputListTime=time;inputList=_inputList;}
	/** request table data
	    time       is the time we want to look for			
	    headIdx    is the current "winkelByte" (i hate it)
			

			returns the list of targets at the given position at the given time
	*/
	void requestHit(unsigned int time,const vecIntC & pos,int headIdx,hitListT & hitList);
	/** return next hit direction from a give head in a given direction
	    including the current head !

			reqHead >0 go right
			reqHead <0 go left

			returns if we found a hit or not 
			returns in retHeadIdx the new head Index (no offset)
			returns the entry that fits to this hit
	*/
	int  requestNextHit(unsigned int time,const vecIntC & pos,int headIdx,int maxHeadChange,int maxWait,int reqHead,filterT useFilter,		
		int & retHeadIdx,const tableLineEntryS * & entry);				
	/// eval the optimum kill order
  void requestOptimalKills(unsigned int time,const vecIntC & pos,int headIdx,int reqHead,hitListT & hitList);
};





//////////////////////7
	/*
	{
		constArrayT<10,int> a;
		a.add(1);
		a.add(2);
		a.add(3);
		a.add(4);
		a.add(5);
		a.del(1);
		a.del(0);
	}
	{
		timeFrameC frame;
		long ret=frame.runTime();
		printLog("%d\n",ret);
	}
	
	// testWinkel();
	linelinetime();
	linelinetimint();
	*/

	//intersectTest();


	

	if (argc != 2)
	{
		fprintf(stderr, "Aufruf: astrobot <IP-Adresse>\n");
		exit(1);
	}



	keysPacketC key;
	sendKeys(key);


	framePacketC frame;
	gameStatusC  game;
	sandBoxC     sandbox;

	framePacketC frame1;
	gameStatusC  game1;
	sandBoxC     sandbox1;
	
	getFramebuffer(frame);	
	game.scanFrame(frame);	
	sandbox.update(game);


	planHitC plan;
top:
	{
		timeFrameC frame;
		getFramebuffer(frame1);	
		printLog("Frame = %4d\n",frame.runTime(1));
		game1.scanFrame(frame1);	
		printLog("Scan  = %4d\n",frame.runTime(1));
		sandbox1.update(game1);
		printLog("Sand  = %4d\n",frame.runTime(1));		
		plan.update(sandbox1.getTime(),sandbox1.getObjects());		
		plan.getOptimalKill(sandbox1.getTime(),vecIntC(512,512),0);
		printLog("Plan  = %4d\n",frame.runTime(1));
		
		/*
		int retHead1=0,retHead2=0;
		unsigned int retKey1,retKey2;
		filterT f1,f2;
		int found=hitTable.requestNextHit(sandbox1.getTime(),vecIntC(512,512),-10,86,10,1,(filterT)-1,retHead1,retKey1,f1);
		found|=hitTable.requestNextHit(sandbox1.getTime(),vecIntC(512,512),-10,86,10,-1,(filterT)-1,retHead2,retKey2,f2);
		*/
		

		

		/*
		if (found)
		{
			printLog("Frame =%5d|kill found %d %d\n",sandbox1.getTime(),retHead1,retHead2);
		}
		*/
	}
	// do some testing with line target hits ..
	
	if (0)
	{ // always take first item from list
		const gameObjListC & lst=sandbox1.getObjects();

		int anyHit=0;
		for (int i=0;i<lst.count();i++)
		{
			gameObjC & obj=lst[i];

			if (obj.getTrackCount()<5)
				continue;
			// hit zero and when ?
			
			vecDblC p0=obj.getP1();			
			vecDblC d0=obj.getDir();
			
			
			
			if (!game1.ship_present) printLog(".");
			/*
			else
				printLog("Ship %d %d\n",game1.ship_x,game1.ship_y);
			*/
			vecDblC h(game1.ship_present?game1.ship_x:524,game1.ship_present?game1.ship_y:524);
			
			
			// vecIntC h(0,0);
			

			int rad=gameObjProp[obj.getType()].radius+gameObjProp[objTypeShip].radius+2;;

			int resultCount=0;
			float resultArray[10];
			intersectWrapLinePoint(p0,d0,h,1000,rad,10,&resultCount,resultArray);

			for (int a=0;a<resultCount;a++)
			{ anyHit=1;
				vecDblC pos=obj.getPredictPos(obj.getT1()+resultArray[a]);	
				vecScreenPositionMap(pos);
				printLog("#%d->%d(%d,%d),",obj.getKey(),(int)resultArray[a],int(pos.x()),int(pos.y()));
				
			}			
		}
		if (anyHit)
			printLog("\n");
					
	}

	
	
	
goto top;

	/*
	

	
	int lx=0;
	int ly=0;
	float t=0;

	int lastFrame=0;
	for (;42;)
	{
		getFramebuffer(frame);
		scanFrame(frame,game);		

		if (frame.frameno==lastFrame)
			continue;
		lastFrame=frame.frameno;

		printLog("%d %d\n",game.asteroids[0].x,game.asteroids[0].y);

		if (lx==0)
		{
			lx=game.asteroids[0].x;
			ly=game.asteroids[0].y;
		}

		float d=sqrt(pow(float(game.asteroids[0].x-lx),2)+pow(float(game.asteroids[0].y-ly),2));
		float h=d/t;
		t++;
		printLog("%g,",h);
	}
	
*/
	return 0;


/*
int intersectWrapLineLineWaitFire(
			/// point for first and for second line				
			const vecDblC & p0,const vecDblC & d0,
			///
			const vecDblC & p1,const vecDblC & d1,			
			///
			float minDist,
			///
			float maxTime,
			/// per result item are two results !
			int maxResult,
			/// number of return results
			int * resultCount,
			/// return arry for the times ..
			float * resultArray
)
{
	// first we pick up the result from the intersection
	*resultCount=0;
	
	float maxDist=d0.len()*maxTime;

	float d0Len=d0.len();
	float d1Len=d1.len();

	vecDblC d1Normale=d1.norm(1).normale();
	vecDblC p1MovePos=d1Normale*minDist;
	vecDblC p1MoveNeg=d1Normale*-minDist;

	int localCount1;
	float localRes1[4];

	int localCount2;
	float localRes2[4];

	int res1=intersectWrapLineLineHit(p0,d0,p1+p1MovePos,d1,minDist,maxDist,2,&localCount1,localRes1);
	int res2=intersectWrapLineLineHit(p0,d0,p1-p1MovePos,d1,minDist,maxDist,2,&localCount2,localRes2);

	if (localCount1!=localCount2)
		return 0;

	for (int i=0;i<localCount1 && *resultCount<maxResult;i++)
	{

		// get values for flight which are factors for d0 and d1
		float a1=localRes1[i*2+0];
		float b1=localRes1[i*2+1];

		float a2=localRes2[i*2+0];
		float b2=localRes2[i*2+1];
		
		if (a1<0 && a2<0)
			continue;
		if (b1<0 && b2<0)
			continue;

		// if we hit in past move the intersection from a into zero and also reduce this time on b
		if (a1<0) { b1-=fabs(a1)*d0.len()/d1.len();a1=0.0;}
		if (a2<0) { b2-=fabs(a2)*d0.len()/d1.len();a2=0.0;}

		if (b1<0) { a1-=fabs(b1)*d1.len()/d0.len();b1=0.0;}
		if (b2<0) { a2-=fabs(b2)*d1.len()/d0.len();b2=0.0;}

		// sort the ranges to make it easier ..
		float minA,maxA;
		if (a1<a2) { minA=a1;maxA=a2;}		  
		else       { minA=a2;maxA=a1;}

		float minB,maxB;
		if (b1<b2) { minB=b1;maxB=b2;}		  
		else       { minB=b2;maxB=b1;}

		float off1;	
		float fire1;

		float off2;			
		float fire2;		
		
		// case 1 cant hit
		//   ----B----
		//               ----A----		
		if (maxB<minA)
			continue;
		
		// the early point
		off1 =b1-a1;
		fire1=a1;
		off2 =b2-a2;
		fire2=a2;

		if (off1<0)
		{
			fire1+=off1;
			off1=0;
		}

		if (off2<0)
		{
			fire2+=off2;
			off2=0;
		}

		if (fire1<0)
		{
			off1+=fire1;
			fire1=0;
		}

		if (fire2<0)
		{
			off2+=fire2;
			fire2=0;
		}
		
		// sort to smaller off first
		if (off2<off1)
		{
			float h1=off1;off1=off2;off2=h1;
			float h2=fire1;fire1=fire2;fire2=h2;
		}
	
		
		// here we have the result pair

		resultArray[(*resultCount)*4+0]=off1;
		resultArray[(*resultCount)*4+1]=fire1;

		resultArray[(*resultCount)*4+2]=off2;
		resultArray[(*resultCount)*4+3]=fire2;

		(*resultCount)++;
	}

	return *resultCount;

			 
}
*/

int intersectWrapLineLineWaitFire(
			/// point for first and for second line				
			const vecDblC & p0,const vecDblC & d0,
			///
			const vecDblC & p1,const vecDblC & d1,			
			///
			float minDist,
			///
			float maxTime,			
			/// return arry for the times ..
			intersectWrapLineLineWaitFireS * resultArray
)
{
	// first we pick up the result from the intersection
	

	// first the ultimate test if we hit our target direct ..
	// to do this we use again a transformation

	vecDblC transD=(d0-d1);
	float resultArrayDirect[10];
	int    resultCountDirect;
	int res0=intersectWrapLinePoint(p0,transD,p1,maxTime,minDist,1,&resultCountDirect,resultArrayDirect);

	int resCount=0;
	struct resPairS {
		float off,fly;
	};
	resPairS results[3];
		
	if (resultCountDirect)
	{
		float off=fabs((p1-p0).skalar(d0.normale()));

		float d0Len=d0.len();
		float d1Len=d1.len();
		// are they on one line ?
		if (off<1e-5)
		{
			

			float off1=resultArrayDirect[0];
			float off2=resultArrayDirect[1];
			// yes we are .. are we against to each other ?
			float side=d0.skalar(d1);
			// formular				
			if (side>0)
			{ // we fly behind each other and p0 is faster									
				resultArray[0].startWaitTime=0;
				resultArray[0].startFlyTime =off1;
				resultArray[0].endWaitTime=500*(d0Len-d1Len);
				resultArray[0].endFlyTime =off2+500*(d0Len-d1Len);
			}
			else
			{ // we fly head to head we can wait until he reach us
				resultArray[0].startWaitTime=0;
				resultArray[0].startFlyTime =off1;
				resultArray[0].endWaitTime=((p0-p1).len()-minDist)/(d1Len);
				resultArray[0].endFlyTime =0;
			}
			return 1;
		}	
		else
		{
			results[resCount].off=0;
			results[resCount].fly=resultArrayDirect[0];
			resCount++;
		}
	}

		
	// now get the missing data

	vecDblC d0Norm=d0.norm(1);
	vecDblC d0Normale=d0Norm.normale();
	vecDblC p0MovePos=d0Normale*minDist;
	vecDblC p0MoveNeg=d0Normale*-minDist;

	int localCount1;
	float localRes1[4];

	int localCount2;
	float localRes2[4];

	// get the other two results
	int res1=intersectWrapLineLineHit(p0+p0MovePos,d0,p1,d1,1,maxTime,1,&localCount1,localRes1);
	int res2=intersectWrapLineLineHit(p0-p0MovePos,d0,p1,d1,1,maxTime,1,&localCount2,localRes2);

	
	
	if (res1)
	{
		float a1,b1;
		a1=localRes1[0];
		b1=localRes1[1];

		if (a1<0 || b1<0 || b1<a1)
		{
		}
		else
		{
			results[resCount].off=b1-a1;
			results[resCount].fly=a1;
			resCount++;
		}

	}
	if (res2)
	{ float a2,b2;
		a2=localRes2[0];
		b2=localRes2[1];

		if (a2<0 || b2<0 || b2<a2)
		{
		}
		else
		{

			results[resCount].off=b2-a2;
			results[resCount].fly=a2;
			resCount++;
		}
	}

	if (resCount<2)
		return 0;

	// sort the list for the smallest b
	for (int i=0;i<resCount;i++)
		for (int a=i+1;a<resCount;a++)
		{
			if (results[a].off<results[i].off)
				swap(results[a],results[i]);
		}

	// the result is the first and last


	int l=resCount-1;
	

	resultArray[0].startWaitTime=results[0].off;
	resultArray[0].startFlyTime=results[0].fly;
	resultArray[0].endWaitTime=results[l].off;
	resultArray[0].endFlyTime=results[l].fly;		

	return 1;



	
/*



		

		// get values for flight which are factors for d0 and d1
		float a1=localRes1[i*2+0];
		float b1=localRes1[i*2+1];

		if (a1<0 || b1<0)
			continue;

		if (b1<a1)
		{ 
			if (!resultCountDirect)
				continue;
			b1=directOff1;
		  a1=directOff1;
		}
						
		float a2=localRes2[i*2+0];
		float b2=localRes2[i*2+1];
		
		if (a2<0 || b2<0)
			continue;

		if (b2<a2)
		{
			if (!resultCountDirect)
				continue;
			b2=directOff1;
		  a2=directOff1;
		}
				
		if (b2<b1)
		{
			swap(b1,b2);
			swap(a1,a2);
		}

		
		float off1=b1-a1;
		float fire1=a1;
		float off2=b2-a2;
		float fire2=a2;


		resultArray[0].startWaitTime=off1;
		resultArray[0].startFlyTime=fire1;
		resultArray[0].endWaitTime=off2;
		resultArray[0].endFlyTime=fire2;		
		found++;




	}

	*/
	return 0;
}	


int intersectWrapLineLineWaitFire(
			/// point for first and for second line				
			const vecDblC & p0,const vecDblC & d0,
			///
			const vecDblC & p1,const vecDblC & d1,			
			///
			float minDist,
			///
			float maxTime,			
			/// return arry for the times ..
			intersectWrapLineLineWaitFireS * resultArray
)
{
	/// the idee .. use again the transoformation to have only one moving target 
	
	int    localCount;
	float localRes[2];


	vecDblC d1Norm=d1.norm(1);
	
	vecDblC transD=(d0-d1);
	vecDblC transDNorm=transD.norm(1);
	vecDblC transDNormale=transDNorm.normale();

	float wi=acos(d1.skalar(d0)/(d1.len()*d0.len()));	
	float correctBOffset;
	float correctAOffset;
	if (fabs(wi-PI/2.0)>1e-8)
	{
		float ah=minDist*tan(wi);
		float ab=sqrt(ah*ah+minDist*minDist);
		correctBOffset=ab/d1.len();
		correctAOffset=sqrt(ab*ab-minDist*minDist)/d0.len();
	}
	else
	{
		correctAOffset=0.0;
		correctBOffset=minDist/d1.len();


	}

	struct resPairS {
		float aTime;
		float bTime;
	};

	float timeForRad=minDist/d1.len();
		
	
	// maximal 3 results
	resPairS results[3];
	int      resultCount=0;
	// create the two lines to intersect with our transformed head
	float resultArrayDirect[10];
	int    resultCountDirect;

	int res=intersectWrapLineLineHit(p0,d0,p1,d1,minDist,maxTime,1,&resultCountDirect,resultArrayDirect);
	if (!res)
		return 0;
	// now we have the timings for the hit point 
	// a is me and b is target
	float a=resultArrayDirect[0];
	float b=resultArrayDirect[1];
	
	// off if the time diff (means how long can i wait for b if i want to hit the middle)

	float minATime=a-correctAOffset;
	float maxATime=a+correctAOffset;
	float minBTime=b-correctBOffset;
	float maxBTime=b+correctBOffset;
	
	// we are against each other .. 	
	float waitAStart,waitAEnd,flyAStart,flyAEnd;
	if (d1.skalar(d0)<0)
	{

		waitAStart=minBTime-maxATime;
		waitAEnd =maxBTime-minATime;

		if (waitAStart<0 && waitAEnd<0)
			return 0;

		if (waitAStart<0)
		{ waitAStart=0.0;
		  intersectWrapLinePoint(p0,transD,p1,maxTime,minDist,1,&resultCountDirect,resultArrayDirect);
			flyAStart=resultArrayDirect[0];
		}
		else
			flyAStart=maxATime;		
		
		flyAEnd  =minATime;
	}
	else
	{
		waitAStart=minBTime-minATime;
		waitAEnd =maxBTime-maxATime;

		if (waitAStart<0 && waitAEnd<0)
			return 0;
		
		if (waitAStart<0)
		{ waitAStart=0.0;
		  intersectWrapLinePoint(p0,transD,p1,maxTime,minDist,1,&resultCountDirect,resultArrayDirect);
			flyAStart=resultArrayDirect[0];
		}
		else
			flyAStart=minATime;
		
		flyAEnd  =maxATime;
	}
	

	
	

	
	resultArray[0].startWaitTime=waitAStart;
	resultArray[0].startFlyTime=flyAStart;
	resultArray[0].endWaitTime=waitAEnd;
	resultArray[0].endFlyTime=flyAEnd;		
	return 1;
		


}	



int intersectWrapLineLineWaitFire(
			/// point for first and for second line				
			const vecDblC & p0,const vecDblC & d0,
			///
			const vecDblC & p1,const vecDblC & d1,			
			///
			float minDist,
			///
			float maxTime,			
			/// return arry for the times ..
			intersectWrapLineLineWaitFireS * resultArray
)
{
	/// the idee .. use again the transoformation to have only one moving target 
	
	int    localCount;
	float localRes[2];


	vecDblC d1Norm=d1.norm(1);
	
	vecDblC transD=(d0-d1);
	vecDblC transDNorm=transD.norm(1);
	vecDblC transDNormale=transDNorm.normale();

	float wi=acos(d1.skalar(d0)/(d1.len()*d0.len()));	
	float correctBOffset;
	float correctAOffset;
	if (fabs(wi-PI/2.0)>1e-8)
	{
		float ah=minDist*tan(wi);
		float ab=sqrt(ah*ah+minDist*minDist);
		correctBOffset=ab;
		correctAOffset=sqrt(ab*ab-minDist*minDist)/d0.len();
	}
	else
	{
		correctAOffset=0.0;
		correctBOffset=minDist;


	}

	// this values we need at the end
	float waitAStart,waitAEnd,flyAStart,flyAEnd;
	
	// create the two lines to intersect with our transformed head
	float resultArrayDirect[2];
	int    resultCountDirect;
	int    res;

	int ok=0;

	// first side
	res=intersectWrapLineLineHit(p0,d0,p1-d1.normale().norm(minDist),d1,minDist,maxTime,1,&resultCountDirect,resultArrayDirect);
	if (!res)
	{
		intersectWrapLinePoint(p0,transD,p1,maxTime,minDist,1,&resultCountDirect,resultArrayDirect);
		waitAStart=0.0;
		flyAStart =resultArrayDirect[0];
		ok++;
	}
	else
	{
		float a=resultArrayDirect[0];
		float b=resultArrayDirect[1];

		if (d1.skalar(d0)<0)
			a+=correctAOffset;
		else
			a-=correctAOffset;

		waitAStart=b-a;
		flyAStart=a;
		
		if (waitAStart>=0)
			ok++;
	}
	// second side
	res=intersectWrapLineLineHit(p0,d0,p1+d1.normale().norm(minDist),d1,minDist,maxTime,1,&resultCountDirect,resultArrayDirect);
	if (!res)
	{
		intersectWrapLinePoint(p0+d1.norm(correctBOffset),transD,p1,maxTime,minDist,1,&resultCountDirect,resultArrayDirect);
		waitAEnd=0.0;
		flyAEnd=resultArrayDirect[0];
		ok++;
	}
	else
	{
		float a=resultArrayDirect[0];
		float b=resultArrayDirect[1];
		// attantion we have here a other sign
		if (d1.skalar(d0)>0)
			a+=correctAOffset;
		else
			a-=correctAOffset;

		waitAEnd=b-a;
		flyAEnd=a;
		
		if (waitAEnd>=0)
			ok++;
	}

	if (ok!=2)
		return 0;

	if (waitAEnd<waitAStart)
	{
		swap(waitAEnd,waitAStart);
		swap(flyAEnd,flyAStart);
	}



	
	resultArray[0].startWaitTime=waitAStart;
	resultArray[0].startFlyTime=flyAStart;
	resultArray[0].endWaitTime=waitAEnd;
	resultArray[0].endFlyTime=flyAEnd;		
	return 1;
		


}	


void planHitC::recursiveSolve(unsigned int time0,unsigned int time,const vecIntC & pos,int head,const constArrayT<32,int> & workIds,unsigned int & bestTime,int & bestLen,constArrayT<10,recursiveResultS> & firePositions)
{
	/*
	// is the list empty .. we are done
	// if we look complete around done
	// if we work at least 5 objects .. done

	if (firePositions.count())
	{
		int cond1=firePositions.count()>=bestLen;
		int cond2=(time-time0)>256*3;
		int cond3=this->objects.count()-workIds.count()>5;
		if (cond1 || cond2 || cond3)
		{
			// if we have a longer path or time is better
			if (firePositions.count()>bestLen || (firePositions.count()==bestLen && time<bestTime))		
			{ bestTime=time;
				bestLen=firePositions.count();			
				recursiveFirePositions=firePositions;
			}
			
			if (cond2 || cond3 || workIds.count()==0)
				return;
		}
	}
	
	// we come to the limit
	if (time>bestTime)
		return;

	if (firePositions.count()>1)
		return;
		
	// if (workIds.count()<=5)
	{
		for (int i=0;i<workIds.count();i++)
		{		
			int retHead;
			unsigned int retFireTime;
			unsigned int retFlyTime;

			int id=workIds[i];

			if (objects[id].getFiredTimeDiff()<4)
				continue;

			if (objects[id].requestNextHit(time,pos,head,86/2,retHead,retFireTime,retFlyTime))
			{				
				constArrayT<32,int> local=workIds;
				constArrayT<10,recursiveResultS> localFire=firePositions;
				localFire.add(recursiveResultS(retHead,retFireTime,id));
				local.del(i);
				recursiveSolve(time0,retFireTime,pos,retHead,local,bestTime,bestLen,localFire);				
			}
		}		
	}
	/*
	else // there are more itmes in que than we can work with ..
	{
		
		constArrayT<32,sortHelperS> topList;

		sortHelperS hlp;

		// extract the top items ..
		for (int i=0;i<workIds.count();i++)
		{
			int retHead;
			unsigned int retFireTime;
			unsigned int retFlyTime;

			int id=workIds[i];

			if (objects[id].requestNextHit(time,pos,head,86,retHead,retFireTime,retFlyTime))
			{				
				
				hlp.id=i;
				hlp.fireTime=retFireTime;

				topList.add(hlp);								
			}		
		}
		
		shellSort(topList,topList.count(),sortCompS(),hlp);

		int limit=topList.count()>5?5:topList.count();
		
		// now take the top items ..

		for (int i=0;i<limit;i++)
		{		
			int retHead;
			unsigned int retFireTime;
			unsigned int retFlyTime;

			int id=workIds[topList[i].id];

			if (objects[id].requestNextHit(time,pos,head,86,retHead,retFireTime,retFlyTime))
			{
				constArrayT<32,int> local=workIds;
				local.del(topList[i].id);
				recursiveSolve(time0,retFireTime,pos,retHead,local,bestTime);
			}
		}		

	}
	*/
}

/// recursive result information
	struct recursiveResultS {
		int					 fireHead;
		unsigned int fireTime;
		int						listPos;
		/// ctor
		recursiveResultS(int head,unsigned int time,int _listPos) { fireHead=head;fireTime=time;listPos=_listPos;}
		recursiveResultS() { };
	};
	
	struct densityFieldDataS : public intersectWrapLineLineWaitFireS {
	/// ctor
	densityFieldDataS() {hitCount=0;head=0;}
	///
	int head;
	/// number of found hits ..
	int hitCount;
	///
	void sum(int h,const intersectWrapLineLineWaitFireS & sec)
	{ hitCount++;
	  head+=h;
		intersectWrapLineLineWaitFireS::sum(sec);
	}
	///
	void div()
	{	if (!hitCount)
	    return;
		head/=hitCount;
		intersectWrapLineLineWaitFireS::div(hitCount);		
	}
	///
	float density(int base) const 
	{
		if (!hitCount)
			return 0.0;
		return float(hitCount)/float(endWaitTime-startWaitTime+abs(getHeadDiff(base,head)));
	}
	/// comp class
	struct compS {
		/// stored time
		unsigned int time;
		/// stored basedhead
		int baseHead;
		/// ctor

		compS(unsigned int t,int bHead) { time=t;this->baseHead=bHead;}
		
		int greater(const densityFieldDataS & first,const densityFieldDataS & sec)	const
		{ // we calc hits per time
			//return first.density(time)+abs(getHeadDiff(baseHead,first.head))<sec.density(time)+abs(getHeadDiff(baseHead,sec.head));
			return first.density(baseHead)<sec.density(baseHead);
		}
	};

};

int planHitC::calcDensityField(const searchOptionS & option,unsigned int time,workListT & workIds,int & retHead,unsigned int & retFireTime)
{
	// idee calc the position with the highest hit concentration

	// we calc from here the next +86 and -86 values 
	constArrayT<MAX_ANGLE/8,densityFieldDataS> fieldData;
	fieldData.resize(MAX_ANGLE/8);

	int baseHead=spaceShip.getRotationIndex();
								
	for (int i=0;i<workIds.count();i++)
	{
		int id=workIds[i];
		
		for (int head=-86;head<86;head++)
		{
			int currentHead=getHeadIdx(baseHead+head);

			intersectWrapLineLineWaitFireS currentData;
			if (objects[id].requestHitData(option,spaceShip.getPosition(),currentHead,currentData))
			{ 													
				
				if (objects[id].getObj().getType()==objTypeAstroidLarge || objects[id].getObj().getType()==objTypeAstroidMed)
					fieldData[currentHead/8].sum(currentHead,currentData);					
				
				fieldData[currentHead/8].sum(currentHead,currentData);
				// go to next head to avoid double count obejct in this sector
				head+=abs(head) % 8;
			}
		}		
	}
	
	
	// calc medium
	{
		for (int i=0;i<fieldData.count();i++)
			fieldData[i].div();
	}
	// at this point the density field is ready .. now we have to make a decision up from the data ..
	
	densityFieldDataS tmp;
	shellSort(fieldData,fieldData.count(),densityFieldDataS::compS(time,baseHead),tmp);
	// now see which is reachable
	for (int i=0;i<fieldData.count();i++)
	{
		int diffHead=abs(getHeadDiff(baseHead,fieldData[i].head));

		if (time+diffHead<(fieldData[i].startWaitTime+fieldData[i].endWaitTime)/2 && time+diffHead>=fieldData[i].startWaitTime)
		{			
			// we found a candiate ..
			retHead    =fieldData[i].head;
			retFireTime=fieldData[i].startWaitTime;
			// use ship to get there..
			printLog("denisty at %d hits %d time %d alternate %d\n",retHead,fieldData[i].hitCount,abs(diffHead),i);
			
			return 1;
		}
	}

	return 0;
}

int planHitC::getOptimalKill(unsigned int time,int & headChange,unsigned int & fireTime,int & panic)
{
	fireTime=0;
	headChange=0;
	panic=0;
					
	if (objects.count()==0)
	{ panic=testPanic(time);
		return 0;
	}

	searchOptionS option;
	option.waitShotTime=shotOffsetTime;
	/*
	// see that happens with our target
	if (currentTarget.key!=0 && shotOffsetTime==0)
	{
		if (time==currentTarget.fireTime && spaceShip.getRotationIndex()==currentTarget.fireHead)
		{
			// just see if the data is still what we need
			int pos=getObjectByKey(currentTarget.key);
			if (pos!=-1)
			{
				unsigned int retFireTime,retFlyTime;
				if (objects[pos].requestNowHit(option,time,spaceShip.getPosition(),currentTarget.fireHead,retFireTime,retFlyTime))
				{
					// ok we will hit it now .. setup all data for this object
					fireTime=retFireTime+retFlyTime;
					// because this works so good we mark this object and the methode can go to the next ..
					spaceShip.incShot(retFireTime,fireTime,currentTarget.key);
					objects[pos].setFire(retFireTime);
					// adapted next shot offset time
					shotOffsetTime=spaceShip.nextFireTime(time)-time;					
					option.waitShotTime=shotOffsetTime;

					printLog("Frame %4d|Exec Fire|Keys=%d Fire=%d\n",time,currentTarget.key,fireTime);
				}
			}
		}
	}
	*/
	
	

	

	// we will calculate this now ..
	currentTarget.reset();
	
	// unsigned int retWaitTime,retFlyTime;
	// int retHead;

	workListT workList,workListFull;

	

	getNextKiller(time,workList);
	addUfo(time,workList);

	int special=workList.count();

		
	{
		for (int i=0;i<objects.count();i++)
		{
			// we just fire to object dont do it again .. later the object will be marked with the tx code
			if (objects[i].getFiredTimeDiff()<8)
					continue;				

			
			
			const gameObjC & obj=objects[i].getObj();

			
			
			/*
			// this code will avoid hits on objects that can not more split
			// maximal possible are	 26 if we kill one we need two places. We take 24 .. 25 would be critital
			if (astroBigFound>=24 && astroSmallFound>0 && // is the array full ?
					(obj.getType()==objTypeAstroidMed || obj.getType()==objTypeAstroidLarge))
			{   printf("*");
					continue;
			}
			
			// we dont hit the limit .. but if we have more than 24 we should avoid to hit large asteroids
			if (astroBigFound>=24 && obj.getType()==objTypeAstroidLarge)
			{   printf("*");
					continue;
			}
			*/
			
			
			
			
						
			// we accepted the item up to this point .. see if we really should ..

			
			workListFull.add(i);
			
		}
	}

	
	if (workList.count()==0)	
		workList=workListFull;

	unsigned int bestTime=-1;
	int          bestHead=0;
	unsigned int bestFly=0;
	int          listPos=-1;
							
	if (workList.count()>4)
	{		
		// try density field
		option.method=searchMinHitTime;
		
		unsigned int targetFireTime=TIME_INFINITE;		

		int dir=0;
		
	
		/*
		if (this->calcDensityField(option,time,workList,dir))
		{			
			
		}
		*/
		
		
		getNextTarget(option,time,spaceShip.getPosition(),spaceShip.getRotationIndex(),dir,workList,TIME_INFINITE,0,listPos,bestTime,bestFly,bestHead);								
		/*
		// try a inlay shot ..
		option.method=searchMinFireTime;
		// create a sub list for targets ..
		getNextTarget(option,time,spaceShip.getPosition(),spaceShip.getRotationIndex(),dir,workListFull,bestTime,bestHead,listPos,bestTime,bestFly,bestHead);
		*/
		
		

	}
	else
	{
		
		unsigned int bestCallTime=TIME_INFINITE;
		recursiveFirePositionsT firePositions;
				
		unsigned int maxTime=TIME_INFINITE;//nextModelChange;
	
		recursiveFirePositions.clear();
		/*
		if (special)
			option.method=searchMinFireTime;
		else
			option.method=searchMinHitTime;
		*/

		option.method=searchMinFireTime;
		
		optNFull(option,maxTime,time,spaceShip,workList,bestCallTime,firePositions);
		/*
		option.method=searchMinHitTime;
		recursiveFirePositions.clear();
		optNFull(option,maxTime,time,spaceShip,workList,bestCallTime,firePositions);

		recursiveFirePositions.clear();
		optN2Full(option,maxTime,time,spaceShip,workList,bestCallTime,firePositions);
		*/
						
		// if we are done we get the result in local structure
		if (recursiveFirePositions.count())
		{
			// printf("*");
			bestTime   =recursiveFirePositions[0].fireTime;
			bestFly    =recursiveFirePositions[0].flyTime;
			bestHead   =recursiveFirePositions[0].head;
			listPos    =recursiveFirePositions[0].listId;
			// that good until now but we may get some targes inbetween			
			printLog("next full n target -> %d %d %d %d\n",objects[listPos].getKey(),bestTime,bestHead,bestFly);

			option.method=searchMinHitTime;
			// create a sub list for targets ..
			if (getNextTarget(option,time,spaceShip.getPosition(),spaceShip.getRotationIndex(),0,workListFull,bestTime,bestHead,listPos,bestTime,bestFly,bestHead))
			{
				
			}

			
			
		}
		else
		{ // printf(".");
			option.method=searchMinHitTime;
			if (getNextTarget(option,time,spaceShip.getPosition(),spaceShip.getRotationIndex(),0,workList,TIME_INFINITE,0,listPos,bestTime,bestFly,bestHead))
			{
				
			}
		}
	}

	if (bestTime==-1)
	{
		// nothing to do
		if (testPanic(time))
			panic=1;
		return 0;
	}

	if (bestTime-time<0)
	{
		fatalError("neg time");
	}
	

	int headDiff=getHeadDiff(spaceShip.getRotationIndex(),bestHead);
	
	headChange=headDiff!=0?(headDiff>0?1:-1):0;	

	if (headDiff==0 && bestTime==time)
		fireTime=bestTime+bestFly;

	if (this->shotOffsetTime==0 && !fireTime && (!special))
	{
		unsigned int retFireTime,retFlyTime;
		int      retListPos;
		if (this->inFireLine(option,time,workListFull,retListPos,retFireTime,retFlyTime))
		{
			// it is possible to fire here .. are we able to hit the original goal also ?
			spaceShip.incShot(time,retFireTime+retFlyTime,objects[retListPos].getKey());
			unsigned int nextTime=spaceShip.nextFireTime(time);
			if (nextTime<=bestTime)
			{
				bestTime=retFireTime;
				bestHead=spaceShip.getRotationIndex();
				bestFly=retFlyTime;
				fireTime=bestTime+bestFly;
				listPos=retListPos;
				// printf(".");
				
				if (retFireTime!=time)
					fatalError("wrong state");					
			}

		}
	}



	
	printLog("Frame %4d|Keys=%d Fire=%d\n",time,headChange,fireTime);
	
	if (bestTime==time && headDiff==0 && listPos>=0)
	{ 				
		objects[listPos].setFire(time);
	}
	else if (listPos>=0)
	{
	  // we do not fire this round .. so target keeps for us
		currentTarget.key=objects[listPos].getKey();
		currentTarget.fireHead=bestHead;
		currentTarget.fireTime=bestTime;
		currentTarget.flyTime=bestFly;
	}

	if (testPanic(time))
    panic=1;
	return 1;
}

int planHitC::getOptimalKill(unsigned int time,int & headChange,unsigned int & fireTime,int & panic)
{
	fireTime=0;
	headChange=0;
	panic=0;
					
	if (objects.count()==0)
	{ panic=testPanic(time);
		return 0;
	}

	searchOptionS option;
	option.waitShotTime=shotOffsetTime;

	// see that happens with our target
	if (currentTarget.key!=0 && shotOffsetTime==0)
	{
		if (time==currentTarget.fireTime && spaceShip.getRotationIndex()==currentTarget.fireHead)
		{
			// just see if the data is still what we need
			int pos=getObjectByKey(currentTarget.key);
			if (pos!=-1)
			{
				unsigned int retFireTime,retFlyTime;
				if (objects[pos].requestNowHit(option,time,spaceShip.getPosition(),currentTarget.fireHead,retFireTime,retFlyTime))
				{
					// ok we will hit it now .. setup all data for this object
					fireTime=retFireTime+retFlyTime;
					// because this works so good we mark this object and the methode can go to the next ..
					spaceShip.incShot(retFireTime,fireTime,currentTarget.key);
					objects[pos].setFire(retFireTime);
					// adapted next shot offset time
					shotOffsetTime=spaceShip.nextFireTime(time)-time;					
					option.waitShotTime=shotOffsetTime;
				}
			}
		}
	}

	

	// we will calculate this now ..
	currentTarget.reset();
	
	// unsigned int retWaitTime,retFlyTime;
	// int retHead;

	workListT workList,workListFull;

	

	getNextKiller(time,workList);
	addUfo(time,workList);

	int special=workList.count();

		
	{
		for (int i=0;i<objects.count();i++)
		{
			// we just fire to object dont do it again .. later the object will be marked with the tx code
			if (objects[i].getFiredTimeDiff()<8)
					continue;				

			
			
			const gameObjC & obj=objects[i].getObj();

			
			
			/*
			// this code will avoid hits on objects that can not more split
			// maximal possible are	 26 if we kill one we need two places. We take 24 .. 25 would be critital
			if (astroBigFound>=24 && astroSmallFound>0 && // is the array full ?
					(obj.getType()==objTypeAstroidMed || obj.getType()==objTypeAstroidLarge))
			{   printf("*");
					continue;
			}
			
			// we dont hit the limit .. but if we have more than 24 we should avoid to hit large asteroids
			if (astroBigFound>=24 && obj.getType()==objTypeAstroidLarge)
			{   printf("*");
					continue;
			}
			*/
			
			
			
			
						
			// we accepted the item up to this point .. see if we really should ..

			
			workListFull.add(i);
			
		}
	}

	
	if (workList.count()==0)	
		workList=workListFull;

	unsigned int bestTime=-1;
	int          bestHead=0;
	unsigned int bestFly=0;
	int          listPos=-1;
							
	if (workList.count()>5)
	{		
		// try density field
		option.method=searchMinHitTime;

		int targetHead=0;
		unsigned int targetFireTime=TIME_INFINITE;		

		int dir=0;
		
		
		if (this->calcDensityField(option,time,workList,dir))
		{			
			
		}
		
		
		getNextTarget(option,time,spaceShip.getPosition(),spaceShip.getRotationIndex(),dir,workList,TIME_INFINITE,0,listPos,bestTime,bestFly,bestHead);								
		/*
		// try a inlay shot ..
		option.method=searchMinFireTime;
		// create a sub list for targets ..
		getNextTarget(option,time,spaceShip.getPosition(),spaceShip.getRotationIndex(),dir,workListFull,bestTime,bestHead,listPos,bestTime,bestFly,bestHead);
		*/
		
		

	}
	else
	{
		
		unsigned int bestCallTime=TIME_INFINITE;
		recursiveFirePositionsT firePositions;
				
		unsigned int maxTime=TIME_INFINITE;//nextModelChange;
	
		recursiveFirePositions.clear();

		if (special)
			option.method=searchMinFireTime;
		else
			option.method=searchMinHitTime;
		
		optNFull(option,maxTime,time,spaceShip,workList,bestCallTime,firePositions);
		/*
		option.method=searchMinHitTime;
		recursiveFirePositions.clear();
		optNFull(option,maxTime,time,spaceShip,workList,bestCallTime,firePositions);

		recursiveFirePositions.clear();
		optN2Full(option,maxTime,time,spaceShip,workList,bestCallTime,firePositions);
		*/
						
		// if we are done we get the result in local structure
		if (recursiveFirePositions.count())
		{
			// printf("*");
			bestTime   =recursiveFirePositions[0].fireTime;
			bestFly    =recursiveFirePositions[0].flyTime;
			bestHead   =recursiveFirePositions[0].head;
			listPos    =recursiveFirePositions[0].listId;
			// that good until now but we may get some targes inbetween			
			printLog("next full n target -> %d %d %d %d\n",objects[listPos].getKey(),bestTime,bestHead,bestFly);

			option.method=searchMinHitTime;
			// create a sub list for targets ..
			if (getNextTarget(option,time,spaceShip.getPosition(),spaceShip.getRotationIndex(),0,workListFull,bestTime,bestHead,listPos,bestTime,bestFly,bestHead))
			{
				
			}

			
			
		}
		else
		{ // printf(".");
			option.method=searchMinHitTime;
			if (getNextTarget(option,time,spaceShip.getPosition(),spaceShip.getRotationIndex(),0,workList,TIME_INFINITE,0,listPos,bestTime,bestFly,bestHead))
			{
				
			}
		}
	}

	if (bestTime==-1)
	{
		// nothing to do
		if (testPanic(time))
			panic=1;
		return 0;
	}

	if (bestTime-time<0)
	{
		fatalError("neg time");
	}
	

	int headDiff=getHeadDiff(spaceShip.getRotationIndex(),bestHead);
	
	headChange=headDiff!=0?(headDiff>0?1:-1):0;	

	if (headDiff==0 && bestTime==time)
		fireTime=bestTime+bestFly;

	if (this->shotOffsetTime==0 && !fireTime && (!special))
	{
		unsigned int retFireTime,retFlyTime;
		int      retListPos;
		if (this->inFireLine(option,time,workListFull,retListPos,retFireTime,retFlyTime))
		{
			// it is possible to fire here .. are we able to hit the original goal also ?
			spaceShip.incShot(time,retFireTime+retFlyTime,objects[retListPos].getKey());
			unsigned int nextTime=spaceShip.nextFireTime(time);
			if (nextTime<=bestTime)
			{
				bestTime=retFireTime;
				bestHead=spaceShip.getRotationIndex();
				bestFly=retFlyTime;
				fireTime=bestTime+bestFly;
				listPos=retListPos;
				// printf(".");
				
				if (retFireTime!=time)
					headChange=0;
			}

		}
	}



	
	printLog("Frame %4d|Keys=%d Fire=%d\n",time,headChange,fireTime);
	
	if (bestTime==time && headDiff==0 && listPos>=0)
	{ 				
		objects[listPos].setFire(time);
	}
	else if (listPos>=0)
	{
	  // we do not fire this round .. so target keeps for us
		currentTarget.key=objects[listPos].getKey();
		currentTarget.fireHead=bestHead;
		currentTarget.fireTime=bestTime;
		currentTarget.flyTime=bestFly;
	}

	if (testPanic(time))
    panic=1;
	return 1;
}