private void createProductionTable()
        {
            productionTable = new List <IDWithList>();
            List <bUUDataObject> unitList = pairObjectLibrary.Where(x => !x.isBuilding).ToList();

            foreach (bUUDataObject thisObject in pairObjectLibrary)
            {
                if (thisObject.isBuilding && thisObject.supplyProvided == 0)//don't include nexus
                {
                    //find all units produced out of this
                    List <int> unitIDs = new List <int>();
                    foreach (bUUDataObject thisUnit in unitList)
                    {
                        if (thisUnit.producedOutOf.Equals(thisObject.name) && thisUnit.mineralCost > 0) //dont include WG
                        {
                            unitIDs.Add(thisUnit.bUUDataID);
                        }
                    }
                    if (unitIDs.Count() > 0)
                    {
                        IDWithList newEntry = new IDWithList(thisObject.bUUDataID, unitIDs);
                        productionTable.Add(newEntry);
                    }
                }
            }
        }
        private List <IDWithList> convertBoolRepBack(List <IDWithList> boolRepresentation, List <int> thisBasketCount)
        {
            List <IDWithList> listToReturn = new List <IDWithList>();

            for (int a = 0; a < boolRepresentation.Count(); a++)
            {
                int        thisID    = boolRepresentation[a].ID;
                List <int> thisSplit = new List <int>();
                //first add default members
                thisSplit.Add(1);
                //(add two to first bucket if have the units)
                if (productionTable[a].IDList.Count() > thisBasketCount[a])
                {
                    thisSplit[0]++;
                }
                for (int i = 1; i < thisBasketCount[a]; i++)
                {
                    thisSplit.Add(1);
                }
                //next add members as determined by bool
                int currentBasket = 0;
                for (int c = 0; c < boolRepresentation[a].IDList.Count(); c++)
                {
                    if (boolRepresentation[a].IDList[c] == 1)
                    {
                        currentBasket++;
                    }
                    thisSplit[currentBasket]++;
                }
                IDWithList newEntry = new IDWithList(thisID, thisSplit);
                listToReturn.Add(newEntry);
            }
            return(listToReturn);
        }
        private void createPrecedenceRelations()
        {
            //need a dataObject: [thisEventID] List[all units that have precedence on thisEventID, or building that is child]
            //pairList is sorted in technological order, precedenceRelations should be sorted in same manner
            precedenceRelations = new List <IDWithList>();

            //go through eventList and make entry for each event
            foreach (bUUEvent thisEvent in eventList)
            {
                //make sure this event is a building
                if (pairObjectLibrary[thisEvent.bUUDataID].isBuilding)
                {
                    List <int> newList  = new List <int>();
                    IDWithList newEntry = new IDWithList(thisEvent.bUUEventID, newList);
                    //add all children of this event
                    List <PairsTable> children = pairList.Where(x => x.parentBUUEventID == thisEvent.bUUEventID).ToList();
                    foreach (PairsTable thisChild in children)
                    {
                        //add the child eventID if nonnegative number (negatives correspond to no child)
                        if (thisChild.childBUUEventID >= 0)
                        {
                            newEntry.IDList.Add(thisChild.childBUUEventID);
                        }
                    }
                    //only add to list if has precedence relations
                    precedenceRelations.Add(newEntry);
                }
            }
            //now add precedence for each unit
            //go through pairObjectLibrary, and consider the tech reqs of each unit
            foreach (bUUDataObject thisObject in pairObjectLibrary)
            {
                if (!thisObject.isBuilding && thisObject.mineralCost > 0) //dont consider warpgate
                {
                    int thisEventID = thisObject.bUUEventIDForPrimaryBuilding;
                    foreach (string thisTechReq in thisObject.buildingReqList)
                    {
                        //find eventID of the tech req. add thisEventID to that row in precedenceRelations
                        int techReqEventID = pairObjectLibrary.First(x => x.name.Equals(thisTechReq)).bUUEventIDForPrimaryBuilding;

                        //techreqEventID may be for an earlier upgrade, in which case it wont exist in precendence relations
                        if (precedenceRelations.Where(x => x.ID == techReqEventID).Any())
                        {
                            precedenceRelations.First(x => x.ID == techReqEventID).IDList.Add(thisEventID);
                        }
                    }
                }
            }
        }
        private List <IDWithList> convertSplitToBool(List <IDWithList> lastSplit)
        {
            //create rows of 1s and 0s based on when split was made
            //0= stay in this basket, 1= move to next basket
            //Example a split of (5,4,2) -> free choices (3,3,2) -> bools are (0,0,0,1,0,0,1,0), where some of the bools are forced into 1 option (like last 1)

            List <IDWithList> boolRepresentation = new List <IDWithList>();

            //go through each production building split directions
            for (int j = 0; j < lastSplit.Count(); j++)
            {
                //create a new row
                int        thisID        = lastSplit[j].ID;
                List <int> thisBinaryRow = new List <int>();
                //only add elements if there are multiple baskets in this row and numElements>numbaskets+1
                if (lastSplit[j].IDList.Count() > 1 && productionTable[j].IDList.Count > lastSplit[j].IDList.Count() + 1)
                {
                    for (int i = 0; i < lastSplit[j].IDList.Count(); i++)
                    {
                        //first basket has 2 defaults, all other baskets have 1 default
                        if (i == 0)
                        {
                            int numberDecisionsToStay = lastSplit[j].IDList[i] - 2;
                            for (int c = 0; c < numberDecisionsToStay; c++)
                            {
                                thisBinaryRow.Add(0);
                            }
                        }
                        else
                        {
                            //if going to add zeroes for a basket, add a 1 for first element that swapped over
                            int numberDecisionsToStay = lastSplit[j].IDList[i] - 1;
                            if (numberDecisionsToStay > 0)
                            {
                                thisBinaryRow.Add(1);
                            }
                            for (int c = 1; c < numberDecisionsToStay; c++) //start at 1 because first element is added as a 1
                            {
                                thisBinaryRow.Add(0);
                            }
                        }
                    }
                }
                IDWithList newEntry = new IDWithList(thisID, thisBinaryRow);
                boolRepresentation.Add(newEntry);
            }

            return(boolRepresentation);
        }
        private List <IDWithList> findEvenSplit(List <int> thisBasketCount)
        {
            //consider even split
            List <IDWithList> evenSplit = new List <IDWithList>();

            for (int i = 0; i < thisBasketCount.Count(); i++)
            {
                //create new row in evenSplit
                int        rowID    = productionTable[i].ID;
                List <int> evenList = buildEventList(thisBasketCount[i], productionTable[i].IDList.Count());
                IDWithList newEntry = new IDWithList(rowID, evenList);
                evenSplit.Add(newEntry);
            }
            return(evenSplit);
        }
        private List <IDWithList> createBasketSplitTable(List <bool> basketSplitDirections)
        {
            List <IDWithList> basketSplitTable = new List <IDWithList>();
            //foreach element in productionTable, consider its list
            //foreach element in its list, consider option to (add another production building)
            int totalElementsChecked  = 0;
            int previousAddedElements = 0;

            foreach (IDWithList thisRow in productionTable)
            {
                List <int> splitForThisRow = new List <int>();
                //split elements in this Row based on basketSplitDirections
                for (int i = 0; i < thisRow.IDList.Count() - 1; i++)
                {
                    //check boolean at this spot
                    if (basketSplitDirections[totalElementsChecked])
                    {
                        //create a new basket
                        splitForThisRow.Add(totalElementsChecked + 1 - previousAddedElements);
                        previousAddedElements = totalElementsChecked + 1;
                    }
                    totalElementsChecked++;
                }
                //add final split element. add up all other splits and make last one reach max
                int sum = 0;
                foreach (int thisInt in splitForThisRow)
                {
                    sum = sum + thisInt;
                }
                int amountLeft = thisRow.IDList.Count() - sum;
                splitForThisRow.Add(amountLeft);
                //update previous Added Elements
                previousAddedElements = totalElementsChecked;
                IDWithList newRow = new IDWithList(thisRow.ID, splitForThisRow);
                basketSplitTable.Add(newRow);
                //add row to listToREturn
            }
            return(basketSplitTable);
        }
        private List <IDWithList> findNextSplit(List <int> thisBasketCount, List <IDWithList> lastSplit, bool firstTime)
        {
            if (firstTime)
            {
                //return max amount in first column
                List <IDWithList> firstSplit = new List <IDWithList>();
                List <int>        itemsToAddToFirstBuilding = new List <int>();
                for (int i = 0; i < productionTable.Count(); i++)
                {
                    int        numItems        = productionTable[i].IDList.Count() - thisBasketCount[i] + 1;
                    List <int> splitForThisRow = new List <int>();
                    splitForThisRow.Add(numItems);
                    //add 1 to every other basket
                    for (int g = 1; g < thisBasketCount[i]; g++)
                    {
                        splitForThisRow.Add(1);
                    }
                    IDWithList newEntry = new IDWithList(productionTable[i].ID, splitForThisRow);
                    firstSplit.Add(newEntry);
                }
                return(firstSplit);
            }
            //at least one unit must go into each basket
            //next unit after that is defaulted to first basket
            //each production building has (#units-#baskets-1) booleans
            //boolean is comprised of X digits, where X represents sum of all production building booleans
            //when checking a digit, find which Row it belongs to, compare rules against properties of this row

            //convert lastSplit into boolean representation
            List <IDWithList> boolRepresentation = convertSplitToBool(lastSplit);


            List <int> boolsPerRow = new List <int>();

            for (int i = 0; i < productionTable.Count(); i++)
            {
                int numBools = productionTable[i].IDList.Count() - thisBasketCount[i] - 1;
                boolsPerRow.Add(numBools);
            }
            //work backwards through each element, find first 0 that can be made 1
            //default all elements after to 0
            bool nextSplitFound = false;

            for (int i = lastSplit.Count() - 1; i >= 0; i--)
            {
                for (int c = boolRepresentation[i].IDList.Count() - 1; c >= 0; c--)
                {
                    if (checkCanChangeBasket(i, c, boolRepresentation, thisBasketCount))
                    {
                        boolRepresentation = incrementSplitHere(i, c, boolRepresentation, thisBasketCount);
                        nextSplitFound     = true;
                        break;
                    }
                }
                if (nextSplitFound)
                {
                    break;
                }
            }
            if (!nextSplitFound) //if this is final split, let parent function know
            {
                lastSplit[0].ID = -1;
                return(lastSplit);
            }
            //convert boolRepresentation back
            List <IDWithList> nextSplit = convertBoolRepBack(boolRepresentation, thisBasketCount);

            return(nextSplit);
        }
        private void createUUEventsAndPairs(List <IDWithList> productionTable, List <IDWithList> basketSplitTable)
        {
            lastBasketEntries = new List <IDWithList>();
            // Split each row in productionTable according to basketSplitTable
            for (int i = 0; i < productionTable.Count(); i++)
            {
                //make sure upgrades always added to predecesors basket
                if (pairObjectLibrary[productionTable[i].ID].name == "forge" && productionTable[i].IDList.Count() > 1 && basketSplitTable[i].IDList.Count() > 1)
                {
                    productionTable[i].IDList = sortForgeList(productionTable[i].IDList, basketSplitTable[i].IDList);
                    if (discardBuild)
                    {
                        return;
                    }
                }
                else if (pairObjectLibrary[productionTable[i].ID].name == "cyberCore" && productionTable[i].IDList.Count() > 1)
                {
                    //productionTable[i].IDList = sortCyberList(productionTable[i].IDList, basketSplitTable[i].IDList);
                }

                List <int> IDOfLastBasketEntry = new List <int>();
                IDWithList thisItem            = new IDWithList(productionTable[i].ID, IDOfLastBasketEntry);
                lastBasketEntries.Add(thisItem);
                int        nextBasket  = 0;
                int        numBaskets  = basketSplitTable[i].IDList.Count();
                List <int> basketSpots = new List <int>(basketSplitTable[i].IDList);
                //need to keep a running total of last unit added to each bucket

                //go through every id in the row to fill baskets
                //go through list backwards to have higher tech units be added later
                bool noBasketsEmpty = false;
                for (int g = productionTable[i].IDList.Count() - 1; g >= 0; g--)
                {
                    //add this unit to next available basket (reduce basketSpots)
                    basketSpots[nextBasket]--;
                    int parentBUUID   = productionTable[i].IDList[g];
                    int parentEventID = pairObjectLibrary[parentBUUID].bUUEventIDForPrimaryBuilding;
                    if (parentEventID == 0)
                    {
                        int pause = 0;
                    }
                    double endTime;
                    if (noBasketsEmpty)
                    {
                        //find child
                        int childEventID = lastBasketEntries[i].IDList[nextBasket];

                        //update event properties (endTime = startTime of child)
                        endTime = eventList[childEventID].startTime;
                        eventList[parentEventID].pairAsParentID = pairList.Count();
                        //add pair as parent (find child ID from IDOfLastBasketEntry)
                        PairsTable newPair = new PairsTable(pairList.Count(), parentEventID, childEventID);
                        pairList.Add(newPair);
                        //update child pair to account for new pair
                        eventList[childEventID].pairAsChildID = pairList.Count() - 1;
                    }
                    else
                    {
                        //first unit into basket (need to add spot in lastBasketEntries)
                        endTime = 0;
                        lastBasketEntries[i].IDList.Add(-1); //add -1 as placeholder
                    }

                    double duration = pairObjectLibrary[parentBUUID].duration;
                    eventList[parentEventID].startTime = endTime - duration;
                    eventList[parentEventID].endTime   = endTime;
                    //update last item in bucket
                    lastBasketEntries[i].IDList[nextBasket] = parentEventID;
                    //update nextBasket
                    int currentBasket = nextBasket;
                    nextBasket = findNextBasket(nextBasket, basketSpots, numBaskets);
                    if (nextBasket <= currentBasket)
                    {
                        noBasketsEmpty = true;
                    }
                }
            }
        }