-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcivSimTribes_tribe_nomadic.go
126 lines (107 loc) · 4.82 KB
/
civSimTribes_tribe_nomadic.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package genworldvoronoi
import (
"log"
"sort"
)
// HANDLE NOMADIC TRIBES HERE.
//
// Nomadic tribes will move around and settle in different regions, depending on their preferences
// and suitability of the regions (what population can be sustained in the region).
//
// If the most prosperous neighbor region cannot sustain the entire tribe, the tribe will split into
// two or more tribes.
func (s *simState) handleNomadicTribe(t *Tribe) {
// We look at all neighboring regions and move to the most suitable region.
// Considerations:
// - We do not move into a region that is already occupied.
// - We do not move into a region that is not suitable for the tribe.
// Calculate the max population for each neighboring region.
neigbors := s.m.R_circulate_r(rNbs, t.RegionID)
maxPopPerRegion := make([]int, len(neigbors))
neighborIndices := make([]int, len(neigbors))
for i, nb := range neigbors {
neighborIndices[i] = i
// We only consider regions that are not ocean regions and are unoccupied.
if s.m.Elevation[nb] > 0 && s.tribeAtRegion[nb] == nil {
maxPopPerRegion[i] = s.calcMaxPopPerRegion(t, nb)
}
}
// Sort the neighbor indices by max population.
sort.Slice(neighborIndices, func(i, j int) bool {
return maxPopPerRegion[neighborIndices[i]] > maxPopPerRegion[neighborIndices[j]]
})
// Start with the most suitable region and check if the entire tribe can move there.
// If not, we need to split the tribe into two tribes and move the remaining tribe to the next suitable region.
tCurrent := t
for _, idx := range neighborIndices {
nb := neigbors[idx]
if s.tribeAtRegion[nb] != nil {
continue // The region is already occupied.
}
// Get the max population for the region.
nbMaxPop := maxPopPerRegion[idx]
if nbMaxPop <= 0 {
break // We ran out of suitable regions.
}
// Check if the entire tribe can move to the new region.
if nbMaxPop >= tCurrent.Population {
// Move the tribe here and be done.
s.moveTribe(tCurrent, nb)
// TODO: The satisfaction should depend on the prosperity of the region
// copared to the current region, etc.
tCurrent.changeSatisfaction(migrationSuccessSatisfaction)
s.newTribes = append(s.newTribes, tCurrent)
tCurrent = nil
break
}
// The max population for the region is less than the population of the tribe.
// Get the number of people that we leave behind (a minimum of 50 people, if the tribe is large enough).
diff := min(max(50, tCurrent.Population-nbMaxPop), tCurrent.Population/2)
log.Println("Tribe ", tCurrent.String(), "is splitting into two tribes. Population:", tCurrent.Population, "Max population:", nbMaxPop, "Diff:", diff)
// Split the tribe into two tribes. The new tribe will be placed in the original region.
newTribe := tCurrent.Split(s.m.getNextTribeID(), diff)
// Move the remaining (the original) tribe to the new region
// and the new tribe to the original region.
currentReg := tCurrent.RegionID
s.moveTribe(tCurrent, nb)
s.moveTribe(newTribe, currentReg)
// TODO: Make these constants.
newTribe.changeSatisfaction(tribeSplitForcedSatisfaction)
tCurrent.changeSatisfaction(tribeSplitForcedSatisfaction)
s.newTribes = append(s.newTribes, tCurrent)
// Set the new tribe as the current tribe.
tCurrent = newTribe
}
// If there is still remaining population, check if they can survive in the current region.
if tCurrent != nil {
log.Println("Tribe ", tCurrent.String(), "is trying to survive in the current region. Population:", tCurrent.Population, "Max population:", t.currentRegionMaxPop)
// Check if the tribe can survive in the current region (or at least part of it can survive).
if maxPop := s.calcMaxPopPerRegion(t, tCurrent.RegionID); maxPop <= 0 {
log.Println("Tribe ", tCurrent.String(), "has died out.")
// TODO: Optionally attack other tribes to move into their regions.
if s.tribeAtRegion[tCurrent.RegionID] == tCurrent {
s.tribeAtRegion[tCurrent.RegionID] = nil
} else {
// DEBUG: Check if the tribe is in the right region.
log.Println("Tribe ", tCurrent.String(), "is in the wrong region?????!!!")
}
} else {
// Check if the tribe lost some of its population.
if maxPop < tCurrent.Population {
t.changeSatisfaction(starvationSatisfaction)
log.Println("Tribe ", tCurrent.String(), " lost some of its population.", tCurrent.Population-maxPop, "people died.", maxPop, "people survived.")
tCurrent.Population = maxPop
} else {
t.changeSatisfaction(migrationSuccessSatisfaction)
}
// DEBUG: Check if the tribe is in the right region.
if s.tribeAtRegion[tCurrent.RegionID] != tCurrent {
log.Println("Tribe", tCurrent.String(), "is in the wrong region.")
}
// Re-assign the tribe to the region.
s.moveTribe(tCurrent, tCurrent.RegionID)
// We can survive in the current region, retain the tribe.
s.newTribes = append(s.newTribes, tCurrent)
}
}
}