private void updateBestChronoEventList(List <bUUEvent> newBestChronoEventList)
        {
            //need to make sure bestBuild has the right number of warpgate events
            for (int i = 0; i < newBestChronoEventList.Count(); i++)
            {
                if (i < bestBuild.Count())
                {
                    bestBuild[i].startTime      = newBestChronoEventList[i].startTime;
                    bestBuild[i].endTime        = newBestChronoEventList[i].endTime;
                    bestBuild[i].fromWG         = newBestChronoEventList[i].fromWG;
                    bestBuild[i].pairAsChildID  = newBestChronoEventList[i].pairAsChildID;
                    bestBuild[i].pairAsParentID = newBestChronoEventList[i].pairAsParentID;
                    bestBuild[i].bUUDataID      = newBestChronoEventList[i].bUUDataID;
                }
                else
                {
                    //need to add on new event to bestBuild
                    bUUEvent newEvent = new bUUEvent(newBestChronoEventList[i].bUUEventID, newBestChronoEventList[i].startTime, newBestChronoEventList[i].endTime, newBestChronoEventList[i].bUUDataID, newBestChronoEventList[i].pairAsChildID, newBestChronoEventList[i].pairAsParentID, newBestChronoEventList[i].name);
                    bestBuild.Add(newEvent);
                }
            }
            //remove any extra items in bestBuild
            int extraEvents = bestBuild.Count() - newBestChronoEventList.Count();

            for (int i = 0; i < extraEvents; i++)
            {
                int spot = bestBuild.Count() - 1 - i;
                bestBuild.RemoveAt(spot);
            }
        }
        private void createPrimaryEventAndPairList(List <bUUPairObject> buildingPairs)
        {
            //convert input to new format
            eventList = new List <bUUEvent>();
            pairList  = new List <PairsTable>();

            foreach (bUUPairObject thisPair in buildingPairs)
            {
                if (thisPair.child.name.Equals("pylon")) //create event but not pair
                {
                    int      eventID  = eventList.Count();
                    bUUEvent newEvent = new bUUEvent(eventID, 0, 0, thisPair.child.bUUDataID, -1, -1);
                    eventList.Add(newEvent);
                }
                else if (thisPair.child.isBuilding)
                {
                    //find parent Event
                    int parentEventID = eventList.First(x => x.bUUDataID == thisPair.parent.bUUDataID).bUUEventID;

                    int      eventID  = eventList.Count();
                    int      pairID   = pairList.Count();
                    bUUEvent newEvent = new bUUEvent(eventID, 0, 0, thisPair.child.bUUDataID, pairID, -1);
                    eventList.Add(newEvent);
                    PairsTable newPair = new PairsTable(pairID, parentEventID, eventID);
                    pairList.Add(newPair);

                    //edit parentEvent to correctly use pairAsParentID
                    eventList[parentEventID].pairAsParentID = pairID;

                    //add eventID to pairsLibrary for quick access
                    pairObjectLibrary[thisPair.child.bUUDataID].bUUEventIDForPrimaryBuilding = eventID;
                }
            }
        }
 private void createEventListCopy()
 {
     cchronoEventList = new List <bUUEvent>();
     bestBuild        = new List <bUUEvent>();
     foreach (bUUEvent thisEvent in eventList)
     {
         bUUEvent newEvent = new bUUEvent(thisEvent.bUUEventID, thisEvent.startTime, thisEvent.endTime, thisEvent.bUUDataID, thisEvent.pairAsChildID, thisEvent.pairAsParentID, thisEvent.name);
         cchronoEventList.Add(newEvent);
         bUUEvent newEvent2 = new bUUEvent(thisEvent.bUUEventID, thisEvent.startTime, thisEvent.endTime, thisEvent.bUUDataID, thisEvent.pairAsChildID, thisEvent.pairAsParentID, thisEvent.name);
         bestBuild.Add(newEvent2);
     }
 }
 private void createUnitEvents()
 {
     //go through pairObjectLibrary and create an event for each unit. include dummy pairs for now. add reference in pairObjectLibrary
     foreach (bUUDataObject thisObject in pairObjectLibrary)
     {
         if (!thisObject.isBuilding && thisObject.mineralCost > 0 && !thisObject.name.Equals("Probe")) //don't include warpgate or probe
         {
             bUUEvent newEvent = new bUUEvent(eventList.Count(), 0, 0, thisObject.bUUDataID, -1, -1);
             thisObject.bUUEventIDForPrimaryBuilding = eventList.Count();
             eventList.Add(newEvent);
         }
     }
 }
 private void createNewVersions(List <bUUEvent> myEventList, List <PairsTable> myPairList, List <bUUDataObject> myPairObjectLibrary)
 {
     eventList         = new List <bUUEvent>();
     pairList          = new List <PairsTable>();
     pairObjectLibrary = new List <bUUDataObject>();
     foreach (bUUEvent thisEvent in myEventList)
     {
         bUUEvent newEvent = new bUUEvent(thisEvent.bUUEventID, thisEvent.startTime, thisEvent.endTime, thisEvent.bUUDataID, thisEvent.pairAsChildID, thisEvent.pairAsParentID);
         eventList.Add(newEvent);
     }
     foreach (PairsTable thisPair in myPairList)
     {
         PairsTable newPair = new PairsTable(thisPair.pairID, thisPair.parentBUUEventID, thisPair.childBUUEventID);
         pairList.Add(newPair);
     }
     foreach (bUUDataObject thisObject in myPairObjectLibrary)
     {
         bUUDataObject newObject = new bUUDataObject(thisObject.bUUDataID, thisObject.bUUEventIDForPrimaryBuilding, thisObject.name, thisObject.duration, thisObject.durationWithwarpGateResearch, thisObject.mineralCost, thisObject.gasCost, thisObject.isProductionBuilding, thisObject.isUnit, thisObject.isBuilding, thisObject.producedOutOf, thisObject.buildingReqList, thisObject.supplyCost, thisObject.supplyProvided);
         pairObjectLibrary.Add(newObject);
     }
 }
        private void addSecondaryBuildings()
        {
            //go through lastBasketEntries
            foreach (IDWithList thisRow in lastBasketEntries)
            {
                //only consider entries after the first one
                for (int i = 1; i < thisRow.IDList.Count; i++)
                {
                    //add secondary building before this event
                    //find event production building to add correct secondary building
                    int           childEventID = thisRow.IDList[i];
                    bUUDataObject B1           = pairObjectLibrary[thisRow.ID];
                    //need to create a new object that copies B1, but with new ID
                    bUUDataObject newObject = new bUUDataObject(B1.name, B1.duration, B1.mineralCost, B1.gasCost, B1.isProductionBuilding, B1.isUnit, B1.supplyProvided, B1.isBuilding);
                    int           dataID    = pairObjectLibrary.Count();
                    newObject.bUUDataID = dataID;
                    pairObjectLibrary.Add(newObject);

                    //create new event
                    int      eventID  = eventList.Count();
                    double   endTime  = eventList[childEventID].startTime;
                    double   duration = B1.duration;
                    bUUEvent newEvent = new bUUEvent(eventID, endTime - duration, endTime, dataID, pairList.Count() + 1, pairList.Count());
                    eventList.Add(newEvent);
                    //create new pair
                    PairsTable newPair = new PairsTable(pairList.Count(), eventID, childEventID);
                    pairList.Add(newPair);

                    //also need to create pair connected secondaryBuilding to its parent
                    //first find parent
                    int        parentOfSecondaryBuildingEventID = pairList[eventList[pairObjectLibrary[thisRow.ID].bUUEventIDForPrimaryBuilding].pairAsChildID].parentBUUEventID;
                    PairsTable newPair2 = new PairsTable(pairList.Count(), parentOfSecondaryBuildingEventID, eventID);
                    pairList.Add(newPair2);
                    //parentEvent will not have relationship added for this pair (only has space to show one relationship currently)

                    //update event PairAsChildID of child
                    eventList[childEventID].pairAsChildID = pairList.Count() - 2;
                }
            }
        }
        public constructBestBUUOrder(double globalFastestBuildYet, int WGRSpot, List <bUUDataObject> myPairObjectLibrary, List <IDWithList> myProductionTable, List <IDWithList> myBasketSplitTable, List <bUUEvent> myEventList, List <PairsTable> myPairList, List <IDWithList> myPrecedenceRelations, List <double> emptyAlteredMineralStatements, List <double> mineralStatements, List <double> gasStatements, List <double> myApproximateChronoTimes, int globalIterationNum, bool firstChronoSelected)
        {
            numChronoFunctionsRan  = 0;
            WGREventChain          = new List <int>();
            approximateChronoTimes = myApproximateChronoTimes;
            precedenceRelations    = myPrecedenceRelations;
            createNewVersions(myEventList, myPairList, myPairObjectLibrary);

            //1. go through each row in basketSplitTable to create events and pairs for all units
            createUUEventsAndPairs(myProductionTable, myBasketSplitTable);
            if (discardBuild)
            {
                return;
            }
            //2. Add in secondary buildings
            addSecondaryBuildings();
            //3. Add in primary buildings at latest possible time given precedence constraints
            addPrimaryBuildings();
            //3.5 Update WGR times to be directly made once cyber is done
            if (WGRSpot >= 0)
            {
                updateWGRTime(WGRSpot);
            }
            //adding names to each event for debugging purposes
            addNamesToEvents();
            if (WGRSpot >= 0)
            {
                bUUEvent wgr = eventList.First(x => x.name == "warpGateResearch");
                wgr.startTime = wgr.startTime - 0.01;
            }


            orderedEventList = new List <bUUEvent>(eventList.OrderBy(x => x.startTime));

            if (orderedEventList[0].startTime < -500)
            {
                discardBuild = true; return;
            }

            //4. Left shift everything as a group based on nonrenewable resource chart
            double timeShifted = leftShiftEntireBuild(mineralStatements, gasStatements);

            if (discardBuild)
            {
                return;
            }                             //discard if time shifted makes over 500 long

            //cut build if timeShifted>globalFastestBuildYet*1.3
            if (timeShifted > globalFastestBuildYet * 1.3)
            {
                discardBuild = true; return;
            }

            //5. Consider how many available chronos based on current time ETA. Repeat below steps for each combination of chronos
            if (timeShifted < globalFastestBuildYet)
            {
                globalFastestBuildYet = timeShifted;
            }
            List <List <int> > chronoOptions = createChronoOptions(globalFastestBuildYet, WGRSpot, globalIterationNum, firstChronoSelected);

            if (WGRSpot >= 0)
            {
                int WGREventID       = pairObjectLibrary[WGRSpot].bUUEventIDForPrimaryBuilding;
                int cyberCoreEventID = pairList[eventList[WGREventID].pairAsChildID].parentBUUEventID;
                int gatewayEventID   = pairList[eventList[cyberCoreEventID].pairAsChildID].parentBUUEventID;
                int pylonEventID     = pairList[eventList[gatewayEventID].pairAsChildID].parentBUUEventID;
                WGREventChain = new List <int> {
                    pylonEventID, gatewayEventID, cyberCoreEventID, WGREventID
                };
            }

            //create a new eventList that will be referenced by each chronoOption (allows to edit start and endtimes while still keeping parent reference
            createEventListCopy(); //initializes cchronoEventList and bestBuild
            semiOrderedChronoEventList = new List <bUUEvent>(cchronoEventList.OrderBy(x => x.startTime));

            //test each chrono option
            for (int i = 0; i < chronoOptions.Count(); i++)
            {
                chronoOptionEvaluation newChronoOptionEvaluation = new chronoOptionEvaluation(globalFastestBuildYet, i, chronoOptions[i], mineralStatements, gasStatements, emptyAlteredMineralStatements, eventList, orderedEventList, cchronoEventList, semiOrderedChronoEventList, WGRSpot, pairObjectLibrary, approximateChronoTimes, WGREventChain, lastBasketEntries, precedenceRelations, pairList, globalIterationNum, firstChronoSelected);
                numChronoFunctionsRan++;
                // first chrono option is all chains ends. If this option is not within 10 % of bestYet, dont test any other chrono options.
                if (newChronoOptionEvaluation.buildEndTime > 1.1 * globalFastestBuildYet && i == 0)
                {
                    break;
                }
                //check if evaluation is new best
                if (newChronoOptionEvaluation.buildEndTime < globalFastestBuildYet || newChronoOptionEvaluation.buildEndTime == globalFastestBuildYet && newChronoOptionEvaluation.chronoEcoLog.Count() == 0)
                {
                    globalFastestBuildYet      = newChronoOptionEvaluation.buildEndTime;
                    bestChronoOptionEvaluation = newChronoOptionEvaluation;
                    excessMinerals             = findExcessMinerals(mineralStatements, newChronoOptionEvaluation.buildEndTime);
                    excessGas = findExcessGas(gasStatements, newChronoOptionEvaluation.buildEndTime);

                    //the chronoEventList times will get altered after each run. Need to save a copy of the best runTimes
                    updateBestChronoEventList(newChronoOptionEvaluation.chronoEventList);
                }
            }
            //if no build is faster than globalFastestBuildYet
            if (bestChronoOptionEvaluation == null)
            {
                discardBuild = true;
            }
        }