Closed sterlind closed 3 months ago
Yep, definitely a regression. Commits prior to 0d448ca29e9cc8fba380d47fc8aaa657bd7a8eed show Coal Power Generation producing 9 electricity and 9 pollution, while commits after show zero for both.
Actually, even as far back as 0d448ca, the bug seems to manifest in some energy: For example, this shows 0/0 (despite accounting for 25%), but coal works:
Actually, I think the problems even begin with 2eaa5575eda4558f6283f73ea833606643fabcc2. At this commit, the game still starts with a production shortage of electricity, and natural gas is 0/0. However, going back to the commit prior to that (15f3f51ed94b9e08af4ae0f0b7fcb1712c657972) fixes electricity stats:
you can see here it's 6/3 instead of 0/0 like above.
Thanks for letting me know and for figuring out where things changed. I'll try to sort this out soon.
@frnsys so yesterday I did some debugging. Commit 2eaa5575eda4558f6283f73ea833606643fabcc2 did introduce bad coefficients in content.rs
, but it really just exposed another bug, which causes processes to silently stop producing with no apparent cause. I will explain and propose a fix.
Here's my high-level understanding of how simulation steps work:
On each simulation step, Game::simulate()
-> State::step_production()
-> State::update_production()
-> State::update_demand()
is called, which:
pub fn update_demand(&mut self) {
let (output_demand, resources_demand) = self.calculate_demand();
self.output_demand = output_demand;
self.resources_demand = resources_demand;
calculate_demand()
ProductionOrder
for each process, to produce the demanded resources based on each process's mix share:
let orders: Vec<ProductionOrder> = self.processes.iter()
.map(|p| p.production_order(&self.output_demand)).collect();
This is done in two passes, with the second pass factoring in additional fuel/electricity demanded by other processes, and values are tweaked based on game state and flags, but the details aren't important.
Once demand is calculated, production is calculated:
// Run production function
let (produced_by_process,
produced_by_type,
consumed_resources,
consumed_feedstocks,
byproducts) = produce(&orders, &self.resources, &self.feedstocks);
let r = process.adj_resources();
let resource_score: f32 = r.items().iter().map(|(k, v)| *v/(resources[*k] + 1.)).sum();
resource_scores.push(resource_score);
let f = process.adj_feedstock_amount();
let feedstock_score = f/(feedstocks[process.feedstock.0] + 1.);
feedstock_scores.push(feedstock_score);
scores.insert(*i, (resource_score, feedstock_score));
Production orders are sorted by these scores. Heavy processes that use the most resources come first:
// Sort so that the best (lowest) scoring are at the end
indices.sort_by_cached_key(|i| {
let (r, f) = scores.get(i).unwrap();
let resource_score = r/max_resource_score;
let feedstock_score = f/max_feedstock_score;
...
let score = feedstock_score + resource_score + byproduct_score;
// Hacky
-((score * 100000.).round() as isize)
});
available_resources
, along with feedstock usage: let amount = produce_amount(
&orders[order_idx],
&mut resources,
&mut feedstocks,
&mut produced_byproducts);
produced[order_idx] = amount;
So to recap, this is a greedy algorithm which selects the process with the highest resource utilization, and applies it. However, it makes terrible decisions handling resource shortages! For example, consider a run with a land shortage, Industrial Livestock Ag and Nuclear Power. Livestock is applied first, since it wants to use >100% of the available land. Now there's zero land left over, so Nuclear Power fails to satisfy any of its production order, since it requires a tiny amount of land. In fact, every process requiring any land will now fail, since cows are on every scrap of earth that hasn't been turned into a national park!
To fix this, I propose inverting the sort order, to put the resource hogs last. ...There's also the optimal solution, which is to use Linear Programming:
The amount of resource $r$ consumed is $\sump [A{rp} xp]$. The gross amount of resource $r$ produced is $\sum{p \in P(r)} xp$. Therefore, the net amount of resource $r$ produced is $\sum{p \in P(r)} [x_p] - \sumq [A{rq} x_q]$. So the objective is to minimize how much net production falls short of resource demands, i.e.
min $\sum_r [D_r - f_r]$, such that:
- $0 \le x_p \le M_p D_r$, for $p \in P(r)$ (process $p$ is non-negative and can't exceed its mix ratio.)
- $\sump A{rp} x_p \le T_r$, if $r$ is an input resource.
- $fr = \sum{p \in P(r)} [x_p - \sumq [A{rq} x_q]]$, if $r$ is an output resource (define net production.)
- $0 \le f_r (\le D_r)$, if $r$ is an output resource (can't consume more fuel, electricity than produced. Guaranteed to be bounded by $D_r$ due to the mix ratio constraint, but I restated for clarity.)
Note that we don't differentiate between feedstocks and natural resources - both are input resources, feedstocks just have no intrinsic demand. Also note that intermediate consumption of resources (e.g. farms requiring electricity) is handled here, so it should not be added to the demands.
I hope this doesn't look like a lot of math - LPs are actually pretty easy to write. But it's probably more work than flipping a sign (if that works!)
Also, there's an additional UI bug where only resources with limits defined (e.g. vertical farms, hydropower) will show red bars if production shortfalls occur. That's why the 0/0 on nuclear was so mysterious to me. It'd also be nice to highlight which resource fell short. But I didn't have time to look into fixing that.
I am also seeing some odd behavior with the game in line with this ticket.
Amazing work, thank you so much for doing all this investigating! Looking back on the commit you highlighted it does look like somehow some of the values are using the wrong units, especially the Chemical and Concrete industries. I'm adjusting those to the correct scale and also flip the scoring ordering for now...if you have a moment please give it a try and let me know if it helps. I'll look more into the other issues you raised. We were originally going with a linear programming approach but ended up abandoning it, I can't recall why.
I am still seeing some cards with zero values (vertical farming as an example). Is this intended behavior?
@frnsys Unfortunately, I think something else regressed. After the first planning session, emissions rise significantly regardless of what you do. The Hero saves your first turn, but there's ultimately no recovering. Also, biofuels are now actually worse than petroleum on emissions, and even blue hydrogen has nearly max pollution. Maybe the numbers you're using for biofuels don't include the CO2 absorbed during production? I don't think the earlier version I played had this error.
Is there a last-known-good commit you could revert to, maybe? One where the game's known to be relatively playable? That way we can have a working version of the site while we look into a proper fix.
I have some time today so I'm going to try and narrow down the config values that are causing these problems. I'll keep you updated
I think these problems may be due to the re-worked biodiversity numbers. I suspect that it's easier to max out biodiversity pressure which is for some reason treated as a "resource" which is limiting process outputs. It's been awhile since I looked closely at the code so I need to confirm that this is the cause, but bumping up the max biodiversity pressure to something much higher seems to resolve the production problems.
Doesn't seem to be biodiversity-related...just to check--@sterlind and @ferninabsurdism are you still seeing the issues in a new game?
The issue with The Ark event was biodiversity related, I have an adjustment that will fix that ready. I'm having trouble re-producing the production-related problems and the only reason I can think of is that saved games use the parameters from when the game was saved, and not whatever the most recent ones are. If you still see the issues (after I update in just a few min) after a new game, let me know and I'll take another look.
Day 1 starts with a critical electricity shortage. Coal shows zero energy production and zero pollution. Petroleum later stops working for no discernible reason.
Also, 93% of energy usage is due to "chemical." It's not clear to me what "chemical" is or how to fix it.
I could have sworn that just a few days ago when I discovered this game, there weren't these issues. It becomes nearly impossible to progress past term 1 due to anger over critical shortages tanking public opinion.