Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rebalance Food Weights #12582

Closed
wants to merge 75 commits into from
Closed
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
1199aaa
Initial rework
itanasi Nov 14, 2024
c3d91d7
Reformat weights so we have AI vs Human
itanasi Nov 15, 2024
4f3f5df
New mods and Focus
itanasi Nov 16, 2024
07b5048
Automation and Sim updates
itanasi Dec 3, 2024
28c190b
Finalize weights
itanasi Dec 6, 2024
d745b10
Crop images (#12583)
itanasi Dec 6, 2024
67ce623
Fixed battle animation crash (#12585)
yairm210 Dec 6, 2024
a84cdd4
4.14.13-patch1
yairm210 Dec 6, 2024
d06b2f3
Refactor into separate function
itanasi Dec 8, 2024
1b0aa74
Cleanup
itanasi Dec 8, 2024
c503c35
Cleanup 2
itanasi Dec 8, 2024
e143c76
Resolved #12601 - "Unit built" notification selects the built unit
yairm210 Dec 8, 2024
43f8ba4
Resolved #12611 - AI can move air units with "Cannot move" unique
yairm210 Dec 8, 2024
6a63b6f
Resolved #12612 - Display city state type name for battle bonuses
yairm210 Dec 8, 2024
75fc42e
Fix tests, unresolve #12611
yairm210 Dec 9, 2024
f9e7451
Resolve #12617 - Remove images of expended units
yairm210 Dec 9, 2024
c2b6205
Decreased base Fort value to not build it instead of useful improvements
yairm210 Dec 9, 2024
7187554
Removed uses of UncivGame.Current.gameInfo when unnecessary
yairm210 Dec 9, 2024
d08f2a2
Resolved #12611 - automated air units with "Cannot move" do not move
yairm210 Dec 9, 2024
ab2c848
Run mod compatibility checks on another thread, to avoid ANRs in new …
yairm210 Dec 9, 2024
f2aefd0
AI: Don't pick most expensive tech as free tech, if it's marked as "0…
yairm210 Dec 9, 2024
f602512
Version rollout (#12619)
yairm210 Dec 9, 2024
1c25206
Fix The Hague's english name (#12581)
SeventhM Dec 9, 2024
bdc5cd2
perf(cpu): Sequences, and initially set array list to desired size
yairm210 Dec 9, 2024
66f9ed5
4.14.14
yairm210 Dec 9, 2024
07262f6
Removed 'ignore touhidurr notifications'
yairm210 Dec 9, 2024
4160f34
Simplified mirroring code in prep for rivers
yairm210 Dec 10, 2024
9a1e904
Added river mirroring
yairm210 Dec 10, 2024
a9908e8
default mirroring none
yairm210 Dec 10, 2024
cf4fd63
Fixed AI religion belief assessment (far too much weight given to tiles)
yairm210 Dec 10, 2024
648e50d
Added "exit" button in world screen popup menu
yairm210 Dec 10, 2024
0e1dfed
Fixed Thai diacritic support
yairm210 Dec 11, 2024
f018b78
Fixed scroll position indicator
yairm210 Dec 11, 2024
f791b70
fix: Scroll position indicators do not block minimap clicks
yairm210 Dec 11, 2024
8519453
Fixed cities built on pillages roads colored red
yairm210 Dec 11, 2024
1e209e3
Make returns
itanasi Dec 12, 2024
6c4965a
Better icons in unit description table - see #12591
yairm210 Dec 13, 2024
dcaf9c4
More unit table improvements - see #12591
yairm210 Dec 13, 2024
212e723
Changed Black in UI to Charcoal - see #12591
yairm210 Dec 13, 2024
17f5f94
TileInfoTable improvements - see #12591
yairm210 Dec 13, 2024
9082e2a
UI tweaks and fixes: dividers, checkbox-to-text spacing, multiplayer …
Toxile Dec 14, 2024
5364fee
Update ReligionAutomation.kt (#12627)
EmperorPinguin Dec 14, 2024
2a0cab7
Increase starting Luxury amount to match Civ 5 (#12631)
SeventhM Dec 14, 2024
5fa2e7b
Update NextTurnAutomation.kt (#12634)
EmperorPinguin Dec 14, 2024
03f06df
Add Avg Victory Turns to Simulation (#12633)
itanasi Dec 14, 2024
effddc0
Version rollout (#12647)
yairm210 Dec 14, 2024
6f535f5
4.14.15
yairm210 Dec 14, 2024
0f4f690
Better "close unit table" button - see #12591
yairm210 Dec 14, 2024
f5eb722
Code cleanup un-nesting
itanasi Dec 14, 2024
101e4d7
Scale turn speed
itanasi Dec 14, 2024
ded0037
Create CODE_OF_CONDUCT.md (#12624)
JTech-Labs Dec 15, 2024
4bac39c
Resolved #12649 - buy button active for puppets when civ can purchase…
yairm210 Dec 15, 2024
7342446
Resolved #12640 - "Tile provides yield without assigned population", …
yairm210 Dec 15, 2024
ec29503
perf: faster vector -> direction conversion
yairm210 Dec 15, 2024
16f0a98
perf(tile-update): cache base data for tile rendering to only recompu…
yairm210 Dec 15, 2024
62bae6b
perf(hit,act): local variables to save data (is null equality that ha…
yairm210 Dec 15, 2024
c3c397a
Revert "perf(tile-update): cache base data for tile rendering to only…
yairm210 Dec 15, 2024
7bc5047
perf: save tile ref on each tile layer
yairm210 Dec 15, 2024
1a0bb51
perf: save more metadata per "list of terrains" for fast lookups, thi…
yairm210 Dec 15, 2024
fdb8026
perf(minor): TileLayerCityButton faster "no-op" check
yairm210 Dec 15, 2024
02fdeb1
Update ConsoleLauncher.kt (#12658)
EmperorPinguin Dec 15, 2024
fcdf6cb
Changes to provide Random Order of Civs in sims (#12656)
itanasi Dec 15, 2024
b06708f
Resolved #12637 - Paused music no longer resumes on game resume
yairm210 Dec 15, 2024
b948024
Initial rework
itanasi Nov 14, 2024
76aa5cd
Reformat weights so we have AI vs Human
itanasi Nov 15, 2024
edf23a3
New mods and Focus
itanasi Nov 16, 2024
af55c18
Automation and Sim updates
itanasi Dec 3, 2024
285e113
Finalize weights
itanasi Dec 6, 2024
f616262
Refactor into separate function
itanasi Dec 8, 2024
fcaf6aa
Cleanup
itanasi Dec 8, 2024
e469b94
Cleanup 2
itanasi Dec 8, 2024
aee4986
Make returns
itanasi Dec 12, 2024
4c386c2
Code cleanup un-nesting
itanasi Dec 14, 2024
7e92935
Scale turn speed
itanasi Dec 14, 2024
56023b8
Merge remote-tracking branch 'origin/Rebalance-Weights' into Rebalanc…
itanasi Dec 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 32 additions & 11 deletions core/src/com/unciv/logic/automation/Automation.kt
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,36 @@ object Automation {
return rank
}


// More complicated logic to properly weigh Food vs other Stats (esp Production)
private fun getFoodModWeight(city: City, surplusFood: Float): Float {
var foodModWeight = 1f

// Zero out Growth if close to Unhappiness limit
if (city.civ.getHappiness() < -8) {
foodModWeight = 0f
itanasi marked this conversation as resolved.
Show resolved Hide resolved
} else if (city.civ.isAI()) {
itanasi marked this conversation as resolved.
Show resolved Hide resolved
// When Happy, 2 production is better than 1 growth,
// but setting such by default worsens AI civ citizen assignment,
// probably due to badly configured personalities not properly weighing food vs non-food yields
if (city.population.population < 5)
foodModWeight = 2f
else if (surplusFood > city.population.getFoodToNextPopulation() / 10)
foodModWeight = 0.75f // get Growth just under Production
else
foodModWeight = 1.5f
} else {
// Human weights. May be different since AI Happiness is always "easier"
// Only apply these for Default to not interfere with Focus weights
if (city.getCityFocus() == CityFocus.NoFocus) {
if (city.population.population < 5)
foodModWeight = 2f
else if (surplusFood > city.population.getFoodToNextPopulation() / 10)
foodModWeight = 0.75f // get Growth just under Production
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You make the growth value dependent on the population and the current growth/turn of the city, which is something the human would need to start keeping track of. I explicitly removed similar requirements some time ago in a PR, as it makes it is annoying keeping track of individual cities that way.
Also, and this is maybe more of a personal preference than a common sentiment, but I would like my city to get 1 growth over 1 production+1 gold. If I want the latter during Happiness (for example when at war). I can click the Avoid Growth button myselves.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small Cities need a higher Food Weight since Growth is more important. For 90% of players who don't optimize assignments every turn, this is more in line with generally good play. I asked you in the Discord thread if there were better metrics to use based on Population and you didn't respond.

As for the base weight, 1Growth over 1Prod+1Gold would mean Food/Prod >3/2 (since Gold = 1/2 Prod). I'd roughly agree and if that's what we really want to do we should adjust the base value not have a multiplier here. But the poll also indicated this was a minority evaluation. Arguably the experts valued it about 1.5x. But this is a grey area. I previously proposed increasing the base 14->16.

Copy link
Contributor

@EmperorPinguin EmperorPinguin Dec 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You asked me, and I replied it would be a better idea to make it dependent on the global game state (game ending conditions) instead of the local state of the city. The are some problems with that, as making the food eval dependent on war status makes it very exploitable by humans (they can declare war and sit back to defend until the AI is irrelevant), and making it dependent on tech% complete doesn't work properly if players start a new game in late eras. The latter would be very nice to combine with scientist saving though, maybe it should be given a try.

Copy link
Contributor Author

@itanasi itanasi Dec 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. Those methods may be slightly more optimal, but introduce a lot more complications, is brittle, and you haven't described a clean algorithm for any of them. This solves a common issue, is simple, and robust enough to handle mods.

The sims also show this is a huge improvement in performance for Generic Civ AI.

Marking as Draft for now. If you still have major issues let's discuss on Discord.

}
}
return foodModWeight
}

fun rankStatsForCityWork(stats: Stats, city: City, areWeRankingSpecialist: Boolean, localUniqueCache: LocalUniqueCache): Float {
val cityAIFocus = city.getCityFocus()
val yieldStats = stats.clone()
Expand Down Expand Up @@ -116,16 +145,8 @@ object Automation {
newGrowthFood += growthFood / 4
}
newGrowthFood = newGrowthFood.coerceAtLeast(0f) // floor to 0 for safety

// When Happy, 2 production is better than 1 growth,
// but setting such by default worsens AI civ citizen assignment,
// probably due to badly configured personalities not properly weighing food vs non-food yields

// Zero out Growth if close to Unhappiness limit as well
val baseFocusWeight = if (city.civ.getHappiness() < -8) 0 else {
if (cityAIFocus in CityFocus.zeroFoodFocuses) 1 else 2
}
yieldStats.food += newGrowthFood * foodBaseWeight * baseFocusWeight

yieldStats.food += newGrowthFood * foodBaseWeight * getFoodModWeight(city, surplusFood)
}

if (city.population.population < 10) {
Expand Down
6 changes: 4 additions & 2 deletions core/src/com/unciv/logic/city/CityFocus.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,15 @@ enum class CityFocus(
FaithFocus("${Stat.Faith.character}", true, Stat.Faith),
GoldGrowthFocus("${Stat.Gold.character} ${Stat.Food.character}", true) {
override fun getStatMultiplier(stat: Stat) = when (stat) {
Stat.Gold, Stat.Food -> 2f
Stat.Gold -> 2f
Stat.Food -> 1.5f
else -> 1f
}
},
ProductionGrowthFocus("${Stat.Production.character} ${Stat.Food.character}", true) {
override fun getStatMultiplier(stat: Stat) = when (stat) {
Stat.Production, Stat.Food -> 2f
Stat.Production -> 2f
Stat.Food -> 1.5f
else -> 1f
}
},
Expand Down
12 changes: 12 additions & 0 deletions core/src/com/unciv/logic/simulation/Simulation.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class Simulation(
var steps = ArrayList<SimulationStep>()
var numWins = mutableMapOf<String, MutableInt>()
private var winRateByVictory = HashMap<String, MutableMap<String, MutableInt>>()
private var winTurnByVictory = HashMap<String, MutableMap<String, MutableInt>>()
private var avgSpeed = 0f
private var avgDuration: Duration = Duration.ZERO
private var totalTurns = 0
Expand All @@ -42,6 +43,9 @@ class Simulation(
winRateByVictory[civ] = mutableMapOf()
for (victory in UncivGame.Current.gameInfo!!.ruleset.victories.keys)
winRateByVictory[civ]!![victory] = MutableInt(0)
winTurnByVictory[civ] = mutableMapOf()
for (victory in UncivGame.Current.gameInfo!!.ruleset.victories.keys)
winTurnByVictory[civ]!![victory] = MutableInt(0)
}
}

Expand Down Expand Up @@ -98,10 +102,12 @@ class Simulation(
// win Rate
numWins.values.forEach { it.value = 0 }
winRateByVictory.flatMap { it.value.values }.forEach { it.value = 0 }
winTurnByVictory.flatMap { it.value.values }.forEach { it.value = 0 }
steps.forEach {
if (it.winner != null) {
numWins[it.winner!!]!!.inc()
winRateByVictory[it.winner!!]!![it.victoryType]!!.inc()
winTurnByVictory[it.winner!!]!![it.victoryType]!!.set(winTurnByVictory[it.winner!!]!![it.victoryType]!!.get() + it.turns)
}
}
totalTurns = steps.sumOf { it.turns }
Expand Down Expand Up @@ -137,6 +143,12 @@ class Simulation(
outString += "$victory: $winsVictory% "
}
outString += "\n"
for (victory in UncivGame.Current.gameInfo!!.ruleset.victories.keys) {
val winsTurns =
winTurnByVictory[civ]!![victory]!!.value / max(winRateByVictory[civ]!![victory]!!.value, 1)
outString += "$victory: $winsTurns "
}
outString += "avg turns\n"
}
outString += "\nAverage speed: %.1f turns/s \n".format(avgSpeed)
outString += "Average game duration: $avgDuration\n"
Expand Down
2 changes: 1 addition & 1 deletion desktop/src/com/unciv/app/desktop/ConsoleLauncher.kt
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ internal object ConsoleLauncher {
UncivGame.Current.gameInfo = newGame


val simulation = Simulation(newGame, 50, 8)
val simulation = Simulation(newGame, 50, 20)
//Unless the effect size is very large, you'll typically need a large number of games to get a statistically significant result

simulation.start()
Expand Down
Loading