Pārlūkot izejas kodu

shipbuilding: calculate consumables cost

raylu 1 nedēļu atpakaļ
vecāks
revīzija
a2059c0dcb
1 mainītis faili ar 42 papildinājumiem un 8 dzēšanām
  1. 42 8
      ts/shipbuilding.ts

+ 42 - 8
ts/shipbuilding.ts

@@ -44,7 +44,7 @@ async function render() {
 		throw new Error('missing shipbuilding container');
 	main.innerHTML = '<p>Loading...</p>';
 
-	const [allPrices, recipes, buildings, knownCompanies, companyProductionById] = await Promise.all([
+	const [allPrices, recipes, buildingList, knownCompanies, companyProductionById] = await Promise.all([
 		cachedFetchJSON('https://refined-prun.github.io/refined-prices/all.json') as Promise<RawPrice[]>,
 		recipeForMats(),
 		cachedFetchJSON('https://api.prunplanner.org/data/buildings/') as Promise<Building[]>,
@@ -53,6 +53,7 @@ async function render() {
 	]);
 	const prices = Object.fromEntries(allPrices.filter((price) => price.ExchangeCode === 'IC1')
 			.map((price) => [price.MaterialTicker, price]));
+	const buildings = Object.fromEntries(buildingList.map((b) => [b.building_ticker, b]));
 
 	const production: Production = {};
 	const extract: Record<string, number> = {};
@@ -72,7 +73,7 @@ async function render() {
 			requiredMats[mat] = (requiredMats[mat] ?? 0) + amount;
 
 	const expertiseGroups: Record<string, string[]> = {};
-	for (const building of buildings) {
+	for (const building of buildingList) {
 		if (!(building.building_ticker in production))
 			continue;
 		if (!expertiseGroups[building.expertise])
@@ -84,7 +85,7 @@ async function render() {
 	main.append(
 		renderAnalysis(analysisNodes),
 		element('p', {textContent: `total cost: ${formatWhole(cost)}`}),
-		renderProduction(expertiseGroups, production, prices, recipes),
+		renderProduction(expertiseGroups, production, prices, recipes, buildings),
 		renderMatList('extract', extract),
 		renderMatList('buy', buy),
 		renderShipbuilders(requiredMats, knownCompanies, companyProductionById),
@@ -239,14 +240,36 @@ function renderAnalysisNode(node: AnalysisNode, level = 0): HTMLElement {
 	return el;
 }
 
-function renderProduction(expertiseGroups: Record<string, string[]>, production: Production,
-		prices: Record<string, RawPrice>, recipes: Record<string, Recipe>): HTMLElement {
+const WORKER_CONSUMPTION: Record<'pioneers' | 'settlers' | 'technicians' | 'engineers' | 'scientists', Record<string, number>> = {
+	pioneers: {'COF': 0.5, 'DW': 4, 'RAT': 4, 'OVE': 0.5, 'PWO': 0.2},
+	settlers: {'DW': 5, 'RAT': 6, 'KOM': 1, 'EXO': 0.5, 'REP': 0.2, 'PT': 0.5},
+	technicians: {'DW': 7.5, 'RAT': 7, 'ALE': 1, 'MED': 0.5, 'SC': 0.1, 'HMS': 0.5, 'SCN': 0.1},
+	engineers: {'DW': 10, 'MED': 0.5, 'GIN': 1, 'FIM': 7, 'VG': 0.2, 'HSS': 0.2, 'PDA': 0.1},
+	scientists: {'DW': 10, 'MED': 0.5, 'WIN': 1, 'MEA': 7, 'NST': 0.1, 'LC': 0.2, 'WS': 0.05},
+};
+
+function buildingDailyCost(building: Building, prices: Record<string, RawPrice>): number {
+	let cost = 0;
+	for (const [workerType, mats] of Object.entries(WORKER_CONSUMPTION)) {
+		const workers = building[workerType as keyof typeof WORKER_CONSUMPTION];
+		for (const [mat, per100] of Object.entries(mats)) {
+			const price = prices[mat].VWAP30D;
+			if (price == null) throw new Error(`no price for ${mat}`);
+			cost += price * workers * per100 / 100;
+		}
+	}
+	return cost;
+}
+
+function renderProduction(expertiseGroups: Record<string, string[]>, production: Production, prices: Record<string, RawPrice>,
+	recipes: Record<string, Recipe>, buildings: Record<string, Building>): HTMLElement {
 	const section = element('section');
 	section.append(element('h2', {textContent: 'production'}));
 
-	for (const [expertise, buildings] of Object.entries(expertiseGroups)) {
+	let totalConsumablesCost = 0;
+	for (const [expertise, productionBuildings] of Object.entries(expertiseGroups)) {
 		section.append(element('h3', {textContent: expertise}));
-		for (const building of buildings) {
+		for (const building of productionBuildings) {
 			const buildingMats = element('div');
 			const mats = Object.entries(production[building]);
 			let buildingMins = 0;
@@ -265,12 +288,17 @@ function renderProduction(expertiseGroups: Record<string, string[]>, production:
 				buildingMins += amount / outputPerRun * (recipe.time_ms / 1000 / 60);
 			}
 			const numBuildings = buildingMins / (24*60) / 5 / 1.605; // one ship every 5 days, 160.5% efficiency
-			const buildingRow = element('div', {className: 'building-row', textContent: `${formatFixed(numBuildings, 1)}x${building}`});
+			const consumablesCost = buildingDailyCost(buildings[building], prices) * Math.round(Math.max(1, numBuildings));
+			totalConsumablesCost += consumablesCost;
+			const buildingRow = element('div', {className: 'building-row',
+				textContent: `${formatFixed(numBuildings, 1)}x${building} (${formatWhole(consumablesCost)}/d)`});
 			buildingRow.append(buildingMats);
 			section.append(buildingRow);
 		}
 	}
 
+	section.append(element('h4', {textContent: `total consumables cost: ${formatWhole(totalConsumablesCost)}/day,
+			${formatWhole(totalConsumablesCost * 5)}/ship`}));
 	return section;
 }
 
@@ -319,12 +347,18 @@ interface RawPrice {
 	ExchangeCode: string
 	Ask: number | null
 	AverageTraded30D: number | null
+	VWAP30D: number | null
 	Supply: number
 }
 
 interface Building {
 	building_ticker: string
 	expertise: string
+	pioneers: number
+	settlers: number
+	technicians: number
+	engineers: number
+	scientists: number
 }
 
 type PMMGCompanyProduction = Record<string, Record<string, {amount: number}>>;