yingqianjiang-lingoace commited on
Commit
bcf0302
·
1 Parent(s): 6cc9c22

Add application file

Browse files
.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ __pycache__
Character.py ADDED
@@ -0,0 +1,242 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import random
2
+ import math
3
+ from utils import get_random_name, get_random_clan_name
4
+ from config import P_DIE_WHEN_LOSE, IMMORTAL_RANK
5
+
6
+ cultivation_rank_map = ["炼气期", "筑基期", "结丹期", "元婴期", "化神期", "成仙者"]
7
+ class Character:
8
+ def __init__(self, name, gender, special_constitution, spiritual_roots, clan=None, partner=None, parents=None):
9
+ self.name = name
10
+ self.gender = gender
11
+ self.real_age = 0
12
+ self.apparent_age = 0
13
+ self.cultivation_level = 0 # 等级
14
+ self.cultivation_rank = 0 # 层次
15
+ self.special_constitution = special_constitution
16
+ self.spiritual_roots = spiritual_roots
17
+ self.experience_points = 0
18
+ self.combat_power = self.calculate_combat_power()
19
+ self.partner = partner
20
+ self.is_alive = True
21
+ self.buff = False
22
+ self.history = []
23
+ self.special_history = []
24
+ self.consume_spiritual_energy = 0
25
+ self.parents = parents
26
+ self.children = []
27
+ self.clan = clan # 宗族
28
+
29
+ def die(self):
30
+ self.history.append(f"{self.real_age}岁,死亡")
31
+ self.special_history.append(f"{self.real_age}岁,死亡")
32
+ self.is_alive = False
33
+
34
+ def cultivate(self, experience_points):
35
+ if not self.is_alive:
36
+ print("角色已经死亡,无法进行修炼。")
37
+ return
38
+ # 成仙者不再修炼
39
+ if self.cultivation_rank >= IMMORTAL_RANK:
40
+ return
41
+
42
+ self.experience_points += experience_points
43
+
44
+ # 根据经验值计算等级,等级越高,升级需要的经验值就越多
45
+ self.cultivation_level = math.floor(self.experience_points / ((1 + self.cultivation_rank) * 1000 + (1 + self.cultivation_level) * 100))
46
+
47
+ # 判断是否达到突破修为层次的条件
48
+ if self.cultivation_level >= 10:
49
+ # 使用一个随机数来表示突破的概率,当前rank越高,则突破成功的概率越低
50
+ success_probability = 0.9 / (self.cultivation_rank * 2 + 1)
51
+ if random.random() < success_probability:
52
+ cultivation_level = self.cultivation_level
53
+ self.cultivation_rank += 1
54
+ self.cultivation_level = 0
55
+ self.experience_points = 0
56
+ self.history.append(f"{self.real_age}岁,突破成功,在{cultivation_level}级, 到达{self.view_rank()}")
57
+ self.special_history.append(f"{self.real_age}岁,突破成功,在{cultivation_level}级, 到达{self.view_rank()}")
58
+ else:
59
+ self.history.append(f"{self.real_age}岁,突破失败,在{self.cultivation_level}级")
60
+
61
+ def marry(self, partner):
62
+ # 成仙者不再结婚
63
+ if self.cultivation_rank >= IMMORTAL_RANK:
64
+ return
65
+ if not self.is_alive:
66
+ print("角色已经死亡,无法结婚。")
67
+ return
68
+ self.partner = partner
69
+ partner.partner = self
70
+
71
+ # 结婚合并宗族
72
+ if self.clan and partner.clan:
73
+ if random.random() < 0.5:
74
+ partner.clan = self.clan
75
+ else:
76
+ self.clan = partner.clan
77
+ else:
78
+ self.clan = self.clan or partner.clan or get_random_clan_name()
79
+ partner.clan = self.clan
80
+
81
+ self.history.append(f"{self.real_age}岁,结婚了")
82
+ self.partner.history.append(f"{self.partner.real_age}岁,结婚了")
83
+ self.special_history.append(f"{self.real_age}岁,结婚了")
84
+ self.partner.special_history.append(f"{self.partner.real_age}岁,结婚了")
85
+
86
+ def give_birth(self):
87
+ # 成仙者不会生育
88
+ if self.cultivation_rank >= IMMORTAL_RANK:
89
+ return
90
+ if not self.is_alive:
91
+ print("角色已经死亡,无法生育。")
92
+ return
93
+ if not self.partner:
94
+ print("角色没有结婚,无法生育。")
95
+ return
96
+
97
+ # 合欢体质加buff
98
+ if self.special_constitution[1] == 1:
99
+ self.buff = True
100
+
101
+
102
+ # 小孩有一定几率遗传父亲或母亲的特殊体质和灵根
103
+ special_constitution = [a if random.random() < 0.5 else b for (a, b) in zip(self.special_constitution, self.partner.special_constitution)]
104
+ spiritual_roots = [a if random.random() < 0.5 else b for (a, b) in zip(self.spiritual_roots, self.partner.spiritual_roots)]
105
+
106
+ # spiritual_roots 一定几率突变
107
+ spiritual_roots = [random.choice([0, 1]) if random.random() < 0.01 else v for v in spiritual_roots]
108
+
109
+ child = Character(get_random_name(), random.choice(["男", "女"]), special_constitution, spiritual_roots, clan=self.clan, parents=[self, self.partner])
110
+ self.history.append(f"{self.real_age}岁,生下小孩{child.name}")
111
+ self.partner.history.append(f"{self.partner.real_age}岁,生下小孩{child.name}")
112
+ self.children.append(child)
113
+ self.partner.children.append(child)
114
+ return child
115
+
116
+ def grow(self):
117
+ # 成仙者不会衰老
118
+ if self.cultivation_rank >= IMMORTAL_RANK:
119
+ return
120
+ self.real_age += 1
121
+
122
+ # 根据修为层次 和 是否拥有木灵根 计算表观年龄
123
+ # 修为层次越高,外表看起来越年轻
124
+ ratio = 1 + self.cultivation_rank
125
+
126
+ # 灵龟和蜉蝣体质
127
+ if self.special_constitution[2] == 1: # 灵龟体质
128
+ ratio *= 2
129
+ elif self.special_constitution[3] == 1: # 蜉蝣体质
130
+ ratio *= 0.5
131
+
132
+ # 根据修为层次计算加成比例,初始加成为10%
133
+ bonus = 0.1 * (self.cultivation_rank * 0 + 1)
134
+ if self.spiritual_roots[1] == 1: # 拥有木灵根(灵根的第二位),最大寿命有加成
135
+ ratio *= 1 + bonus
136
+
137
+ self.apparent_age = math.floor(self.real_age / ratio)
138
+
139
+ def calculate_combat_power(self):
140
+ # 根据修为层次和修为等级计算战斗力参数:等级越高,各数值都越高;层次对等级是碾压效果
141
+ attack_power = (self.cultivation_rank + 1) * 30 + 1 * (1 + self.cultivation_level)
142
+ defense_power = (self.cultivation_rank + 1) * 30 + 1 * (1 + self.cultivation_level)
143
+ attack_speed = (self.cultivation_rank + 1) * 30 + 1 * (1 + self.cultivation_level)
144
+ health_points = (self.cultivation_rank + 1) * 60 + 2 * (1 + self.cultivation_level)
145
+
146
+ # 根据修为层次计算加成比例,初始加成为10%
147
+ bonus = 0.1 * (self.cultivation_rank * 0 + 1)
148
+
149
+ # 根据灵根调整战斗力参数,灵根分别为:[金木水火土], 分别对以下属性有加成:攻击速度, 最大寿命, 生命值, 攻击力, 防御力
150
+ if self.spiritual_roots[0] == 1: # 金
151
+ attack_speed *= 1 + bonus
152
+
153
+ if self.spiritual_roots[2] == 1: # 水
154
+ health_points *= 1 + bonus
155
+
156
+ if self.spiritual_roots[3] == 1: # 火
157
+ attack_power *= 1 + bonus
158
+
159
+ if self.spiritual_roots[4] == 1: # 土
160
+ defense_power *= 1 + bonus
161
+
162
+ return {
163
+ 'attack_power': attack_power,
164
+ 'defense_power': defense_power,
165
+ 'attack_speed': attack_speed,
166
+ 'health_points': health_points
167
+ }
168
+
169
+ def before_battle(self):
170
+ self.combat_power = self.calculate_combat_power()
171
+
172
+ def attack(self, opponent):
173
+ # 成仙者不会打架
174
+ if self.cultivation_rank >= IMMORTAL_RANK:
175
+ return
176
+ if not self.is_alive:
177
+ print("角色已经死亡,无法攻击。")
178
+ return
179
+
180
+ # 战斗体质加buff
181
+ if self.special_constitution[0] == 1:
182
+ self.buff = True
183
+
184
+ # TODO: 考虑攻击速度
185
+ damage = self.combat_power['attack_power'] - opponent.combat_power['defense_power']
186
+ if damage > 0:
187
+ opponent.combat_power['health_points'] -= damage
188
+
189
+ def check_is_alive(self):
190
+ if self.combat_power['health_points'] <= 0:
191
+ # 一定概率会死亡
192
+ if random.random() < P_DIE_WHEN_LOSE:
193
+ self.die()
194
+ return False
195
+ return True
196
+
197
+ def __str__(self):
198
+ # Display current attributes
199
+ history = "\n".join(self.history)
200
+ attributes = [
201
+ f"Name: {self.name}",
202
+ f"Gender: {self.gender}",
203
+ f"Real Age: {self.real_age}",
204
+ f"Apparent Age: {self.apparent_age}",
205
+ f"Cultivation Level: {self.cultivation_level}",
206
+ f"Cultivation Rank: ({self.cultivation_rank}){self.view_rank()}",
207
+ f"Special Constitution: {self.special_constitution}",
208
+ f"Spiritual Roots: {self.spiritual_roots}",
209
+ f"Experience Points: {self.experience_points}",
210
+ f"Combat Power: {self.combat_power}",
211
+ f"Partner: {self.partner.name if self.partner is not None else ''}",
212
+ f"Is Alive: {self.is_alive}",
213
+ f"Buff: {self.buff}",
214
+ f"Children: {[child.name for child in self.children]}",
215
+ f"History: {history}",
216
+ ]
217
+ return "\n".join(attributes)
218
+
219
+ def view_rank(self):
220
+ if self.cultivation_rank <= len(cultivation_rank_map):
221
+ return f"{cultivation_rank_map[self.cultivation_rank]}({self.cultivation_level})"
222
+ else:
223
+ return "天外飞仙"
224
+
225
+ def to_list(self):
226
+ numerical_attributes = [
227
+ self.real_age,
228
+ self.apparent_age,
229
+ self.cultivation_level,
230
+ self.cultivation_rank,
231
+ self.experience_points,
232
+ self.combat_power["attack_power"],
233
+ self.combat_power["defense_power"],
234
+ self.combat_power["attack_speed"],
235
+ self.combat_power["health_points"],
236
+ *self.special_constitution, # [1, 0, 0, 0], 数组解构拼接
237
+ *self.spiritual_roots, # [1, 0, 0, 0, 0], 数组解构拼接
238
+ 1 if self.is_alive else 0, # bool转int
239
+ 1 if self.buff else 0, # bool转int
240
+ len(self.children),
241
+ ]
242
+ return numerical_attributes
CharacterStatistics.py ADDED
@@ -0,0 +1,245 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import matplotlib.pyplot as plt
3
+
4
+ class CharacterStatistics:
5
+ def __init__(self, characters):
6
+ self.characters = characters
7
+ self.characters_array = np.array([c.to_list() for c in characters])
8
+
9
+ # 前n名排行榜
10
+ def find_highest_cultivation(self, n=1):
11
+ sorted_characters = sorted(self.characters, key=lambda c: (c.cultivation_rank, c.cultivation_level), reverse=True)
12
+ return sorted_characters[:n]
13
+
14
+ # 宗族人数排行榜
15
+ def rank_top_clans(self, top_n=4):
16
+ clan_size = {}
17
+ for c in self.characters:
18
+ clan_size[c.clan] = clan_size.get(c.clan, 0) + 1
19
+
20
+ sorted_clans = sorted(clan_size.items(), key=lambda x: x[1], reverse=True)[:top_n]
21
+
22
+ return sorted_clans
23
+
24
+ # real_age、apparent_age、cultivation_level、cultivation_rank 分布图
25
+ def plot_attribute_distribution(self):
26
+ attributes = ['Real Age', 'Apparent Age', 'Cultivation Level', 'Cultivation Rank']
27
+ attribute_indices = [0, 1, 2, 3]
28
+ fig, axs = plt.subplots(2, 2, figsize=(10, 8))
29
+ axs = axs.flatten()
30
+ for i, ax in enumerate(axs):
31
+ ax.hist(self.characters_array[:, attribute_indices[i]], bins=20, edgecolor='black')
32
+ ax.set_xlabel(attributes[i])
33
+ ax.set_ylabel('Frequency')
34
+ plt.tight_layout()
35
+ plt.show()
36
+
37
+ # real_age、apparent_age、cultivation_level、cultivation_rank、孩子数量 统计平均数
38
+ def calculate_average_attributes(self):
39
+ real_age_mean = np.mean(self.characters_array[:, 0])
40
+ apparent_age_mean = np.mean(self.characters_array[:, 1])
41
+ cultivation_level_mean = np.mean(self.characters_array[:, 2])
42
+ cultivation_rank_mean = np.mean(self.characters_array[:, 3])
43
+ child_count_mean = np.mean(self.characters_array[:, 19])
44
+ return real_age_mean, apparent_age_mean, cultivation_level_mean, cultivation_rank_mean, child_count_mean
45
+
46
+ # 画出 cultivation_rank (x轴) 和 4项combat_power的关系(y轴)
47
+ def plot_combat_power_vs_cultivation_rank(self):
48
+
49
+ fig, axs = plt.subplots(2, 2, figsize=(10, 8))
50
+ axs = axs.flatten()
51
+
52
+ for i, combat_power in enumerate(['Attack Power', 'Defense Power', 'Attack Speed', 'Health Points']):
53
+
54
+ combat_power_data = []
55
+ for rank in range(6):
56
+ rank_data = self.characters_array[self.characters_array[:,3]==rank, i+5]
57
+ combat_power_data.append(rank_data)
58
+
59
+ axs[i].boxplot(combat_power_data)
60
+ axs[i].set_title(combat_power)
61
+ axs[i].set_xlabel('Cultivation Rank')
62
+ axs[i].set_ylabel('Value')
63
+
64
+ plt.tight_layout()
65
+ plt.show()
66
+
67
+ def calculate_average_special_constitution(self):
68
+ special_constitution_mean = np.mean(self.characters_array[:, 9:13], axis=0)
69
+ return special_constitution_mean
70
+
71
+ def calculate_average_spiritual_roots(self):
72
+ spiritual_roots_mean = np.mean(self.characters_array[:, 13:18], axis=0)
73
+ return spiritual_roots_mean
74
+
75
+ # 统计无灵根者的数量
76
+ def count_zero_spiritual_roots(self):
77
+ zero_spiritual_roots_count = np.sum(np.all(self.characters_array[:, 13:18] == 0, axis=1))
78
+ return zero_spiritual_roots_count
79
+
80
+ # 灵根数量分布图
81
+ def plot_sum_spiritual_root_distribution(self):
82
+ spiritual_roots_sum = np.sum(self.characters_array[:, 13:18], axis=1)
83
+
84
+ plt.hist(spiritual_roots_sum, bins=5, range=(0,5))
85
+ plt.xlabel('Number of Spiritual Roots')
86
+ plt.ylabel('Number of Characters')
87
+ plt.title('Distribution of Spiritual Roots')
88
+
89
+ plt.show()
90
+
91
+ # 各灵根人口分布(x轴:5种灵根,y轴:人数)
92
+ def plot_spiritual_roots_distribution(self):
93
+
94
+ spiritual_roots = self.characters_array[:, 13:18]
95
+
96
+ means = np.mean(spiritual_roots, axis=0)
97
+ roots = ['Metal', 'Wood', 'Water', 'Fire', 'Earth']
98
+
99
+ plt.bar(roots, means)
100
+ plt.xlabel('Spiritual Roots')
101
+ plt.ylabel('Percentage of Characters')
102
+ plt.title('Distribution of Spiritual Roots in Population')
103
+
104
+ plt.show()
105
+
106
+ # 宗族人数分布图
107
+ def plot_clan_size_distribution(self):
108
+ clan_size = {}
109
+ for c in self.characters:
110
+ clan_size[c.clan] = clan_size.get(c.clan, 0) + 1
111
+
112
+ sizes = list(clan_size.values())
113
+ plt.hist(sizes, bins=20)
114
+ plt.xlabel('Clan Size')
115
+ plt.ylabel('Number of Clans')
116
+ plt.show()
117
+
118
+ def summarize(self):
119
+ print("===== Character Statistics Summary =====")
120
+
121
+ # 打印平均属性
122
+ print("Average Attributes:")
123
+ real_age, apparent_age, cultivation_level, cultivation_rank, child_count = self.calculate_average_attributes()
124
+ print(f"Real Age: {real_age:.2f}")
125
+ print(f"Apparent Age: {apparent_age:.2f}")
126
+ print(f"Cultivation Level: {cultivation_level:.2f}")
127
+ print(f"Cultivation Rank: {cultivation_rank:.2f}")
128
+ print(f"Child Count: {child_count:.2f}")
129
+
130
+ # 打印平均特质
131
+ print("\nAverage Special Constitutions:")
132
+ special_names = ['战斗', '合欢', '灵龟', '蜉蝣']
133
+ for i, v in enumerate(self.calculate_average_special_constitution()):
134
+ print(f"{special_names[i]}: {v:.2%}")
135
+
136
+ # 打印平均灵根
137
+ print("\nAverage Spiritual Roots:")
138
+ root_names = ['金', '木', '水', '火', '土']
139
+ for i, v in enumerate(self.calculate_average_spiritual_roots()):
140
+ print(f"{root_names[i]}: {v:.2%}")
141
+
142
+ # 打印统计图
143
+ print("\nPlotting graphs...")
144
+ self.plot_attribute_distribution()
145
+ # self.plot_combat_power_vs_cultivation_rank()
146
+ self.plot_spiritual_roots_distribution()
147
+ self.plot_sum_spiritual_root_distribution()
148
+ self.plot_clan_size_distribution()
149
+ self.print_top_cultivators()
150
+ # 攻击力排行榜
151
+ self.print_rank('attack_power', name='Attack Power')
152
+ # 防御力排行榜
153
+ self.print_rank('defense_power', name='Defense Power')
154
+ self.print_top_clans()
155
+
156
+ print("\n===== End Summary =====\n")
157
+
158
+ # 返回Markdown字符串的总结输出
159
+ def summarize_markdown(self):
160
+ md = "## Character Statistics Summary\n\n"
161
+ md += "### Average Attributes:\n\n"
162
+ real_age, apparent_age, cultivation_level, cultivation_rank, child_count = self.calculate_average_attributes()
163
+ md += f"Real Age: {real_age:.2f}\n\n"
164
+ md += f"Apparent Age: {apparent_age:.2f}\n\n"
165
+ md += f"Cultivation Level: {cultivation_level:.2f}\n\n"
166
+ md += f"Cultivation Rank: {cultivation_rank:.2f}\n\n"
167
+ md += f"Child Count: {child_count:.2f}\n\n"
168
+
169
+ md += "### Average Special Constitutions:\n\n"
170
+ special_names = ['战斗', '合欢', '灵龟', '蜉蝣']
171
+ for i, v in enumerate(self.calculate_average_special_constitution()):
172
+ md += f"{special_names[i]}: {v:.2%}\n\n"
173
+
174
+ md += "### Average Spiritual Roots:\n\n"
175
+ root_names = ['金', '木', '水', '火', '土']
176
+ for i, v in enumerate(self.calculate_average_spiritual_roots()):
177
+ md += f"{root_names[i]}: {v:.2%}\n\n"
178
+
179
+ # md += "### Plotting graphs...\n\n"
180
+ # md += "#### Attribute Distribution\n\n"
181
+ # md += "![Attribute Distribution](./attribute_distribution.png)\n\n"
182
+ # md += "#### Spiritual Roots Distribution\n\n"
183
+ # md += "![Spiritual Roots Distribution](./spiritual_roots_distribution.png)\n\n"
184
+ # md += "#### Sum Spiritual Roots Distribution\n\n"
185
+ # md += "![Sum Spiritual Roots Distribution](./sum_spiritual_roots_distribution.png)\n\n"
186
+ # md += "#### Clan Size Distribution\n\n"
187
+ # md += "![Clan Size Distribution](./clan_size_distribution.png)\n\n"
188
+ md += "#### Top Cultivators\n\n"
189
+ md += self.print_top_cultivators_markdown()
190
+ md += "#### Attack Power Ranking\n\n"
191
+ md += self.print_rank_markdown('attack_power', name='Attack Power')
192
+ md += "#### Defense Power Ranking\n\n"
193
+ md += self.print_rank_markdown('defense_power', name='Defense Power')
194
+ md += "#### Top Clans\n\n"
195
+ md += self.print_top_clans_markdown()
196
+
197
+ return md
198
+
199
+ def print_top_cultivators(self, top_n=10):
200
+
201
+ print("\n== Top Cultivators ==")
202
+ print("{:<10} {:>10} {:>10} {:>10} {:>10}".format('Name', 'Clan', 'Rank', 'Level', '境界'))
203
+ for c in self.find_highest_cultivation(top_n):
204
+ print("{:<10} {:>10} {:>10} {:>10} {:>10}".format(c.name, c.clan, c.cultivation_rank, c.cultivation_level, c.view_rank()))
205
+
206
+ def print_top_cultivators_markdown(self, n=10):
207
+ md = f"| Name | Clan | Cultivation Rank | Cultivation Level | 境界\n"
208
+ md += "| ---- | ---- | ---------------- | ---------------- | ----\n"
209
+ for c in self.find_highest_cultivation(n):
210
+ md += f"| {c.name} | {c.clan} | {c.cultivation_rank:.2f} | {c.cultivation_level:.2f} | {c.view_rank()}\n"
211
+ return md
212
+
213
+ def print_rank(self, rank_key, top_n=10, name=None):
214
+
215
+ print(f"\n== {'Name' if name is None else name} Rank ==")
216
+
217
+ sorted_characters = sorted(self.characters, key=lambda c: c.combat_power[rank_key], reverse=True)
218
+
219
+ print("{:<10} {:>10} {:>10} {:>10} {:>10}".format('Name', rank_key if name is None else name, 'Rank', 'Level', '境界'))
220
+
221
+ for c in sorted_characters[:top_n]:
222
+ print("{:<10} {:>10}{:>10} {:>10} {:>10}".format(c.name, c.combat_power[rank_key], c.cultivation_rank, c.cultivation_level, c.view_rank()))
223
+
224
+ def print_rank_markdown(self, attr, name=None, n=10):
225
+ md = f"| Name | {attr if name is None else name} | Cultivation Rank | Cultivation Level | 境界\n"
226
+ md += "| ---- | ---- | ---------------- | ---------------- | ----\n"
227
+ sorted_characters = sorted(self.characters, key=lambda c: c.combat_power[attr], reverse=True)
228
+ for c in sorted_characters[:n]:
229
+ md += f"| {c.name} | {c.combat_power[attr]:.2f} | {c.cultivation_rank:.2f} | {c.cultivation_level:.2f} | {c.view_rank()}\n"
230
+ return md
231
+
232
+ def print_top_clans(self, top_n=4):
233
+
234
+ print("\n== Top Clans ==")
235
+ print("{:<10} {:>10}".format('Clan', 'Members'))
236
+
237
+ for clan, size in self.rank_top_clans(top_n):
238
+ print("{:<10} {:>10}".format(clan, size))
239
+
240
+ def print_top_clans_markdown(self, n=10):
241
+ md = "| Clan | Clan Size |\n"
242
+ md += "| -------- | --------- |\n"
243
+ for clan, size in self.rank_top_clans(n):
244
+ md += f"| {clan} | {size} |\n"
245
+ return md
PluginManager.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class PluginManager:
2
+ def __init__(self):
3
+ self.plugins = []
4
+
5
+ def add_plugin(self, plugin):
6
+ self.plugins.append(plugin)
7
+
8
+ def remove_plugin(self, plugin):
9
+ self.plugins.remove(plugin)
10
+
11
+ def execute_plugins(self, *args, **kwargs):
12
+ for plugin in self.plugins:
13
+ plugin.execute(*args, **kwargs)
WorldSimulation.py ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from config import DISASTER_FREQUENCY, MARRIAGE_RATE, DISASTER_PROB, NORMAL_BIRTH_RATE, LOW_BIRTH_RATE, NORMAL_BATTLE_RATE, HIGH_BATTLE_RATE
2
+ from Character import Character
3
+ from plugins.CharacterCreationPlugin import CharacterCreationPlugin
4
+ from plugins.CultivationPlugin import CultivationPlugin
5
+ from plugins.MarriagePlugin import MarriagePlugin
6
+ from plugins.BirthPlugin import BirthPlugin
7
+ from plugins.CharacterGrowthPlugin import CharacterGrowthPlugin
8
+ from plugins.DisasterPlugin import DisasterPlugin
9
+ from plugins.BattlePlugin import BattlePlugin
10
+ from plugins.ResourceDepletionPlugin import ResourceDepletionPlugin
11
+
12
+ class WorldSimulation:
13
+ def __init__(self, special_constitution_ratio, spiritual_roots_ratio, initial_population, world_spiritual_energy, resources = 100000, resources_threshold = 10):
14
+ # 初始化插件
15
+ self.character_creation_plugin = CharacterCreationPlugin(special_constitution_ratio, spiritual_roots_ratio)
16
+ self.cultivation_plugin = CultivationPlugin()
17
+ self.marriage_plugin = MarriagePlugin(MARRIAGE_RATE)
18
+ self.birth_plugin = BirthPlugin(NORMAL_BIRTH_RATE)
19
+ self.character_growth_plugin = CharacterGrowthPlugin(100)
20
+ self.disaster_plugin = DisasterPlugin(DISASTER_FREQUENCY, DISASTER_PROB)
21
+ self.battle_plugin = BattlePlugin(NORMAL_BATTLE_RATE)
22
+ self.resource_depletion_plugin = ResourceDepletionPlugin(resources_threshold)
23
+
24
+ # 初始化参数
25
+ self.initial_population = initial_population
26
+ self.resources = resources # 总资源量
27
+ self.resources_threshold = resources_threshold # 人均最少资源需求
28
+ self.init_world_spiritual_energy = world_spiritual_energy
29
+ self.world_spiritual_energy = world_spiritual_energy
30
+ self.characters = []
31
+ self.dead_characters = []
32
+ self.nth_round = 0
33
+ self.world_log = []
34
+
35
+ def log(self, msg):
36
+ self.world_log.append(msg)
37
+
38
+ def simulate_round(self):
39
+ self.character_growth_plugin.execute(self.characters, self.character_die)
40
+ self.disaster_plugin.execute(self.characters, self.nth_round, self.character_die)
41
+
42
+ # 每人可用资源
43
+ per_capita_resources = self.resources / len(self.characters)
44
+ if per_capita_resources < self.resources_threshold:
45
+ self.birth_plugin.set_birth_rate(LOW_BIRTH_RATE)
46
+ self.battle_plugin.set_battle_rate(HIGH_BATTLE_RATE)
47
+ else:
48
+ self.birth_plugin.set_birth_rate(NORMAL_BIRTH_RATE)
49
+ self.battle_plugin.set_battle_rate(NORMAL_BATTLE_RATE)
50
+
51
+ self.resource_depletion_plugin.execute(per_capita_resources, self.characters, self.character_die)
52
+
53
+ self.battle_plugin.execute(self.characters, self.character_die)
54
+ self.birth_plugin.execute(self.characters)
55
+ self.marriage_plugin.execute(self.characters)
56
+ self.cultivation_plugin.execute(self.characters, self.world_spiritual_energy, self.init_world_spiritual_energy, self.consume_spiritual_energy)
57
+
58
+ def start_simulation(self):
59
+ self.nth_round = 0
60
+ self.create_initial_population()
61
+
62
+ def run_simulation(self, num_rounds):
63
+ md = ""
64
+ for _ in range(num_rounds):
65
+ self.nth_round += 1
66
+ print(f"第{self.nth_round}轮模拟:")
67
+ md += f"第{self.nth_round}轮模拟:\n"
68
+ self.simulate_round()
69
+ print(f"当前世界灵气总量:{self.world_spiritual_energy}")
70
+ print(f"当前存活角色数量:{len(self.characters)}")
71
+ print("")
72
+ md += f"当前世界灵气总量:{self.world_spiritual_energy}\n"
73
+ md += f"当前存活角色数量:{len(self.characters)}\n\n"
74
+ if len(self.characters) == 0:
75
+ print("所有角色死亡,模拟结束")
76
+ md += "所有角色死亡,模拟结束\n"
77
+ break
78
+ return md
79
+
80
+ def add_custom_character(self, name, gender, special_constitution, spiritual_roots):
81
+ character = Character(name, gender, special_constitution, spiritual_roots)
82
+ self.characters.append(character)
83
+
84
+ def create_initial_population(self):
85
+ # 创建角色
86
+ for _ in range((self.initial_population - len(self.characters))):
87
+ character = self.character_creation_plugin.create_character()
88
+ self.characters.append(character)
89
+
90
+ def character_die(self, character):
91
+ character.die()
92
+ self.world_spiritual_energy += character.consume_spiritual_energy # 灵气回归
93
+ if character.partner:
94
+ character.partner.history.append(f"{character.partner.real_age}岁,配偶{character.name}({character.real_age}岁)死亡")
95
+ character.partner.partner = None # 解除配偶关系
96
+ self.characters.remove(character)
97
+ self.dead_characters.append(character)
98
+
99
+ def consume_spiritual_energy(self, amount):
100
+ self.world_spiritual_energy -= amount
app.py ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from CharacterStatistics import CharacterStatistics
3
+ from WorldSimulation import WorldSimulation
4
+
5
+ # 创建一个世界模拟对象
6
+ simulation = None
7
+ num_rounds = 0
8
+
9
+ def initialize_world(c1, c2, c3, c4, r1, r2, r3, r4, r5, initial_population=3000, world_spiritual_energy=1000000):
10
+ global simulation
11
+ special_constitution_ratio = [c1, c2, c3, c4]
12
+ spiritual_roots_ratio = [r1, r2, r3, r4, r5]
13
+ initial_population = int(initial_population)
14
+ simulation = WorldSimulation(special_constitution_ratio, spiritual_roots_ratio, initial_population, world_spiritual_energy)
15
+
16
+ return f"世界初始化成功:\n\n初始人口:{initial_population}\n\n世界灵气能量:{world_spiritual_energy}"
17
+
18
+
19
+ def add_custom_character(name, gender, special_constitution, spiritual_roots):
20
+ special_constitution = [1 if i in special_constitution else 0 for i in range(4)]
21
+ spiritual_roots = [1 if i in spiritual_roots else 0 for i in range(5)]
22
+ simulation.add_custom_character(name, gender, special_constitution, spiritual_roots)
23
+ return str(simulation.characters[-1])
24
+
25
+ def start_simulation():
26
+ simulation.start_simulation()
27
+ return f"世界人口数量达到{len(simulation.characters)},可以运行模拟了。"
28
+
29
+ def run_simulation(rounds):
30
+ global num_rounds
31
+ num_rounds = rounds
32
+ if simulation is None:
33
+ return "请先初始化世界"
34
+ return simulation.run_simulation(num_rounds)
35
+
36
+ def get_character_info(character_index):
37
+ if character_index < len(simulation.characters):
38
+ return str(simulation.characters[character_index])
39
+ else:
40
+ return f"没有第{character_index}个角色,目前共有{len(simulation.characters)}个存活角色"
41
+
42
+ def get_dead_character_info(character_index):
43
+ if character_index < len(simulation.dead_characters):
44
+ return str(simulation.dead_characters[character_index])
45
+ else:
46
+ return f"没有第{character_index}个死亡角色,目前共有{len(simulation.dead_characters)}个死亡角色"
47
+
48
+ def get_world_stats():
49
+ stats = CharacterStatistics(simulation.characters)
50
+ return stats.summarize_markdown()
51
+
52
+ with gr.Blocks() as demo:
53
+ # 初始化世界
54
+ gr.Markdown("## 初始化世界")
55
+ with gr.Row():
56
+ initial_population_input = gr.Number(label="初始人口", value=3000, precision=0)
57
+ world_spiritual_energy_input = gr.Number(label="世界灵气能量", value=1000000)
58
+ # 特殊体质
59
+ gr.Markdown("特殊体质比例")
60
+ with gr.Row():
61
+ special_constitution_ratio_input = [
62
+ gr.Number(label="战斗体质", minimum=0, maximum=1, value=0.001),
63
+ gr.Number(label="合欢体质", minimum=0, maximum=1, value=0.001),
64
+ gr.Number(label="灵龟体质", minimum=0, maximum=1, value=0.001),
65
+ gr.Number(label="蜉蝣体质", minimum=0, maximum=1, value=0.001)]
66
+ # 灵根
67
+ gr.Markdown("灵根比例")
68
+ with gr.Row():
69
+ spiritual_roots_ratio_input = [
70
+ gr.Number(label="金", minimum=0, maximum=1, value=0.04),
71
+ gr.Number(label="木", minimum=0, maximum=1, value=0.04),
72
+ gr.Number(label="水", minimum=0, maximum=1, value=0.04),
73
+ gr.Number(label="火", minimum=0, maximum=1, value=0.04),
74
+ gr.Number(label="土", minimum=0, maximum=1, value=0.04)]
75
+ initialize_button = gr.Button("初始化世界")
76
+ output_text = gr.Markdown(label="初始化结果")
77
+ initialize_button.click(fn=initialize_world, inputs=[*special_constitution_ratio_input, *spiritual_roots_ratio_input, initial_population_input, world_spiritual_energy_input], outputs=output_text)
78
+
79
+ # 添加角色
80
+ with gr.Accordion("添加角色"):
81
+ gr.Markdown("每次添加一个,添加完可以继续添加。")
82
+ name_input = gr.Textbox(label="姓名")
83
+ gender_input = gr.Radio(["男", "女"], label="性别")
84
+ special_constitution_input = gr.CheckboxGroup(["战斗体质", "合欢体质", "灵龟体质", "蜉蝣体质"], label="特殊体质", type="index")
85
+ spiritual_roots_input = gr.CheckboxGroup(["金", "木", "水", "火", "土"], label="灵根", type="index")
86
+ add_character_button = gr.Button("添加角色")
87
+ new_character_info_output = gr.Textbox(label="新角色信息")
88
+ add_character_button.click(fn=add_custom_character, inputs=[name_input,
89
+ gender_input,
90
+ special_constitution_input, spiritual_roots_input], outputs=new_character_info_output)
91
+
92
+ # 开始模拟
93
+ start_simulation_button = gr.Button("生成初始人口")
94
+ output_text = gr.Markdown("")
95
+ start_simulation_button.click(fn=start_simulation, inputs=[], outputs=output_text)
96
+
97
+ # 运行模拟
98
+ gr.Markdown("## 运行模拟\n\n输入轮数,运行模拟,可以多次运行。")
99
+ with gr.Row():
100
+ rounds_input = gr.Number(label="轮数", precision=0, value=1)
101
+ run_simulation_button = gr.Button("运行模拟")
102
+ simulation_result_output = gr.Textbox(label="模拟结果")
103
+ run_simulation_button.click(fn=run_simulation, inputs=[rounds_input], outputs=[simulation_result_output])
104
+
105
+ # 查看统计信息
106
+ gr.Markdown("## 查看统计信息")
107
+ get_stats_button = gr.Button("查看统计信息")
108
+ with gr.Box():
109
+ world_stats_output = gr.Markdown("")
110
+ get_stats_button.click(fn=get_world_stats, inputs=[], outputs=[world_stats_output])
111
+
112
+ # 查看角色信息
113
+ with gr.Row():
114
+ character_info_output = gr.Number(label="角色信息", info="输入角色编号", precision=0)
115
+ get_character_info_button = gr.Button("查看角色信息")
116
+ character_info_output_display = gr.Textbox(label="角色信息")
117
+ get_character_info_button.click(fn=get_character_info, inputs=[character_info_output], outputs=[character_info_output_display])
118
+
119
+ with gr.Row():
120
+ dead_character_info_output = gr.Number(label="死亡角色信息", info="输入死亡角色编号", precision=0)
121
+ get_dead_character_info_button = gr.Button("查看死亡角色信息")
122
+ dead_character_info_output_display = gr.Textbox(label="死亡角色信息")
123
+ get_dead_character_info_button.click(fn=get_dead_character_info, inputs=[dead_character_info_output], outputs=[dead_character_info_output_display])
124
+
125
+ demo.launch(debug=True)
config.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ P_DIE_WHEN_LOSE = 0.6 # 战败死亡的概率
2
+ MAX_BATTLE_ROUND = 100 # 战斗最大回合数
3
+ MARRIAGE_RATE = 0.3 # 每名适龄青年每次模拟找对象的概率
4
+
5
+ # 当每人资源大于阈值时,生育率正常,战斗率正常
6
+ NORMAL_BIRTH_RATE = 0.2
7
+ NORMAL_BATTLE_RATE = 0.3
8
+
9
+ # 当每人资源低于阈值时,生育率线性下降,战斗率线性上升
10
+ LOW_BIRTH_RATE = 0.05
11
+ HIGH_BATTLE_RATE = 0.8
12
+
13
+ # 每10轮有5%概率发生灾难
14
+ DISASTER_PROB = 0.05
15
+ DISASTER_FREQUENCY = 10
16
+
17
+ # 每50轮有10%概率发生战争
18
+ WAR_PROB = 0.1
19
+ WAR_FREQUENCY = 50
20
+
21
+ # 成仙等级
22
+ IMMORTAL_RANK = 5
plugins/BattlePlugin.py ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import random
2
+
3
+ class BattlePlugin:
4
+ def __init__(self, probability, min_battle_age=10, max_battle_round=100):
5
+ self.probability = probability
6
+ self.min_battle_age = min_battle_age # 最小参战年龄
7
+ self.max_battle_round = max_battle_round # 最大战斗回合数
8
+
9
+ def simulate_battle(self, character, opponent):
10
+ battle_round = 0
11
+
12
+ character.before_battle()
13
+ opponent.before_battle()
14
+ while character.check_is_alive() and opponent.check_is_alive() and battle_round < self.max_battle_round:
15
+ battle_round += 1
16
+
17
+ # 根据攻击速度确定行动顺序
18
+ if character.combat_power["attack_speed"] >= opponent.combat_power["attack_speed"]:
19
+ character.attack(opponent)
20
+ if opponent.check_is_alive():
21
+ opponent.attack(character)
22
+ else:
23
+ opponent.attack(character)
24
+ if character.check_is_alive():
25
+ character.attack(opponent)
26
+
27
+ # 胜利或平手判断
28
+ if character.check_is_alive() and opponent.check_is_alive():
29
+ # print(f"{character.name}和{opponent.name}打成平手!")
30
+ return None
31
+ elif character.check_is_alive():
32
+ print(f"{character.name}战胜了{opponent.name}!")
33
+ return (character, opponent)
34
+ elif opponent.check_is_alive():
35
+ print(f"{opponent.name}战胜了{character.name}!")
36
+ return (opponent, character)
37
+
38
+ def perform_battles(self, characters, character_die):
39
+ eligible_characters = [character for character in characters if character.apparent_age > self.min_battle_age]
40
+ for _ in range(int(len(eligible_characters) * self.probability)):
41
+ character = random.choice(eligible_characters)
42
+ opponent = random.choice(eligible_characters)
43
+ if character != opponent and character.clan != opponent.clan:
44
+ result = self.simulate_battle(character, opponent)
45
+ if result is not None:
46
+ (winner, loser) = result
47
+ winner.cultivate(100)
48
+ winner.history.append(f"{winner.real_age}岁({winner.view_rank()}),战胜了{loser.name}({loser.view_rank()})")
49
+ loser.history.append(f"{loser.real_age}岁({loser.view_rank()}),被{winner.name}({winner.view_rank()})打败了")
50
+ if not loser.is_alive:
51
+ print(f"{loser.name}因失血过多死亡了!")
52
+ character_die(loser)
53
+ return
54
+
55
+ def set_battle_rate(self, probability):
56
+ self.probability = probability
57
+
58
+ # 统一插件接口
59
+ def execute(self, *args, **kwargs):
60
+ self.perform_battles(*args, **kwargs)
plugins/BirthPlugin.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import random
2
+
3
+ class BirthPlugin:
4
+ def __init__(self, birth_rate, min_birth_age=20, birth_age_range=15):
5
+ self.birth_rate = birth_rate
6
+ self.birth_age = min_birth_age
7
+ self.birth_age_range = birth_age_range
8
+
9
+ def perform_births(self, characters):
10
+ new_birth_count = 0
11
+ for character in characters:
12
+ if character.partner and character.apparent_age > self.birth_age and character.apparent_age < self.birth_age + self.birth_age_range and character.partner.apparent_age > self.birth_age and character.partner.apparent_age < self.birth_age + self.birth_age_range:
13
+ if random.random() < self.birth_rate / 2:
14
+ child = character.give_birth()
15
+ if child:
16
+ characters.append(child)
17
+ new_birth_count += 1
18
+
19
+ print(f"共{new_birth_count}对夫妻生了孩子!")
20
+
21
+ def set_birth_rate(self, birth_rate):
22
+ self.birth_rate = birth_rate
23
+
24
+ # 统一插件接口
25
+ def execute(self, *args, **kwargs):
26
+ self.perform_births(*args, **kwargs)
plugins/CharacterCreationPlugin.py ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import random
2
+ from Character import Character
3
+ from utils import get_random_name
4
+
5
+ class CharacterCreationPlugin:
6
+ def __init__(self, special_constitution_ratio, spiritual_roots_ratio):
7
+ self.special_constitution_ratio = special_constitution_ratio
8
+ self.spiritual_roots_ratio = spiritual_roots_ratio
9
+
10
+ def create_character(self):
11
+ # 根据 special_constitution_ratio 随机确定这个角色拥有哪些特殊体质
12
+ special_constitution = [1 if random.random() < ratio else 0 for ratio in self.special_constitution_ratio]
13
+
14
+ # 根据 spiritual_roots_ratio 随机确定这个角色拥有哪些灵根
15
+ spiritual_roots = [1 if random.random() < ratio else 0 for ratio in self.spiritual_roots_ratio]
16
+
17
+ character = Character(get_random_name(), random.choice(["男", "女"]), special_constitution, spiritual_roots)
18
+ return character
plugins/CharacterGrowthPlugin.py ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import random
2
+ class CharacterGrowthPlugin:
3
+ def __init__(self, max_apparent_age):
4
+ self.max_apparent_age = max_apparent_age
5
+
6
+ def grow_characters(self, characters, character_die_callback):
7
+ die_count = 0
8
+ for character in characters:
9
+ # 检查角色是否存活
10
+ if not character.is_alive:
11
+ print(f"{character.name}死亡了!")
12
+ character_die_callback(character)
13
+ continue
14
+
15
+ # 角色成长
16
+ character.grow()
17
+
18
+ # 表观年龄>60岁的角色有死亡风险,年纪越大风险越高,>100岁99%会死亡
19
+ if character.apparent_age > 60:
20
+ death_probability = min(0.01 * (character.apparent_age - 60), 0.99)
21
+ if random.random() < death_probability:
22
+ character_die_callback(character)
23
+ die_count += 1
24
+ print(f"{die_count}人寿终正寝了")
25
+
26
+ def execute(self, *args, **kwargs):
27
+ self.grow_characters(*args, **kwargs)
28
+
plugins/CultivationPlugin.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import random
2
+ class CultivationPlugin:
3
+ def __init__(self, cultivation_speed=1.0):
4
+ self.cultivation_speed = cultivation_speed
5
+
6
+ def cultivate_characters(self, characters, world_spiritual_energy, init_world_spiritual_energy, consume_spiritual_energy_callback):
7
+ for character in characters:
8
+ if sum(character.spiritual_roots) > 0:
9
+ cultivation_speed = self.cultivation_speed * [0, 1.2, 1, 0.8, 0.6, 0.5][sum(character.spiritual_roots)] # 灵根数量惩罚
10
+
11
+ # 根据特殊体质修炼速度进行调整
12
+ if character.special_constitution[2] == 1: # 灵龟体质
13
+ cultivation_speed *= 0.5
14
+ elif character.special_constitution[3] == 1: # 蜉蝣体质
15
+ cultivation_speed *= 2
16
+
17
+ if world_spiritual_energy > 0:
18
+ cultivation_speed *= world_spiritual_energy / init_world_spiritual_energy
19
+ success_rate = 1 - 0.2 * random.random()
20
+ character.cultivate(1000 * cultivation_speed * success_rate)
21
+
22
+ consume_amount = 10 * cultivation_speed * success_rate
23
+ consume_spiritual_energy_callback(consume_amount) # 消耗灵气
24
+ character.consume_spiritual_energy += consume_amount
25
+
26
+ else:
27
+ # 没有灵气,无法修炼了
28
+ pass
29
+
30
+ def execute(self, characters, world_spiritual_energy, init_world_spiritual_energy, consume_spiritual_energy):
31
+ self.cultivate_characters(characters, world_spiritual_energy, init_world_spiritual_energy, consume_spiritual_energy)
plugins/DisasterPlugin.py ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import random
2
+
3
+ class DisasterPlugin:
4
+ def __init__(self, disaster_frequency, disaster_prob):
5
+ self.disaster_frequency = disaster_frequency
6
+ self.disaster_prob = disaster_prob
7
+
8
+ def trigger_disaster(self, characters, character_die_callback):
9
+ print("发生自然灾难...")
10
+ num_killed = int(len(characters) * self.disaster_prob)
11
+ killed = random.sample(characters, num_killed)
12
+ for c in killed:
13
+ c.history.append(f"{c.real_age}岁,死于自然灾难")
14
+ character_die_callback(c)
15
+
16
+ def execute(self, characters, round_num, character_die_callback):
17
+ if round_num % self.disaster_frequency == 0 and random.random() < self.disaster_prob:
18
+ self.trigger_disaster(characters, character_die_callback)
plugins/MarriagePlugin.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import random
2
+ class MarriagePlugin:
3
+ def __init__(self, marriage_rate):
4
+ self.marriage_rate = marriage_rate
5
+
6
+ def perform_marriages(self, characters):
7
+ # 随机一些表观年龄>20的角色结婚
8
+ eligible_characters = [character for character in characters if character.apparent_age > 20 and character.partner is None]
9
+ new_couple_count = 0
10
+ for _ in range(int(len(eligible_characters) * self.marriage_rate)):
11
+ character = random.choice(eligible_characters)
12
+ partner = random.choice(eligible_characters)
13
+ if character != partner and character.gender != partner.gender and character.partner is None and partner.partner is None:
14
+ character.marry(partner)
15
+ new_couple_count += 1
16
+ print(f"{new_couple_count}对新人结婚了")
17
+
18
+ def set_marriage_rate(self, marriage_rate):
19
+ self.marriage_rate = marriage_rate
20
+
21
+ # 统一插件接口
22
+ def execute(self, *args, **kwargs):
23
+ self.perform_marriages(*args, **kwargs)
plugins/ResourceDepletionPlugin.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import random
2
+ class ResourceDepletionPlugin:
3
+ def __init__(self, depletion_threshold, death_rate = 0.3):
4
+ self.depletion_threshold = depletion_threshold
5
+ self.death_rate = death_rate
6
+
7
+ def trigger_disaster(self, characters, character_die_callback):
8
+ print("资源耗尽! 发生灾难...")
9
+
10
+ # 按照宗族大小排序
11
+ clan_size = {}
12
+ for c in characters:
13
+ clan_size[c.clan] = clan_size.get(c.clan, 0) + 1
14
+
15
+ clans = sorted(clan_size.items(), key=lambda x: x[1], reverse=True)
16
+
17
+ # 前 50% 大小的宗族,死亡 30%, 后 50% 大小的宗族,死亡 60%
18
+ for i, (clan, size) in enumerate(clans):
19
+ if i < len(clans) // 2:
20
+ num_killed = int(size * self.death_rate)
21
+ else:
22
+ num_killed = int(size * (self.death_rate * 2))
23
+
24
+ # 随机选择死亡成员
25
+ clan_members = [c for c in characters if c.clan == clan]
26
+ killed = random.sample(clan_members, num_killed)
27
+
28
+ for c in killed:
29
+ character_die_callback(c)
30
+
31
+ def execute(self, resources, characters, character_die_callback):
32
+ # 检查资源是否耗尽,如果耗尽则触发灾难
33
+ if resources < self.depletion_threshold:
34
+ self.trigger_disaster(characters, character_die_callback)
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ gradio
2
+ numpy
3
+ matplotlib
run.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from CharacterStatistics import CharacterStatistics
2
+ from WorldSimulation import WorldSimulation
3
+
4
+ # 创建一个世界模拟对象
5
+ simulation = WorldSimulation(special_constitution_ratio=[0.001, 0.001, 0.001, 0.001], spiritual_roots_ratio=[0.04, 0.04, 0.04, 0.04, 0.04], initial_population=3000, world_spiritual_energy=1000000)
6
+
7
+ # 运行模拟
8
+ simulation.add_custom_character("CoraBaby1", "女", special_constitution=[1, 0, 0, 1], spiritual_roots=[1, 1, 1, 1, 1])
9
+ simulation.add_custom_character("CoraBaby2", "女", special_constitution=[0, 1, 0, 1], spiritual_roots=[1, 1, 1, 1, 1])
10
+
11
+ simulation.start_simulation()
12
+ simulation.run_simulation(num_rounds=10)
13
+
14
+ # 查看世界统计
15
+ stats = CharacterStatistics(simulation.characters)
16
+ print(stats.summarize_markdown())
17
+
18
+ print(simulation.characters[0])
19
+ print(simulation.characters[1])
20
+
21
+ print(simulation.dead_characters[0])
22
+ print(simulation.dead_characters[1])
utils.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import string
2
+ import random
3
+
4
+ def get_random_name():
5
+ vowels = "aeiou"
6
+ consonants = "".join(set(string.ascii_lowercase) - set(vowels))
7
+ name = random.choice(consonants).upper()
8
+ name += random.choice(vowels)
9
+ name += random.choice(consonants)
10
+ name += random.choice(vowels)
11
+
12
+ return name
13
+
14
+ def get_random_clan_name():
15
+ vowels = "aeiou"
16
+ consonants = "".join(set(string.ascii_lowercase) - set(vowels))
17
+ name = random.choice(consonants).upper()
18
+ name += random.choice(vowels)
19
+ name += random.choice(consonants)
20
+ name += random.choice(vowels)
21
+ name += random.choice(consonants)
22
+ name += random.choice(vowels)
23
+ name += random.choice(consonants)
24
+ name += random.choice(vowels)
25
+
26
+ return name