|
@@ -70,6 +70,13 @@ async function _render(planetName: string, pop: Pop) {
|
|
|
const lastPOPRts = Math.floor(new Date(lastPOPR.ReportTimestamp).getTime() / 1000);
|
|
const lastPOPRts = Math.floor(new Date(lastPOPR.ReportTimestamp).getTime() / 1000);
|
|
|
const nextPOPRts = lastPOPRts + 7 * 24 * 60 * 60;
|
|
const nextPOPRts = lastPOPRts + 7 * 24 * 60 * 60;
|
|
|
|
|
|
|
|
|
|
+ let currentPop = 0;
|
|
|
|
|
+ if (pop == 'pio') currentPop = lastPOPR.NextPopulationPioneer;
|
|
|
|
|
+ else if (pop == 'set') currentPop = lastPOPR.NextPopulationSettler;
|
|
|
|
|
+ else if (pop == 'tec') currentPop = lastPOPR.NextPopulationTechnician;
|
|
|
|
|
+ else if (pop == 'eng') currentPop = lastPOPR.NextPopulationEngineer;
|
|
|
|
|
+ else if (pop == 'sci') currentPop = lastPOPR.NextPopulationScientist;
|
|
|
|
|
+
|
|
|
const siteCount = siteCounts[0].Count;
|
|
const siteCount = siteCounts[0].Count;
|
|
|
|
|
|
|
|
const totalNeeds: Record<Need, number> = {
|
|
const totalNeeds: Record<Need, number> = {
|
|
@@ -151,7 +158,7 @@ async function _render(planetName: string, pop: Pop) {
|
|
|
</tr>
|
|
</tr>
|
|
|
</table>
|
|
</table>
|
|
|
|
|
|
|
|
- <h2>POPI</h2>
|
|
|
|
|
|
|
+ <h2>current POPI</h2>
|
|
|
<table>
|
|
<table>
|
|
|
<tr>
|
|
<tr>
|
|
|
${infras.map((infra) => {
|
|
${infras.map((infra) => {
|
|
@@ -165,17 +172,28 @@ async function _render(planetName: string, pop: Pop) {
|
|
|
}).join('')}
|
|
}).join('')}
|
|
|
</tr>
|
|
</tr>
|
|
|
</table>
|
|
</table>
|
|
|
|
|
+ current projected ${pop.toUpperCase()} happiness:
|
|
|
|
|
+ ${formatPct(projectedHappiness(pop, totalNeeds, siteCount, currentPOPIFilled))}
|
|
|
|
|
|
|
|
<h2>options</h2>
|
|
<h2>options</h2>
|
|
|
- current projected ${pop} happiness: ${formatPct(projectedHappiness(pop, totalNeeds, siteCount, currentPOPIFilled))}
|
|
|
|
|
<table class="options">
|
|
<table class="options">
|
|
|
- ${paretoFront(pop, totalNeeds, siteCount, currentPOPIFilled, prices).map((result) => {
|
|
|
|
|
- return `<tr>
|
|
|
|
|
- <td>${[...result.config.entries()].map(([building, fill]) => `${building}: ${fill.numMats}`).join(', ')}</td>
|
|
|
|
|
- <td>${formatPct(result.happiness)}</td>
|
|
|
|
|
- <td>${formatNum(result.cost)}/day</td>
|
|
|
|
|
- </tr>`;
|
|
|
|
|
- }).join('')}
|
|
|
|
|
|
|
+ <tr>
|
|
|
|
|
+ <th>config</th>
|
|
|
|
|
+ <th>projected migration</th>
|
|
|
|
|
+ <th>cost/day</th>
|
|
|
|
|
+ <th>unit cost</th>
|
|
|
|
|
+ </tr>
|
|
|
|
|
+ ${paretoFront(pop, totalNeeds, siteCount, currentPOPIFilled, currentPop, prices).map((result) => {
|
|
|
|
|
+ let unitCost = '';
|
|
|
|
|
+ if (result.cost > 0)
|
|
|
|
|
+ unitCost = formatNum(result.cost / result.migration);
|
|
|
|
|
+ return `<tr>
|
|
|
|
|
+ <td>${[...result.config.entries()].map(([building, fill]) => `${building}: ${fill.numMats}`).join(', ')}</td>
|
|
|
|
|
+ <td>${formatDelta(result.migration)}</td>
|
|
|
|
|
+ <td>${formatNum(result.cost)}</td>
|
|
|
|
|
+ <td>${unitCost}</td>
|
|
|
|
|
+ </tr>`;
|
|
|
|
|
+ }).join('')}
|
|
|
</table>
|
|
</table>
|
|
|
`;
|
|
`;
|
|
|
}
|
|
}
|
|
@@ -185,9 +203,9 @@ const formatPct = new Intl.NumberFormat(undefined, {style: 'percent', maximumFra
|
|
|
|
|
|
|
|
function formatDelta(n: number, withPlus: boolean = true): string {
|
|
function formatDelta(n: number, withPlus: boolean = true): string {
|
|
|
if (n > 0)
|
|
if (n > 0)
|
|
|
- return `<span class="positive">${withPlus ? '+' : ''}${n}</span>`;
|
|
|
|
|
|
|
+ return `<span class="positive">${withPlus ? '+' : ''}${formatNum(n)}</span>`;
|
|
|
else if (n < 0)
|
|
else if (n < 0)
|
|
|
- return `<span class="negative">${n}</span>`;
|
|
|
|
|
|
|
+ return `<span class="negative">${formatNum(n)}</span>`;
|
|
|
else
|
|
else
|
|
|
return n.toString();
|
|
return n.toString();
|
|
|
}
|
|
}
|
|
@@ -230,21 +248,28 @@ function calcPOPIFilled(infra: Infrastructure): number | null {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function paretoFront(pop: Pop, totalNeeds: Record<Need, number>, siteCount: number, currentPOPIFilled: POPIFill,
|
|
function paretoFront(pop: Pop, totalNeeds: Record<Need, number>, siteCount: number, currentPOPIFilled: POPIFill,
|
|
|
- prices: Map<string, number>): {config: POPIFill, happiness: number, cost: number}[] {
|
|
|
|
|
- const results: {config: POPIFill, happiness: number, cost: number}[] = [];
|
|
|
|
|
|
|
+ currentPop: number, prices: Map<string, number>): {config: POPIFill, migration: number, cost: number}[] {
|
|
|
|
|
+ const results: {config: POPIFill, migration: number, cost: number}[] = [];
|
|
|
for (const config of popiFillCombinations(currentPOPIFilled)) {
|
|
for (const config of popiFillCombinations(currentPOPIFilled)) {
|
|
|
const happiness = projectedHappiness(pop, totalNeeds, siteCount, config);
|
|
const happiness = projectedHappiness(pop, totalNeeds, siteCount, config);
|
|
|
|
|
+ let migration = 0;
|
|
|
|
|
+ if (happiness > 0.7)
|
|
|
|
|
+ migration = currentPop * (happiness - 0.7);
|
|
|
|
|
+ else if (happiness < 0.5)
|
|
|
|
|
+ migration = 0.8 * currentPop * (happiness - 0.5);
|
|
|
|
|
+ // TODO: education
|
|
|
|
|
+
|
|
|
let cost = calcCost(config, prices);
|
|
let cost = calcCost(config, prices);
|
|
|
// is any result better than this one?
|
|
// is any result better than this one?
|
|
|
- if (results.some((result) => (result.happiness >= happiness && result.cost < cost) ||
|
|
|
|
|
- (result.happiness > happiness && result.cost <= cost)))
|
|
|
|
|
|
|
+ if (results.some((result) => (result.migration >= migration && result.cost < cost) ||
|
|
|
|
|
+ (result.migration > migration && result.cost <= cost)))
|
|
|
continue;
|
|
continue;
|
|
|
// are any results worse than this one?
|
|
// are any results worse than this one?
|
|
|
for (let i = results.length - 1; i >= 0; i--)
|
|
for (let i = results.length - 1; i >= 0; i--)
|
|
|
- if ((results[i].happiness <= happiness && results[i].cost > cost) ||
|
|
|
|
|
- (results[i].happiness < happiness && results[i].cost >= cost))
|
|
|
|
|
|
|
+ if ((results[i].migration <= migration && results[i].cost > cost) ||
|
|
|
|
|
+ (results[i].migration < migration && results[i].cost >= cost))
|
|
|
results.splice(i, 1);
|
|
results.splice(i, 1);
|
|
|
- results.push({config, happiness, cost});
|
|
|
|
|
|
|
+ results.push({config, migration, cost});
|
|
|
}
|
|
}
|
|
|
return results;
|
|
return results;
|
|
|
}
|
|
}
|