示例#1
0
        public static int OptimalOreForCash(double hpc, ref int searchStartpoint)
        {
            Ore fakeOreForBinarySearch = new Ore("", hpc, 0, 0, hpc, hpc, 0);
            int maxOreIndex            = oreList.BinarySearch(searchStartpoint, oreList.Count - searchStartpoint, fakeOreForBinarySearch, new MinDamageComparer());

            if (maxOreIndex > 0)
            {
                Ore o = oreList[maxOreIndex];
                if (o.MinHpcToConsider != o.MaxHpcToConsider)
                {
                    // exactly hit a good ore at its minimum value
                    oreList[maxOreIndex].UpdateClicks(hpc);
                    return(maxOreIndex);
                }
                maxOreIndex--; // exactly hit a dud ore
            }
            else
            {
                // a negative return value means the ~ of the place where this value would be inserted
                maxOreIndex = ~maxOreIndex - 1;
            }

            Ore optimalOreSoFar = fakeOreForBinarySearch;
            int optimalIndex    = -1;

            for (int candidateIndex = maxOreIndex; candidateIndex >= 0; candidateIndex--)
            {
                Ore candidateOre = oreList[candidateIndex];
                if (hpc < candidateOre.MaxHpcToConsider)
                {
                    candidateOre.UpdateClicks(hpc);
                    if (candidateOre.ValuePerClick > optimalOreSoFar.ValuePerClick)
                    {
                        optimalOreSoFar = candidateOre;
                        optimalIndex    = candidateIndex;
                    }
                }

                if (hpc >= candidateOre.MaxHpcOfAllAbove) // past last possible point
                {
                    searchStartpoint = candidateIndex;
                    break;
                }
            }
            return(optimalIndex);
        }
示例#2
0
        public static int ComputeMostLucrativeOre(int[] upgradeState, WealthStatistics currentStatistics, out uint clicksForEachVictory, out double valueOfEachVictory)
        {
            double rawPickDamage          = currentStatistics.CurrentP * currentStatistics.IdleActiveMultipliers() * upgradeState[(int)UpgradeID.ICAUTOPOWER & 127];
            Ore    fakeOreForComparingRpd = new Ore()
            {
                Defense = 0, Hp = rawPickDamage, MinHpcToConsider = rawPickDamage, MaxHpcToConsider = rawPickDamage
            };
            int lowestFeasibleOre = Ore.oreList.BinarySearch(0, currentStatistics.HighestOre + 7,
                                                             fakeOreForComparingRpd, new MinDamageComparer());
            int highestFeasibleOre = Ore.oreList.BinarySearch(lowestFeasibleOre, currentStatistics.HighestOre + 7 - lowestFeasibleOre,
                                                              fakeOreForComparingRpd, new MaxDamageComparer());

            if (lowestFeasibleOre < 0)
            {
                lowestFeasibleOre = ~lowestFeasibleOre - 1;
            }
            if (highestFeasibleOre < 0)
            {
                highestFeasibleOre = ~highestFeasibleOre;
            }
            int oreIndexMaxRevenue = highestFeasibleOre;
            Ore oreAtMaxRevenue    = Ore.oreList[oreIndexMaxRevenue];

            oreAtMaxRevenue.UpdateClicks(rawPickDamage);
            //double maxRevenuePerClick = oreAtMaxRevenue.ValuePerClick;
            for (int i = lowestFeasibleOre; i < highestFeasibleOre; i++)
            {
                Ore temp = Ore.oreList[i];
                temp.UpdateClicks(rawPickDamage);
                if (temp.ValuePerClick > oreAtMaxRevenue.ValuePerClick)
                {
                    oreAtMaxRevenue    = temp;
                    oreIndexMaxRevenue = i;
                }
            }
            if (currentStatistics.HighestOre < oreIndexMaxRevenue)
            {
                oreIndexMaxRevenue = currentStatistics.HighestOre;
            }
            clicksForEachVictory = Ore.oreList[oreIndexMaxRevenue].Clicks;
            valueOfEachVictory   = Ore.oreList[oreIndexMaxRevenue].Value;
            return(oreIndexMaxRevenue);
        }
        static IList <Ore> BuildFeasibleOreList(double hpc)
        {
            List <Ore> localOreList = new List <Ore>();
            // double bestValuePerClick = 0;
            Ore fakeOreToFindOneclick = new Ore()
            {
                Defense = 0, Hp = hpc
            };
            int oneClickIndex = Ore.oreList.BinarySearch(fakeOreToFindOneclick, new OreOnehitComparer());

            if (oneClickIndex < 0)
            {
                oneClickIndex = ~oneClickIndex - 1;
            }
            int bextRpc = Ore.OptimalOreForCash(hpc, oneClickIndex);

            // not sure, do I need to update ores here? Or can I just skip up to oneClickIndex and then take until bextRpc?
            for (int i = oneClickIndex; i <= bextRpc; i++)
            {
                Ore.oreList[i].UpdateClicks(hpc);
                localOreList.Add(Ore.oreList[i]);
            }
            return(localOreList);
        }
示例#4
0
        private void ARUPInternal(ClickUpgradePath soFar, double hpc, double currentGps, int af, int ap, int maxItems, List<ClickUpgradePath> retval)
        {
            if (maxItems == 0) return;
#if false
            // gemfinder addition is handled by simulateUpgradePath
            if (!soFar.UpgradeOrder.Contains(UpgradeID.ICGEMFINDER))
            {
                ClickUpgradePath withGemfinder = new ClickUpgradePath(soFar);
                withGemfinder.UpgradeOrder.Add(UpgradeID.ICGEMFINDER);
                retval.AddRange(ARUPInternal(withGemfinder, oldGemsPerSecond, af, ap, gf+1, maxItems - 1,retval));
            }
#endif
            var autoPowerList = Upgrade.ic(UpgradeID.ICAUTOPOWER);
            var autoSpeedList = Upgrade.ic(UpgradeID.ICAUTOSPEED);
            double costOfClickFaster = autoSpeedList[af].nextLevelCost;
            double costOfClickPower = autoPowerList[ap].nextLevelCost;
            bool clickFasterIsCheaper = costOfClickFaster < costOfClickPower;
            double hpcAfterPowerUpgrade = hpc * autoPowerList[ap+1].value/autoPowerList[ap].value; // old hpc * power increment
            // determine which is the optimal ore at that rawdamage level
            double gpsIfYouClickPowerful = Ore.oreList[Ore.OptimalOreForCash(hpcAfterPowerUpgrade, 0)].ValuePerClick * autoSpeedList[af].value;
            double clickFasterEfficiency = 1.0528/costOfClickFaster;
            double clickPowerEfficiency = gpsIfYouClickPowerful/(currentGps*costOfClickPower);
            bool clickFasterIsMoreEfficient = clickFasterEfficiency > clickPowerEfficiency;
            ClickUpgradePath withClickFaster = new ClickUpgradePath(soFar);
            withClickFaster.UpgradeOrder.Add(UpgradeID.ICAUTOSPEED);
            ClickUpgradePath withClickPower = new ClickUpgradePath(soFar);
            withClickPower.UpgradeOrder.Add(UpgradeID.ICAUTOPOWER);
            if (clickFasterIsCheaper || clickFasterIsMoreEfficient)
            {
                ARUPInternal(withClickFaster,hpc,currentGps*1.0528,af+1,ap,maxItems-1,retval);
            }
            if (!clickFasterIsCheaper || !clickFasterIsMoreEfficient)
            {
                ARUPInternal(withClickPower,hpcAfterPowerUpgrade,gpsIfYouClickPowerful,af,ap+1,maxItems-1,retval);
            }
        }
示例#5
0
        public void Calc()
        {
            double bestEfficiency = 0;
            ShoppingCart cartForBestEfficiency = null;
            ClickUpgradePath pathForBestEfficiency = null;
            int gwForBestEfficiency = -1;

            var pathCollection = AllReasonableUpgradePaths();
            var cartCollection = AllReasonableShoppingCarts();
            var pCollection = GetPCollection(); // collection of P values to shoot for

            foreach (var upgradePath in pathCollection)
            {
                IList<ClickUpgradePath.UpgradeSimulationResult> pathSimulationGroup = upgradePath.Simulate(initialStats);
                foreach (ClickUpgradePath.UpgradeSimulationResult pathSimulation in pathSimulationGroup)
                {
                    WealthStatistics pathResult = pathSimulation.w;
                    UpgradeState completedInstantUpgrades = pathSimulation.u;
                    double timeSpent = pathSimulation.timeSpent;
                
                double clicksPerSecond = Upgrade.ic(UpgradeID.ICAUTOSPEED)[completedInstantUpgrades.afLevel].value;
                double gemFinderOdds = Upgrade.ic(UpgradeID.ICGEMFINDER)[completedInstantUpgrades.gfLevel].value;
                double autoPowerMultiplier = Upgrade.ic(UpgradeID.ICAUTOPOWER)[completedInstantUpgrades.apLevel].value;
                foreach (var sc in cartCollection)
                {
                    var costs = sc.TotalCostWithoutAndWithGemwaster();
                    //double timeSpentBuyingBSUpgradesOnceWeHaveEnoughMoney = (sc.NumBBP + sc.NumBF + sc.NumBS + sc.NumBX)/6.5 + (sc.NumBBP>0 ? 1 : 0) + (sc.NumBF<0 ? 1 : 0) + (sc.NumBS>0?1:0)+(sc.NumBX>0?1:0);
                    double efficiencyDiscount = 0.01 * (100 - completedInstantUpgrades.bfLevel - sc.NumBF);
                    foreach (var desiredP in pCollection)
                    {
                        int gw = 0;

                        foreach(var expect in sc.ChancesOfBeatingTargetAndExpectedPsIfYouDo(desiredP)) // each item corresponds to a different gemwaster
                        {
                            double costOfShoppingCart = (gw <= this.initialUpgradeState.gwLevel) ? costs.Item1 : costs.Item2;
                            double averageGemsForOneCraft = ShoppingCart.gwNumberOfGems[gw] * efficiencyDiscount;
                            double failChance = 1-expect.Item1;
                            // need to solve failChance^expectedNumCrafts < .2
                            // n ln failchance < ln .2
                            // n = ln .2 / ln failchance
                            double expectedNumCrafts = lnConfidenceLevel/Math.Log(failChance);
                            double expectedCraftingTime = expectedNumCrafts / 6.5;
                            double gemsRequired = expectedNumCrafts * averageGemsForOneCraft - pathResult.Gems; // still exact
                            // due to linearity of expectation
                            double expectedNeededOresMined = Math.Ceiling(gemsRequired / gemFinderOdds);
                            double hpc = pathResult.IdleActiveMultipliers()*pathResult.CurrentP*autoPowerMultiplier;
                            var miningList = EarnMoney.MiningPlanToEarnSpecifiedGoldAndGems(hpc, costOfShoppingCart, expectedNeededOresMined);
                            double timeSavingUpGoldAndGemsForCraft = miningList.Sum(x => x.Item2 * x.Item1.Clicks)*Upgrade.ic(UpgradeID.ICAUTOSPEED)[completedInstantUpgrades.afLevel].value;
                            double totalTime = timeSpentFollowingUpgradePath
                                + timeSavingUpGoldAndGemsForCraft
                                //+ timeSpentBuyingBSUpgradesOnceWeHaveEnoughMoney // can buy them on-the-run
                                + expectedCraftingTime;
                            pathResult.CurrentP = expect.Item2;
                            int clicksForEachVictory;
                            double valueOfEachVictory;
                            var stats = Ore.OptimalOreForCash( ); completedInstantUpgrades.instant, pathResult, out clicksForEachVictory, out valueOfEachVictory);

                            gw++;
                        }
                    }
                    
                    
                    
                }
                
            }

        }

    }
示例#6
0
        internal void Simulate(WealthStatistics initialStats,
            UpgradeState upgradesWithoutGemfinder,
            UpgradeState upgradesWithGemfinder,
            WealthStatistics wealthWithoutGemfinder,
            IList<WealthStatistics> wealthWithGemfinderBoughtAfterIthUpgrade)
        {
            var retval = new UpgradeSimulationResult[UpgradeOrder.Count + 1];
            List<WealthStatistics> currentStatistics = { new WealthStatistics(initialStats) };
            UpgradeState usWithoutGemfinder = new UpgradeState(us);
            UpgradeState usWithGemfinder;
            bool gfMaxed = usWithoutGemfinder.gfLevel == Upgrade.ic(UpgradeID.ICGEMFINDER).Count - 1;
            int itemsBoughtSoFar = 0;
            double secondsPerClick = 1/Upgrade.ic(UpgradeID.ICAUTOSPEED)[usWithoutGemfinder.afLevel].value;
            double gemsForEachVictoryBefore = Upgrade.ic(UpgradeID.ICGEMFINDER)[usWithoutGemfinder.gfLevel].value;
            double gemsForEachVictoryAfter = gfMaxed ? 0 : Upgrade.ic(UpgradeID.ICGEMFINDER)[usWithoutGemfinder.gfLevel + 1].value;
            int ore = -1;
            uint clicksForEachVictory=0;
            double timeForEachVictory = 0;
            double valueOfEachVictory=0;
            while (itemsBoughtSoFar < UpgradeOrder.Count)
            {
                UpgradeID pendingItem = _upgradeOrder[itemsBoughtSoFar];
                int upgradeLevelOfPendingItem = usWithoutGemfinder.instant[(int)pendingItem&127];

                Upgrade nextUpgrade = Upgrade.ic(pendingItem)[upgradeLevelOfPendingItem];
                double nextLevelCost = nextUpgrade.nextLevelCost;
                foreach (
                while (currentStatistics.Any(x=>x.Gold < nextLevelCost))
                {
                    if (ore == -1)
                    {
                        RecomputeOre(x, usWithoutGemfinder, secondsPerClick, out clicksForEachVictory, out valueOfEachVictory, out ore, out timeForEachVictory);
                    } 
                    currentStatistics.ForEach(x=>
                    {
                        x.Gold += valueOfEachVictory;
                        x.Gems += something ? gemsForEachVictoryBefore : gemsForEachVictoryAfter;
                        x.dataXp += clicksForEachVictory;
                        x.dataAge.Add(timeForEachVictory);
                    timeSpent += timeForEachVictory;
                    if (currentStatistics.dataXp > currentStatistics.dataXpThreshold || currentStatistics.dataAge.Sum() > currentStatistics.dataAgeThreshold)
                    {
                        currentStatistics.setThresholds();
                        ore = -1; // or recompute now
                    }
                    if (ore == currentStatistics.HighestOre)
                    {
                        currentStatistics.HighestOre++;
                        ore = -1; // or recompute now
                    }
                    if (ore == -1 && currentStatistics.Gold < nextLevelCost)
                    {
                        RecomputeOre(currentStatistics, usWithoutGemfinder, secondsPerClick, out clicksForEachVictory, out valueOfEachVictory, out ore, out timeForEachVictory);
                    }
                }

                // TODO: Handle this with a dictionary or list of delegates
                switch (pendingItem)
                {
                    case UpgradeID.ICAUTOSPEED:
                        usWithoutGemfinder.afLevel++;
                        secondsPerClick = Upgrade.ic(UpgradeID.ICAUTOSPEED)[usWithoutGemfinder.afLevel].value;
                        timeForEachVictory = clicksForEachVictory * secondsPerClick;
                        break;
                    case UpgradeID.ICAUTOPOWER:
                        usWithoutGemfinder.apLevel++;
                        ore = Ore.ComputeMostLucrativeOre(usWithoutGemfinder.instant, currentStatistics, out clicksForEachVictory, out valueOfEachVictory);
                        timeForEachVictory = clicksForEachVictory * secondsPerClick;
                        break;
                    case UpgradeID.ICGEMFINDER:
                        usWithoutGemfinder.gfLevel++;
                        gemsForEachVictoryBefore = Upgrade.ic(UpgradeID.ICGEMFINDER)[usWithoutGemfinder.gfLevel].value;
                        break;
                }
                currentStatistics.Gold -= nextLevelCost;
                timeSpent += 1.0; // it takes some time to click
                itemsBoughtSoFar++;
            }
            foreach (UpgradeSimulationResult thing in retval)
            {
                thing.u = usWithGemfinder;
            }
            retval[retval.Length()-1].u = usWithoutGemfinder;
            retval[retval.Length()-1].w = currentStatistics;
            return Tuple.Create(currentStatistics,usWithoutGemfinder);
        }
示例#7
0
 private static void RecomputeOre(WealthStatistics currentStatistics, UpgradeState currentUpgradeState, double secondsPerClick, out uint clicksForEachVictory, out double valueOfEachVictory, out int ore, out double timeForEachVictory)
 {
     ore = Ore.ComputeMostLucrativeOre(currentUpgradeState.instant, currentStatistics, out clicksForEachVictory, out valueOfEachVictory);
     timeForEachVictory = VictorySeconds(secondsPerClick, clicksForEachVictory);
 }