Krzysd / Matter Of Scale

// ==UserScript==
// @name         Matter Of Scale
// @namespace    dont have one
// @version      0.1
// @description  Script written by https://www.reddit.com/user/ZeroNihilist
// @author       Reddit User ZeroNihilist
// @domain      astarsearcher.com
// ==/UserScript==

// This script was written by Reddit User ZeroNihilist, I do not take credit for this, I only made it into a user script which can be used with Tampermonkey/Greasemonkey.



goalBuildingBloodhoundCount = 90;
exponentialIgnoreBuildings = 40;
levelTimeExponent = 1.15;

goalBuildingEquivalence =
	function(level, bid)
	{
		//we want every combination to take approximately as long as n bloodhounds + 15% longer (cumulative) per level
		//i.e. level 0 is T(n bh)*1.15^0, level 1 is T(n bh)*1.15^1, level 2 is T(n bh)*1.15^2, etc.
		//note that this is an idealised calculation, not factoring in real concerns like tick rate, lost money (if any), etc.
		var timeBloodhounds = goalBuildingTime(0, 0, goalBuildingBloodhoundCount);
		var timeLevel = timeBloodhounds*Math.pow(levelTimeExponent, level);
		//we want to converge on the right time by binary search
		//could possibly do it directly with a formula, but this is easier to program
		var low = 1;
		var high = 500; //very difficult to actually exceed, so it serves as a suitable upper bound
		//note with these values it is guaranteed to take 9 iterations
		while(high - low > 1)
		{
			var middle = Math.ceil((low + high)/2);
			var time = goalBuildingTime(level, bid, middle);
			if(time > timeLevel)
			{
				high = middle;
			}
			else
			{
				low = middle;
			}
		}
		return low;
	};

goalBuildingTime =
	function(level, bid, amount)
	{
		var baseCost = leveldata[level].buildings[bid].cost;
		var purchaseRate = (bid + 1)*(bid + 1);
		var exponent = 1.1 - 0.008*bid; //so in range [1.1, 1.028]
		var numIgnored = Math.min(amount, exponentialIgnoreBuildings);
		var numExponential = amount - numIgnored;
		
		var ignoredCost = baseCost*numIgnored;
		var exponentialCost = baseCost*(1 - Math.pow(exponent, numExponential))/(1 - exponent);
		var cost = ignoredCost + exponentialCost;
		return cost/purchaseRate;
	};

GoalBuildOne.prototype.create =
	function(level)
	{
		this.level = level;
		this.bid = index_roll(Math.random(), [1.000, 0.531, 0.375, 0.281, 0.214, 0.162, 0.120, 0.083, 0.052, 0.025]);
		//default is: [1, 1/3, 1/5, 1/7, 1/9, 1/11, 1/13, 1/15, 1/17, 1/19]);
		//delta between adjacent terms (and hence probability of picking them) corresponds to the original weightings
		this.count = goalBuildingEquivalence(this.level, this.bid);
	};

GoalBuildingIncome.prototype.create =
	function(level)
	{
		this.level = level;
		this.bid = index_roll(Math.random(), [1.000, 0.531, 0.375, 0.281, 0.214, 0.162, 0.120, 0.083, 0.052, 0.025]);
		//default is the same as for GoalBuildOne
		//hence the adjusted values are the same too
		this.income = Math.floor(leveldata[this.level].buildings[this.bid].income*goalBuildingEquivalence(this.level, this.bid));
		//default is: income*(200 - 20*bid + 100*level) = income*20*(10 - bid + 5*level)
		//meaning you need to build (with no upgrades) 20 tier 10 buildings + 100 per level to complete a tier 10 objective (i.e. you need 320 to do it for a city)
	};

GoalBuildAll.prototype.create =
	function(level)
	{
		this.min = 0;
		this.max = 4;
		this.count = goalBuildingEquivalence(level, this.max);
	};