Exemple #1
0
EResults RunEncounter (CUniverse &Universe, CSimViewer &Viewer, CStationType *pDefenderType, CShipClass *pAttackerClass, CSovereign *pAttackerSovereign)
	{
	int iTimeOut = DEFAULT_TIME_OUT;

	//	Make sure the universe is clean

	CString sError;
	if (Universe.InitGame(0, &sError) != NOERROR)
		{
		printf("ERROR: %s", sError.GetASCIIZPointer());
		return resultError;
		}

	//	Create an empty system

	CSystem *pSystem;
	if (Universe.CreateEmptyStarSystem(&pSystem) != NOERROR)
		{
		printf("ERROR: Unable to create empty star system.\n");
		return resultError;
		}

	//	Create a station in the center of the system

	CSpaceObject *pStation;
	if (pSystem->CreateStation(pDefenderType, NULL, CVector(), &pStation) != NOERROR)
		{
		printf("ERROR: Unable to create station.\n");
		return resultError;
		}

	//	Set the POV

	Universe.SetPOV(pStation);
	pSystem->SetPOVLRS(pStation);

	//	Prepare system

	Universe.UpdateExtended();
	Universe.GarbageCollectLibraryBitmaps();
	Universe.StartGame(true);

	//	Now create an attacker some distance away

	CVector vPos = PolarToVector(mathRandom(0, 359), INITIAL_DISTANCE);

	CShip *pAttacker;
	if (pSystem->CreateShip(pAttackerClass->GetUNID(), NULL, NULL, pAttackerSovereign, vPos, CVector(), 0, NULL, NULL, &pAttacker) != NOERROR)
		{
		printf("ERROR: Unable to create attacking ship.\n");
		return resultError;
		}

	//	Set the attacker to attack the station

	IShipController *pController = pAttacker->GetController();
	if (pController == NULL)
		{
		printf("ERROR: No controller for ship.\n");
		return resultError;
		}

	pController->AddOrder(IShipController::orderAttackStation, pStation, IShipController::SData());

	//	Watch the attacker

	Universe.SetPOV(pAttacker);
	pSystem->SetPOVLRS(pAttacker);

	//	Update context

	SSystemUpdateCtx Ctx;
	Ctx.bForceEventFiring = true;
	Ctx.bForcePainted = true;

	//	Now keep updating until either the station is destroyed, the ship is destroyed, or we time-out

	int iTime = 0;
	int iDestroyedTime = (Viewer.IsEmpty() ? 0 : DESTROY_TIME);
	bool bDestroyed = false;
	EResults iResult = resultTimeout;
	while (iTime < iTimeOut && (!bDestroyed || iDestroyedTime > 0))
		{
		iTime++;
		Universe.Update(Ctx);

		if (!Viewer.IsEmpty())
			Viewer.PaintViewport(Universe);

		if (bDestroyed)
			iDestroyedTime--;
		else if (pStation->IsDestroyed() || pStation->IsAbandoned())
			{
			bDestroyed = true;
			iResult = resultDefenderDestroyed;
			}
		else if (pAttacker->IsDestroyed())
			{
			bDestroyed = true;
			iResult = resultAttackerDestroyed;
			}
		}

	//	Done

	return iResult;
	}
void GenerateEncounterCount (CUniverse &Universe, CXMLElement *pCmdLine)
	{
	int i, j, k, l;

	//	Options

	int iSystemSample = pCmdLine->GetAttributeIntegerBounded(CONSTLIT("count"), 1, -1, 1);
	bool bLogo = !pCmdLine->GetAttributeBool(CONSTLIT("noLogo"));
	bool bAll = pCmdLine->GetAttributeBool(CONSTLIT("all"));

	//	Additional columns

	TArray<CString> Cols;
	for (i = 0; i < pCmdLine->GetAttributeCount(); i++)
		{
		CString sAttrib = pCmdLine->GetAttributeName(i);

		if (!IsMainCommandParam(sAttrib)
				&& !strEquals(sAttrib, CONSTLIT("count"))
				&& !strEquals(sAttrib, CONSTLIT("encountercount")))
			{
			CString sValue = pCmdLine->GetAttribute(i);
			
			if (!strEquals(sValue, CONSTLIT("true")))
				Cols.Insert(strPatternSubst(CONSTLIT("%s:%s"), sAttrib, sValue));
			else
				Cols.Insert(sAttrib);
			}
		}

	//	Generate systems for multiple games

	TSortMap<CString, SNodeDesc> NodeTable;

	for (i = 0; i < iSystemSample; i++)
		{
		if (bLogo)
			printf("pass %d...\n", i+1);

		//	Initialize the game

		CString sError;
		if (Universe.InitGame(0, &sError) != NOERROR)
			{
			printf("%s\n", sError.GetASCIIZPointer());
			return;
			}

		for (j = 0; j < Universe.GetTopologyNodeCount(); j++)
			{
			CTopologyNode *pNode = Universe.GetTopologyNode(j);
			if (pNode->IsEndGame())
				continue;

			//	Create the system

			CSystem *pSystem;
			if (Universe.CreateStarSystem(pNode, &pSystem) != NOERROR)
				{
				printf("ERROR: Unable to create star system.\n");
				return;
				}

			//	Create a sort string for this system

			CString sSort = strPatternSubst(CONSTLIT("%02d-%s"), pSystem->GetLevel(), pNode->GetID());

			//	Get the table

			bool bNew;
			SNodeDesc *pResult = NodeTable.SetAt(sSort, &bNew);
			if (bNew)
				{
				pResult->iLevel = pNode->GetLevel();
				pResult->sNodeID = pNode->GetID();
				}

			//	Accumulate data

			AddSystemData(pSystem, bAll, pResult);

			//	Done with old system

			Universe.DestroySystem(pSystem);
			}

		Universe.Reinit();
		}

	//	Header

	printf("Level\tNode\tSystemType\tCategory\tSovereign\tEncounter\tCount");
	for (i = 0; i < Cols.GetCount(); i++)
		printf("\t%s", Cols[i].GetASCIIZPointer());
	printf("\n");

	//	Output all rows

	for (i = 0; i < NodeTable.GetCount(); i++)
		{
		for (j = 0; j < NodeTable[i].Table.GetCount(); j++)
			{
			CCountTable &Encounters = NodeTable[i].Table[j];

			for (k = 0; k < Encounters.GetCount(); k++)
				{
				int iCount = Encounters[k] / iSystemSample;
				int iCountFrac = 1000 * (Encounters[k] % iSystemSample) / iSystemSample;
				CStationType *pEncounterType = Universe.FindStationType(Encounters.GetKey(k));
				if (pEncounterType == NULL)
					continue;

				CSovereign *pSovereign = pEncounterType->GetControllingSovereign();
				CString sSovereign = (pSovereign ? pSovereign->GetTypeName() : CONSTLIT("(Unknown)"));

				printf("%d\t%s\t0x%08x\t%s\t%s\t%s\t%d.%03d",
						NodeTable[i].iLevel,
						NodeTable[i].sNodeID.GetASCIIZPointer(),
						NodeTable[i].Table.GetKey(j),
						pEncounterType->GetDataField(CONSTLIT("category")).GetASCIIZPointer(),
						sSovereign.GetASCIIZPointer(),
						pEncounterType->GetName().GetASCIIZPointer(),
						iCount,
						iCountFrac);

				for (l = 0; l < Cols.GetCount(); l++)
					{
					CString sValue = pEncounterType->GetDataField(Cols[l]);
					printf("\t%s", sValue.GetASCIIZPointer());
					}

				printf("\n");
				}
			}
		}
	}
Exemple #3
0
void GenerateSnapshot (CUniverse &Universe, CXMLElement *pCmdLine)
	{
	ALERROR error;
	int i;

	//	Get some parameters

	int iInitialUpdateTime = pCmdLine->GetAttributeIntegerBounded(CONSTLIT("initialUpdate"), 0, -1, 10);
	int iUpdateTime = pCmdLine->GetAttributeInteger(CONSTLIT("wait"));
	bool bObjOnly = pCmdLine->GetAttributeBool(CONSTLIT("objOnly"));

	//	Criteria

	CString sNode = pCmdLine->GetAttribute(CONSTLIT("node"));
	CString sCriteria = pCmdLine->GetAttribute(CONSTLIT("criteria"));

	//	Number of snapshots

	int iTotalCount = pCmdLine->GetAttributeIntegerBounded(CONSTLIT("count"), 1, -1, 1);

	//	Output

	int cxWidth;
	int cyHeight;
	if (pCmdLine->FindAttributeInteger(CONSTLIT("size"), &cxWidth))
		{
		cyHeight = cxWidth;
		}
	else
		{
		cxWidth = 1024;
		cyHeight = 1024;
		}

	//	Paint flags

	DWORD dwPaintFlags = 0;
	if (pCmdLine->GetAttributeBool(CONSTLIT("noStars")))
		dwPaintFlags |= CSystem::VWP_NO_STAR_FIELD;

	//	Output file

	CString sFilespec = pCmdLine->GetAttribute(CONSTLIT("output"));
	if (!sFilespec.IsBlank())
		sFilespec = pathStripExtension(sFilespec);

	//	Output image

	CG32bitImage Output;
	Output.Create(cxWidth, cyHeight);

	//	Update context

	SSystemUpdateCtx Ctx;
	Ctx.bForceEventFiring = true;
	Ctx.bForcePainted = true;

	RECT rcViewport;
	rcViewport.left = 0;
	rcViewport.top = 0;
	rcViewport.right = cxWidth;
	rcViewport.bottom = cyHeight;

	//	Loop over all systems until we find what we're looking for

	int iLoops = 20;
	int iNodeIndex = 0;
	int iSnapshotIndex = 0;
	CTopologyNode *pNode = Universe.GetTopologyNode(iNodeIndex);
	while (true)
		{
		//	Create the system

		CSystem *pSystem;
		if (error = Universe.CreateStarSystem(pNode, &pSystem))
			{
			printf("ERROR: Unable to create star system.\n");
			return;
			}

		//	If this is the node we want, then search

		CSpaceObject *pTarget;
		if (sNode.IsBlank() || strEquals(sNode, pNode->GetID()))
			{
			printf("Searching %s...\n", pNode->GetSystemName().GetASCIIZPointer());

			//	Set the POV

			CSpaceObject *pPOV = pSystem->GetObject(0);
			Universe.SetPOV(pPOV);
			pSystem->SetPOVLRS(pPOV);

			//	Prepare system

			Universe.UpdateExtended();
			Universe.GarbageCollectLibraryBitmaps();

			//	Update for a while

			for (i = 0; i < iInitialUpdateTime; i++)
				{
				Universe.Update(Ctx);
				Universe.PaintPOV(Output, rcViewport, 0);
				}

			//	Compose the criteria

			CSpaceObject::Criteria Criteria;
			CSpaceObject::ParseCriteria(pPOV, sCriteria, &Criteria);

			//	Get the list of all objects in the system that match the criteria

			CSpaceObject::SCriteriaMatchCtx Ctx(Criteria);
			TArray<CSpaceObject *> Results;
			for (i = 0; i < pSystem->GetObjectCount(); i++)
				{
				CSpaceObject *pObj = pSystem->GetObject(i);
				if (pObj && pObj->MatchesCriteria(Ctx, Criteria))
					Results.Insert(pObj);
				}

			//	Pick the appropriate object from the list

			if (Results.GetCount() == 0)
				pTarget = NULL;
			else if (Criteria.bNearestOnly || Criteria.bFarthestOnly)
				pTarget = Ctx.pBestObj;
			else
				pTarget = Results[mathRandom(0, Results.GetCount() - 1)];
			}
		else
			pTarget = NULL;

		//	If we found the target, then output

		if (pTarget)
			{
			Universe.SetPOV(pTarget);

			//	Wait a bit
			//
			//	NOTE: After we update, pTarget could be invalid (i.e., destroyed)
			//	so we can't use it again.

			CString sTargetName = pTarget->GetNounPhrase(0);

			for (i = 0; i < iUpdateTime; i++)
				{
				if ((i % 100) == 99)
					printf(".");

				Universe.Update(Ctx);
				Universe.PaintPOV(Output, rcViewport, 0);
				}

			if (iUpdateTime >= 99)
				printf("\n");

			//	Paint

			if (bObjOnly)
				{
				SViewportPaintCtx Ctx;
				Ctx.pObj = Universe.GetPOV();
				Ctx.XForm = ViewportTransform(Universe.GetPOV()->GetPos(), 
						g_KlicksPerPixel, 
						cxWidth / 2, 
						cyHeight / 2);
				Ctx.XFormRel = Ctx.XForm;
				Ctx.fNoRecon = true;
				Ctx.fNoDockedShips = true;
				Ctx.fNoSelection = true;
				Ctx.fNoStarfield = true;

				CSpaceObject *pPOV = pSystem->GetObject(0);
				CSpaceObject::Criteria Criteria;
				CSpaceObject::ParseCriteria(pPOV, sCriteria, &Criteria);

				//	Paint all objects that match the criteria

				CSpaceObject::SCriteriaMatchCtx CriteriaCtx(Criteria);
				for (i = 0; i < pSystem->GetObjectCount(); i++)
					{
					CSpaceObject *pObj = pSystem->GetObject(i);
					if (pObj && pObj->MatchesCriteria(CriteriaCtx, Criteria))
						{
						Ctx.pObj = pObj;
						int xObj;
						int yObj;
						Ctx.XForm.Transform(pObj->GetPos(), &xObj, &yObj);

						pObj->Paint(Output, xObj, yObj, Ctx);
						}
					}
				}
			else
				{
			
				Universe.PaintPOV(Output, rcViewport, 0);
				}

			//	Write to file

			if (!sFilespec.IsBlank())
				{
				CString sBmpFilespec;
				if (iTotalCount > 100)
					sBmpFilespec = pathAddExtensionIfNecessary(strPatternSubst(CONSTLIT("%s%03d"), sFilespec, iSnapshotIndex + 1), CONSTLIT(".bmp"));
				else if (iTotalCount > 1)
					sBmpFilespec = pathAddExtensionIfNecessary(strPatternSubst(CONSTLIT("%s%02d"), sFilespec, iSnapshotIndex + 1), CONSTLIT(".bmp"));
				else
					sBmpFilespec = pathAddExtensionIfNecessary(sFilespec, CONSTLIT(".bmp"));

				CFileWriteStream OutputFile(sBmpFilespec);
				if (OutputFile.Create() != NOERROR)
					{
					printf("ERROR: Unable to create '%s'\n", sBmpFilespec.GetASCIIZPointer());
					return;
					}

				Output.WriteToWindowsBMP(&OutputFile);
				OutputFile.Close();
				printf("Found %s: Saved to %s\n", sTargetName.GetASCIIZPointer(), sBmpFilespec.GetASCIIZPointer());
				}

			//	Otherwise, clipboard

			else
				{
				if (error = Output.CopyToClipboard())
					{
					printf("ERROR: Unable to copy image to clipboard.\n");
					return;
					}

				printf("Found %s: Copied to clipboard.\n", sTargetName.GetASCIIZPointer());
				}

			//	Reset maximum loops

			iLoops = 20;

			//	Done

			iSnapshotIndex++;
			if (iSnapshotIndex >= iTotalCount)
				break;
			}

		//	Done with old system

		Universe.DestroySystem(pSystem);

		//	Loop to the next node

		do
			{
			iNodeIndex = ((iNodeIndex + 1) % Universe.GetTopologyNodeCount());
			pNode = Universe.GetTopologyNode(iNodeIndex);
			}
		while (pNode == NULL || pNode->IsEndGame());

		//	If we're back to the first node again, restart

		if (iNodeIndex == 0)
			{
			if (--iLoops > 0)
				{
				//	Reinitialize

				Universe.Reinit();
				CString sError;
				if (Universe.InitGame(0, &sError) != NOERROR)
					{
					printf("ERROR: %s\n", sError.GetASCIIZPointer());
					return;
					}

				iNodeIndex = 0;
				pNode = Universe.GetTopologyNode(iNodeIndex);
				}
			else
				{
				printf("ERROR: Specified target could not be found.\n");
				return;
				}
			}
		}
	}
void GenerateSystemLabelCount (CUniverse &Universe, CXMLElement *pCmdLine)
	{
	ALERROR error;
	int i, j;
	CString sError;

	enum STypes
		{
		typeSystemLabels,
		typeNodeAttributes,
		typeNodeDebug,
		};

	//	Figure out what kind of output we want

	STypes iType;
	if (pCmdLine->GetAttributeBool(CONSTLIT("nodes")))
		iType = typeNodeAttributes;
	else if (pCmdLine->GetAttributeBool(CONSTLIT("nodeDebug")))
		iType = typeNodeDebug;
	else
		iType = typeSystemLabels;

	//	Samples

	int iSystemSample = pCmdLine->GetAttributeIntegerBounded(CONSTLIT("count"), 1, -1, 1);

	//	Options

	bool bPermutations = pCmdLine->GetAttributeBool(CONSTLIT("permutations"));

	//	Generate systems for multiple games

	CSystemCreateStats Stats;
	Stats.AddPermuteAttrib(CONSTLIT("asteroids"));
	Stats.AddPermuteAttrib(CONSTLIT("planetary"));
	Stats.AddPermuteAttrib(CONSTLIT("void"));
	Stats.AddPermuteAttrib(CONSTLIT("innerSystem"));
	Stats.AddPermuteAttrib(CONSTLIT("lifeZone"));
	Stats.AddPermuteAttrib(CONSTLIT("outerSystem"));
	Stats.AddPermuteAttrib(CONSTLIT("envAir"));
	Stats.AddPermuteAttrib(CONSTLIT("envEarth"));
	Stats.AddPermuteAttrib(CONSTLIT("envFire"));
	Stats.AddPermuteAttrib(CONSTLIT("envWater"));
	bPermutations = true;

	for (i = 0; i < iSystemSample; i++)
		{
		printf("pass %d...\n", i+1);

		//	Initialize the universe

		if (error = Universe.InitGame(0, &sError))
			{
			printf("ERROR: %s", sError.GetASCIIZPointer());
			return;
			}

		//	Loop over all topology nodes

		for (j = 0; j < Universe.GetTopologyNodeCount(); j++)
			{
			CTopologyNode *pNode = Universe.GetTopologyNode(j);
			if (pNode->IsEndGame())
				continue;

			//	Different stats depending on type

			switch (iType)
				{
				case typeSystemLabels:
					{
					//	Create the system and generate stats

					CSystem *pSystem;
					if (error = Universe.CreateStarSystem(pNode, &pSystem, NULL, &Stats))
						{
						printf("ERROR: Unable to create star system.\n");
						return;
						}

					//	Done

					Universe.DestroySystem(pSystem);
					break;
					}

				case typeNodeAttributes:
					{
					CString sAttribs = pNode->GetAttributes();

					if (!sAttribs.IsBlank())
						Stats.AddLabel(sAttribs);
					else
						Stats.AddLabel(CONSTLIT("[no attributes]"));

					break;
					}

				case typeNodeDebug:
					{
					CString sAttribs = pNode->GetAttributes();
					printf("%s: %s\n", 
							pNode->GetID().GetASCIIZPointer(), 
							pNode->GetAttributes().GetASCIIZPointer());
					break;
					}
				}
			}
		}

	//	Titles

	int iTotalLabels100 = Stats.GetTotalLabelCount() * 100 / iSystemSample;
	int iTotalLabels = iTotalLabels100 / 100;
	int iTotalLabelsDecimal = iTotalLabels100 % 100;

	switch (iType)
		{
		case typeSystemLabels:
			printf("LABEL STATISTICS\n\n");
			printf("Average no. of labels per universe: %d.%02d\n\n", iTotalLabels, iTotalLabelsDecimal);
			break;

		case typeNodeAttributes:
			printf("NODE ATTRIBUTES\n\n");
			printf("Average no. of nodes per universe: %d.%02d\n\n", iTotalLabels, iTotalLabelsDecimal);
			break;
		}

	//	Nodes

	if (iType != typeNodeDebug)
		{
		for (i = 0; i < Stats.GetLabelAttributesCount(); i++)
			{
			CString sAttribs;
			int iCount;

			Stats.GetLabelAttributes(i, &sAttribs, &iCount);

			if (bPermutations || strFind(sAttribs, CONSTLIT(",")) == -1)
				{
				int iCount100 = iCount * 100 / iSystemSample;
				int iPercent100 = iCount * 10000 / Stats.GetTotalLabelCount();

				printf("%s: %d.%02d (%d.%02d%%)\n", 
						sAttribs.GetASCIIZPointer(), 
						iCount100 / 100,
						iCount100 % 100,
						iPercent100 / 100,
						iPercent100 % 100);
				}
			}
		}
	}
void TestUpdate (CUniverse &Universe, CXMLElement *pCmdLine)
{
    int i;
    int iTrial;

    TArray<DWORD> Trials;
    DWORD dwLastAverage;

    //	How many tests

    int iCount = pCmdLine->GetAttributeInteger(CONSTLIT("count"));
    if (iCount == 0)
        iCount = 1;

    //	How long do we update

    int iUpdateCount = pCmdLine->GetAttributeInteger(CONSTLIT("updateCount"));
    if (iUpdateCount == 0)
        iUpdateCount = DEFAULT_UPDATE;

    //	Create the fist system

    for (iTrial = 0; iTrial < iCount; iTrial++)
    {
        TArray<SSample> Timings;

        printf("Trial: %d\n", iTrial + 1);

        //	Initialize the universe

        CString sError;
        if (Universe.InitGame(0, &sError) != NOERROR)
        {
            printf("ERROR: %s", sError.GetASCIIZPointer());
            return;
        }

        //	Create the first system

        CTopologyNode *pNode = Universe.GetFirstTopologyNode();
        if (pNode == NULL)
        {
            printf("ERROR: Cannot find first node.\n");
            return;
        }

        CSystem *pSystem;
        if (Universe.CreateStarSystem(pNode, &pSystem) != NOERROR)
        {
            printf("ERROR: Unable to create star system.\n");
            return;
        }

        //	Set the POV

        CSpaceObject *pPOV = pSystem->GetObject(0);
        Universe.SetPOV(pPOV);
        pSystem->SetPOVLRS(pPOV);

        //	Prepare system

        Universe.UpdateExtended();
        Universe.GarbageCollectLibraryBitmaps();
        Universe.StartGame(true);

        //	Update context

        SSystemUpdateCtx Ctx;
        Ctx.bForceEventFiring = true;
        Ctx.bForcePainted = true;

        //	Update for a while

        DWORD dwStart = ::GetTickCount();
        for (i = 0; i < iUpdateCount; i++)
        {
            Universe.Update(Ctx);

            if (i > 0 && (i % SAMPLE_SIZE) == 0)
            {
                DWORD dwEnd = ::GetTickCount();
                DWORD dwTime = dwEnd - dwStart;
                SSample *pSample = Timings.Insert();
                pSample->dwTime = dwTime;
                pSample->iObjCount = GetValidObjCount(pSystem);

                CString sTime = strFormatMilliseconds(dwTime);
                CString sObjTime = strFormatMicroseconds(1000 * dwTime / pSample->iObjCount);
                printf("Objs: %d  Total time: %s  Per obj: %s\n",
                       pSample->iObjCount,
                       sTime.GetASCIIZPointer(),
                       sObjTime.GetASCIIZPointer());

                dwStart = ::GetTickCount();
            }
        }

        //	Compute trial average

        DWORD dwTotal = 0;
        DWORD dwAverage = 0;
        for (i = 0; i < Timings.GetCount(); i++)
            dwTotal += Timings[i].dwTime;

        if (Timings.GetCount() > 0)
        {
            dwAverage = dwTotal / Timings.GetCount();
            CString sTime = strFormatMilliseconds(dwAverage);
            printf("Trial average: %s\n", sTime.GetASCIIZPointer());
        }

        Trials.Insert(dwAverage);

        //	Compute total average

        dwTotal = 0;
        for (i = 0; i < Trials.GetCount(); i++)
            dwTotal += Trials[i];

        dwLastAverage = dwTotal / Trials.GetCount();
        CString sTime = strFormatMilliseconds(dwLastAverage);
        printf("\n");
        printf("Running average: %s\n", sTime.GetASCIIZPointer());
        printf("\n");
    }

    //	Final tally

    CString sTime = strFormatMilliseconds(dwLastAverage);
    CString sTime2 = strFormatMicroseconds(1000 * dwLastAverage / SAMPLE_SIZE);

    printf("Total updates: %d\n", iUpdateCount * iCount);
    printf("Average time for %d updates: %s\n", SAMPLE_SIZE, sTime.GetASCIIZPointer());
    printf("Average time per update: %s\n", sTime2.GetASCIIZPointer());
}
Exemple #6
0
void GenerateSimTables (CUniverse &Universe, CXMLElement *pCmdLine)
	{
	ALERROR error;
	int i, j, k;

	int iSystemSample = pCmdLine->GetAttributeInteger(CONSTLIT("count"));
	if (iSystemSample == 0)
		iSystemSample = DEFAULT_SYSTEM_SAMPLE;

	//	Keep track of stats for each type

	TSortMap<DWORD, STypeStats> AllStats;
	for (i = 0; i < iSystemSample; i++)
		{
		TSortMap<DWORD, STypeInfo> AllTypes;

		printf("sample %d...\n", i+1);

		//	Initialize the game

		CString sError;
		if (error = Universe.InitGame(0, &sError))
			{
			printf("%s\n", sError.GetASCIIZPointer());
			return;
			}

		//	Loop over all nodes

		for (j = 0; j < Universe.GetTopologyNodeCount(); j++)
			{
			CTopologyNode *pNode = Universe.GetTopologyNode(j);

			//	Skip end game nodes

			if (pNode->IsEndGame())
				continue;

			//	Create the system

			CSystem *pSystem;
			if (error = Universe.CreateStarSystem(pNode, &pSystem, &sError))
				{
				printf("ERROR: Unable to create star system: %s\n", sError.GetASCIIZPointer());
				return;
				}

			//	Accumulate

			AccumulateSystem(pNode, pSystem, AllTypes);

			//	Done with old system

			Universe.DestroySystem(pSystem);
			}

		//	Now accumulate all stats

		for (j = 0; j < Universe.GetDesignTypeCount(); j++)
			{
			CDesignType *pType = Universe.GetDesignType(j);
			STypeStats *pStats = AllStats.SetAt(pType->GetUNID());

			STypeInfo *pTypeInfo = AllTypes.GetAt(pType->GetUNID());
			if (pTypeInfo)
				{
				pStats->PerGame.Insert(pTypeInfo->iTotalCount);

				for (k = 0; k < MAX_TECH_LEVEL; k++)
					pStats->PerLevel[k].Insert(pTypeInfo->PerLevel[k]);
				}
			else
				{
				pStats->PerGame.Insert(0);

				for (k = 0; k < MAX_TECH_LEVEL; k++)
					pStats->PerLevel[k].Insert(0);
				}
			}

		Universe.Reinit();
		}

	//	Output

	if (error = OutputTypeTable(AllStats, iSystemSample))
		return;

	//	Create a table with the sum of all items for the game

	printf("Total count statistic computed.\n");
	}
void GenerateEncounterFrequency (CUniverse &Universe, CXMLElement *pCmdLine)
	{
	enum ETypes
		{
		outputFreq,
		outputFillLocations,
		};

	int i, j;

	//	Options

	int iSystemSample = pCmdLine->GetAttributeIntegerBounded(CONSTLIT("count"), 1, -1, 1);
	bool bLogo = !pCmdLine->GetAttributeBool(CONSTLIT("noLogo"));
	bool bAll = pCmdLine->GetAttributeBool(CONSTLIT("all"));

	bool bRawData = pCmdLine->GetAttributeBool(CONSTLIT("rawData"));
	
	ETypes iType;
	if (pCmdLine->GetAttributeBool(CONSTLIT("fillLocations")))
		iType = outputFillLocations;
	else
		iType = outputFreq;

	//	Additional columns

	TArray<CString> Cols;
	for (i = 0; i < pCmdLine->GetAttributeCount(); i++)
		{
		CString sAttrib = pCmdLine->GetAttributeName(i);

		if (!IsMainCommandParam(sAttrib)
				&& !strEquals(sAttrib, CONSTLIT("count"))
				&& !strEquals(sAttrib, CONSTLIT("fillLocations"))
				&& !strEquals(sAttrib, CONSTLIT("rawData"))
				&& !strEquals(sAttrib, CONSTLIT("encounterfreq")))
			{
			CString sValue = pCmdLine->GetAttribute(i);
			
			if (!strEquals(sValue, CONSTLIT("true")))
				Cols.Insert(strPatternSubst(CONSTLIT("%s:%s"), sAttrib, sValue));
			else
				Cols.Insert(sAttrib);
			}
		}

	//	Generate systems for multiple games

	CSystemCreateStats Stats;
	for (i = 0; i < iSystemSample; i++)
		{
		if (bLogo)
			printf("pass %d...\n", i+1);

		//	Initialize the game

		CString sError;
		if (Universe.InitGame(0, &sError) != NOERROR)
			{
			printf("%s\n", sError.GetASCIIZPointer());
			return;
			}

		for (j = 0; j < Universe.GetTopologyNodeCount(); j++)
			{
			CTopologyNode *pNode = Universe.GetTopologyNode(j);
			if (pNode->IsEndGame())
				continue;

			//	Create the system

			CSystem *pSystem;
			if (Universe.CreateStarSystem(pNode, &pSystem, NULL, &Stats) != NOERROR)
				{
				printf("ERROR: Unable to create star system.\n");
				return;
				}

			//	Done with old system

			Universe.DestroySystem(pSystem);
			}

		Universe.Reinit();
		}

	//	Output based on type

	if (iType == outputFreq)
		{
		//	Generate a table for each encounter

		TSortMap<CStationType *, SEncounterFreqEntry> EncounterFreq;
		for (i = 0; i < Stats.GetEncounterTableCount(); i++)
			{
			const CSystemCreateStats::SEncounterTable &Table = Stats.GetEncounterTable(i);

			//	Skip if only planets and asteroids

			if (!Table.bHasStation && !bAll)
				continue;

			//	For each entry in the table, add to the frequency table

			for (j = 0; j < Table.Table.GetCount(); j++)
				{
				CStationType *pEncounterType = Table.Table.GetAt(j);
				int iChance = Table.Table.GetChance(j);

				SEncounterFreqEntry *pEntry = EncounterFreq.SetAt(pEncounterType);
				pEntry->iCount += Table.iCount;
				pEntry->iTotalChance += Table.iCount * iChance;

				if (pEntry->pMaxTable == NULL || iChance > pEntry->iMaxChance)
					{
					pEntry->pMaxTable = &Table;
					pEntry->iMaxChance = iChance;
					}

				if (pEntry->pMinTable == NULL || iChance < pEntry->iMinChance)
					{
					pEntry->pMinTable = &Table;
					pEntry->iMinChance = iChance;
					}
				}
			}

		//	Output encounter frequency distribution

		printf("Level\tCategory\tEncounter\tTotal Chances\tAverage Chance\tMin Chance\tMax Chance");
		for (i = 0; i < Cols.GetCount(); i++)
			printf("\t%s", Cols[i].GetASCIIZPointer());
		printf("\n");

		for (i = 0; i < EncounterFreq.GetCount(); i++)
			{
			CStationType *pEncounterType = EncounterFreq.GetKey(i);
			int iAveWhole = EncounterFreq[i].iTotalChance / EncounterFreq[i].iCount;
			int iAveFrac = 1000 * (EncounterFreq[i].iTotalChance % EncounterFreq[i].iCount) / EncounterFreq[i].iCount;

			printf("%d\t%s\t%s\t%d\t%d.%03d\t%d\t%d",
					pEncounterType->GetLevel(),
					pEncounterType->GetDataField(CONSTLIT("category")).GetASCIIZPointer(),
					pEncounterType->GetName().GetASCIIZPointer(),
					EncounterFreq[i].iCount,
					iAveWhole,
					iAveFrac,
					EncounterFreq[i].iMinChance,
					EncounterFreq[i].iMaxChance);

			for (j = 0; j < Cols.GetCount(); j++)
				{
				CString sValue = pEncounterType->GetDataField(Cols[j]);
				printf("\t%s", sValue.GetASCIIZPointer());
				}

			printf("\n");
			}

		//	Output raw data

		if (bRawData)
			{
			//	Loop over stats and output tables

			for (i = 0; i < Stats.GetEncounterTableCount(); i++)
				{
				const CSystemCreateStats::SEncounterTable &Table = Stats.GetEncounterTable(i);

				//	Skip if only planets and asteroids

				if (!Table.bHasStation && !bAll)
					continue;

				//	Header

				printf("LEVEL %d (%d location%s)\nSystem Type: %08x\nStations: %s\n", 
						Table.iLevel,
						Table.iCount,
						(Table.iCount == 1 ? "" : "s"),
						Table.pSystemType->GetUNID(),
						Table.sStationCriteria.GetASCIIZPointer());

				//	Location attributes

				printf("Location: ");
				for (j = 0; j < Table.LabelAttribs.GetCount(); j++)
					{
					if (j != 0)
						printf(", ");
					printf(Table.LabelAttribs[j].GetASCIIZPointer());
					}
				printf("\n");

				//	Entries

				for (j = 0; j < Table.Table.GetCount(); j++)
					printf("%s\t%d\n", Table.Table.GetAt(j)->GetName().GetASCIIZPointer(), Table.Table.GetChance(j));

				printf("\n");
				}
			}
		}
	else if (iType == outputFillLocations)
		{
		printf("Level\tSystem\tEncounter\tChance\n");

		for (i = 0; i < Stats.GetFillLocationsTableCount(); i++)
			{
			const CSystemCreateStats::SFillLocationsTable &Entry = Stats.GetFillLocationsTable(i);

			for (j = 0; j < Entry.Table.GetCount(); j++)
				{
				int iPercent = (int)(1000.0 * Entry.Table.GetChance(j) / (Metric)Entry.Table.GetTotalChance());

				printf("%d\t%s\t%s\t%d.%d\n",
						Entry.iLevel,
						Entry.sSystemName.GetASCIIZPointer(),
						Entry.Table[j]->GetName().GetASCIIZPointer(), 
						iPercent / 10,
						iPercent % 10);
				}
			}
		}
	}