Prechádzať zdrojové kódy

roi: include habitation area and capex

raylu 15 hodín pred
rodič
commit
bcd3176086
3 zmenil súbory, kde vykonal 30 pridanie a 11 odobranie
  1. 25 6
      roi.py
  2. 3 3
      ts/roi.ts
  3. 2 2
      www/index.html

+ 25 - 6
roi.py

@@ -15,16 +15,29 @@ def main() -> None:
 		p['MaterialTicker']: Price(p['VWAP7D'], p['AverageTraded7D']) for p in raw_prices # pyright: ignore[reportArgumentType]
 		if p['ExchangeCode'] == 'IC1' and p['VWAP7D'] is not None
 	}
+	habitation: typing.Mapping[Worker, str] = {
+		'Pioneers': 'HB1',
+		'Settlers': 'HB2',
+		'Technicians': 'HB3',
+		'Engineers': 'HB4',
+		'Scientists': 'HB5',
+	}
+	hab_area_cost: dict[Worker, float] = {}
+	hab_capex: dict[Worker, float] = {}
+	for worker, hab in habitation.items():
+		hab_area_cost[worker] = buildings[hab]['AreaCost'] / 100
+		hab_capex[worker] = building_construction_cost(buildings[hab], prices) / 100
 
 	profits: list[Profit] = []
 	for recipe in recipes:
-		if profit := calc_profit(recipe, buildings, materials, prices):
+		if profit := calc_profit(recipe, buildings, hab_area_cost, hab_capex, materials, prices):
 			profits.append(profit)
 	profits.sort()
 	with open('www/roi.json', 'w') as f:
 		json.dump([dataclasses.asdict(p) for p in profits], f, indent='\t')
 
-def calc_profit(recipe: Recipe, buildings: typing.Mapping[str, Building], materials: typing.Mapping[str, Material],
+def calc_profit(recipe: Recipe, buildings: typing.Mapping[str, Building], hab_area_cost: typing.Mapping[Worker, float],
+		hab_capex: typing.Mapping[Worker, float], materials: typing.Mapping[str, Material],
 		prices: typing.Mapping[str, Price]) -> Profit | None:
 	try:
 		(output,) = recipe['Outputs']
@@ -37,8 +50,9 @@ def calc_profit(recipe: Recipe, buildings: typing.Mapping[str, Building], materi
 		return
 	revenue = output_price.vwap * output['Amount']
 	building = buildings[recipe['BuildingTicker']]
-	capex = sum(bm['Amount'] * prices[bm['CommodityTicker']].vwap
-			for bm in building['BuildingCosts'])
+	area = building['AreaCost'] + sum(hab_area_cost[worker] * building[worker] for worker in hab_area_cost)
+	capex = building_construction_cost(building, prices) + \
+		sum(hab_capex[worker] * building[worker] for worker in hab_capex)
 	profit_per_run = revenue - cost
 	runs_per_day = 24 * 60 * 60 * 1000 / recipe['TimeMs']
 	if building['Ticker'] in ('FRM', 'ORC'):
@@ -51,17 +65,20 @@ def calc_profit(recipe: Recipe, buildings: typing.Mapping[str, Building], materi
 		sum(materials[input['Ticker']]['Volume'] * input['Amount'] for input in recipe['Inputs']),
 		materials[output['Ticker']]['Weight'] * output['Amount'],
 		materials[output['Ticker']]['Volume'] * output['Amount'],
-	) * runs_per_day / building['AreaCost']
+	) * runs_per_day / area
 	return Profit(output['Ticker'], recipe['RecipeName'],
 			expertise=building['Expertise'].replace('_', ' ').lower(),
 			profit_per_day=(profit_per_run * runs_per_day - worker_consumable_daily_cost),
-			area=building['AreaCost'],
+			area=area,
 			capex=capex,
 			cost_per_day=cost_per_day,
 			logistics_per_area=logistics_per_area,
 			output_per_day=output_per_day,
 			average_traded_7d=output_price.average_traded_7d)
 
+def building_construction_cost(building: Building, prices: typing.Mapping[str, Price]) -> float:
+	return sum(bc['Amount'] * prices[bc['CommodityTicker']].vwap for bc in building['BuildingCosts'])
+
 def building_daily_cost(building: Building, prices: typing.Mapping[str, Price]) -> float:
 	consumption = {
 		'Pioneers': [('COF', 0.5), ('DW', 4), ('RAT', 4), ('OVE', 0.5), ('PWO', 0.2)],
@@ -77,6 +94,8 @@ def building_daily_cost(building: Building, prices: typing.Mapping[str, Price])
 			cost += prices[mat].vwap * workers * per_100 / 100
 	return cost
 
+Worker = typing.Literal['Pioneers', 'Settlers', 'Technicians', 'Engineers', 'Scientists']
+
 class Recipe(typing.TypedDict):
 	RecipeName: str
 	BuildingTicker: str

+ 3 - 3
ts/roi.ts

@@ -22,9 +22,9 @@ async function render() {
 		tr.innerHTML = `
 			<td>${p.output}</td>
 			<td>${p.expertise}</td>
-			<td style="color: ${color(profit_per_area, 0, 300)}">${formatDecimal(profit_per_area)}</td>
-			<td><span style="color: ${color(break_even, 30, 2)}">${formatDecimal(break_even)}</span>d</td>
-			<td style="color: ${color(p.capex, 300_000, 50_000)}">${formatWhole(p.capex)}</td>
+			<td style="color: ${color(profit_per_area, 0, 250)}">${formatDecimal(profit_per_area)}</td>
+			<td><span style="color: ${color(break_even, 30, 3)}">${formatDecimal(break_even)}</span>d</td>
+			<td style="color: ${color(p.capex, 300_000, 40_000)}">${formatWhole(p.capex)}</td>
 			<td style="color: ${color(p.cost_per_day, 40_000, 1_000)}">${formatWhole(p.cost_per_day)}</td>
 			<td style="color: ${color(p.logistics_per_area, 2, 0.2)}">${formatDecimal(p.logistics_per_area)}</td>
 			<td>

+ 2 - 2
www/index.html

@@ -16,9 +16,9 @@
 				<tr>
 					<th>wrought<br>product</th>
 					<th>expertise</th>
-					<th>daily<br>profit/area</th>
+					<th data-tooltip="area includes worker habitation">daily<br>profit/area</th>
 					<th>break<br>even</th>
-					<th data-tooltip="construction cost of 1 building">capex</th>
+					<th data-tooltip="construction cost of 1 building and fractional habitation">capex</th>
 					<th data-tooltip="input and worker costs of 1 building (deterioration/repair not included)">daily<br>opex</th>
 					<th data-tooltip="max of input and output t and m³ per area. 2 ≅ 2 SCB visits/day. 0.25 ≅ SCB visit every 4 days">logistics</th>
 					<th data-tooltip="units output by 1 building over average daily traded">daily output<br>traded</th>