yingqianjiang-lingoace commited on
Commit
0a0d866
1 Parent(s): 4e30523
Character.py CHANGED
@@ -18,6 +18,7 @@ class Character:
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 = []
@@ -27,7 +28,7 @@ class Character:
27
  self.clan = clan # 宗族
28
 
29
  def die(self):
30
- if self.is_alive and self.cultivation_rank < IMMORTAL_RANK:
31
  self.history.append(f"{self.real_age}岁,死亡")
32
  self.special_history.append(f"{self.real_age}岁,死亡")
33
  self.is_alive = False
@@ -37,7 +38,7 @@ class Character:
37
  print("角色已经死亡,无法进行修炼。")
38
  return
39
  # 成仙者不再修炼
40
- if self.cultivation_rank >= IMMORTAL_RANK:
41
  return
42
 
43
  self.experience_points += experience_points
@@ -56,12 +57,17 @@ class Character:
56
  self.experience_points = 0
57
  self.history.append(f"{self.real_age}岁,突破成功,在{cultivation_level}级, 到达{self.view_rank()}")
58
  self.special_history.append(f"{self.real_age}岁,突破成功,在{cultivation_level}级, 到达{self.view_rank()}")
 
 
 
 
 
59
  else:
60
  self.history.append(f"{self.real_age}岁,突破失败,在{self.cultivation_level}级")
61
 
62
  def marry(self, partner):
63
  # 成仙者不再结婚
64
- if self.cultivation_rank >= IMMORTAL_RANK:
65
  return
66
  if not self.is_alive:
67
  print("角色已经死亡,无法结婚。")
@@ -86,7 +92,7 @@ class Character:
86
 
87
  def give_birth(self):
88
  # 成仙者不会生育
89
- if self.cultivation_rank >= IMMORTAL_RANK:
90
  return
91
  if not self.is_alive:
92
  print("角色已经死亡,无法生育。")
@@ -116,7 +122,7 @@ class Character:
116
 
117
  def grow(self):
118
  # 成仙者不会衰老
119
- if self.cultivation_rank >= IMMORTAL_RANK:
120
  return
121
  self.real_age += 1
122
 
@@ -142,7 +148,7 @@ class Character:
142
  attack_power = (self.cultivation_rank + 1) * 30 + 1 * (1 + self.cultivation_level)
143
  defense_power = (self.cultivation_rank + 1) * 30 + 1 * (1 + self.cultivation_level)
144
  attack_speed = (self.cultivation_rank + 1) * 30 + 1 * (1 + self.cultivation_level)
145
- health_points = (self.cultivation_rank + 1) * 60 + 2 * (1 + self.cultivation_level)
146
 
147
  # 根据修为层次计算加成比例,初始加成为10%
148
  bonus = 0.1 * (self.cultivation_rank * 0 + 1)
@@ -161,18 +167,18 @@ class Character:
161
  defense_power *= 1 + bonus
162
 
163
  return {
164
- 'attack_power': attack_power,
165
- 'defense_power': defense_power,
166
- 'attack_speed': attack_speed,
167
- 'health_points': health_points
168
  }
169
 
170
  def before_battle(self):
171
  self.combat_power = self.calculate_combat_power()
172
 
173
- def attack(self, opponent):
174
  # 成仙者不会打架
175
- if self.cultivation_rank >= IMMORTAL_RANK:
176
  return
177
  if not self.is_alive:
178
  print("角色已经死亡,无法攻击。")
@@ -182,8 +188,33 @@ class Character:
182
  if self.special_constitution[0] == 1:
183
  self.buff = True
184
 
185
- # TODO: 考虑攻击速度
186
- damage = self.combat_power['attack_power'] - opponent.combat_power['defense_power']
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
  if damage > 0:
188
  opponent.combat_power['health_points'] -= damage
189
 
 
18
  self.combat_power = self.calculate_combat_power()
19
  self.partner = partner
20
  self.is_alive = True
21
+ self.is_immortal = False
22
  self.buff = False
23
  self.history = []
24
  self.special_history = []
 
28
  self.clan = clan # 宗族
29
 
30
  def die(self):
31
+ if self.is_alive and not self.is_immortal:
32
  self.history.append(f"{self.real_age}岁,死亡")
33
  self.special_history.append(f"{self.real_age}岁,死亡")
34
  self.is_alive = False
 
38
  print("角色已经死亡,无法进行修炼。")
39
  return
40
  # 成仙者不再修炼
41
+ if self.is_immortal:
42
  return
43
 
44
  self.experience_points += experience_points
 
57
  self.experience_points = 0
58
  self.history.append(f"{self.real_age}岁,突破成功,在{cultivation_level}级, 到达{self.view_rank()}")
59
  self.special_history.append(f"{self.real_age}岁,突破成功,在{cultivation_level}级, 到达{self.view_rank()}")
60
+ # 判断是否达到成仙的条件
61
+ if self.cultivation_rank >= IMMORTAL_RANK:
62
+ self.is_immortal = True
63
+ self.history.append(f"{self.real_age}岁,成仙了")
64
+ self.special_history.append(f"{self.real_age}岁,成仙了")
65
  else:
66
  self.history.append(f"{self.real_age}岁,突破失败,在{self.cultivation_level}级")
67
 
68
  def marry(self, partner):
69
  # 成仙者不再结婚
70
+ if self.is_immortal:
71
  return
72
  if not self.is_alive:
73
  print("角色已经死亡,无法结婚。")
 
92
 
93
  def give_birth(self):
94
  # 成仙者不会生育
95
+ if self.is_immortal:
96
  return
97
  if not self.is_alive:
98
  print("角色已经死亡,无法生育。")
 
122
 
123
  def grow(self):
124
  # 成仙者不会衰老
125
+ if self.is_immortal:
126
  return
127
  self.real_age += 1
128
 
 
148
  attack_power = (self.cultivation_rank + 1) * 30 + 1 * (1 + self.cultivation_level)
149
  defense_power = (self.cultivation_rank + 1) * 30 + 1 * (1 + self.cultivation_level)
150
  attack_speed = (self.cultivation_rank + 1) * 30 + 1 * (1 + self.cultivation_level)
151
+ health_points = (self.cultivation_rank + 1) * 90 + 3 * (1 + self.cultivation_level)
152
 
153
  # 根据修为层次计算加成比例,初始加成为10%
154
  bonus = 0.1 * (self.cultivation_rank * 0 + 1)
 
167
  defense_power *= 1 + bonus
168
 
169
  return {
170
+ 'attack_power': math.ceil(attack_power),
171
+ 'defense_power': math.ceil(defense_power),
172
+ 'attack_speed': math.ceil(attack_speed),
173
+ 'health_points': math.ceil(health_points),
174
  }
175
 
176
  def before_battle(self):
177
  self.combat_power = self.calculate_combat_power()
178
 
179
+ def attack(self, opponent, params={"P_CRIT": 0.2, "P_DODGE": 0.05, "P_BLOCK": 0.1, "P_COUNTER": 0.05}):
180
  # 成仙者不会打架
181
+ if self.is_immortal:
182
  return
183
  if not self.is_alive:
184
  print("角色已经死亡,无法攻击。")
 
188
  if self.special_constitution[0] == 1:
189
  self.buff = True
190
 
191
+ # 根据攻击速度计算攻击次数
192
+ attack_times = math.ceil(self.combat_power['attack_speed'] / 10)
193
+ # 根据攻击力计算伤害
194
+ damage = self.combat_power['attack_power'] * attack_times
195
+ # 根据防御力计算伤害减免
196
+ damage -= opponent.combat_power['defense_power']
197
+ # 伤害最小为1
198
+ damage = max(1, damage)
199
+ # 根据概率计算暴击
200
+ if random.random() < params['P_CRIT']:
201
+ damage *= 2
202
+ print("暴击!")
203
+ # 根据概率计算闪避
204
+ if random.random() < params['P_DODGE']:
205
+ print("闪避!")
206
+ return
207
+ # 根据概率计算格挡
208
+ if random.random() < params['P_BLOCK']:
209
+ print("格挡!")
210
+ damage = max(1, damage // 2)
211
+ # 根据概率计算反击
212
+ if random.random() < params['P_COUNTER']:
213
+ print("反击!")
214
+ damage = max(1, damage // 2)
215
+ opponent.combat_power['health_points'] -= damage
216
+ return
217
+
218
  if damage > 0:
219
  opponent.combat_power['health_points'] -= damage
220
 
CharacterStatistics.py CHANGED
@@ -32,7 +32,7 @@ class CharacterStatistics:
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):
@@ -62,7 +62,7 @@ class CharacterStatistics:
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)
@@ -81,12 +81,13 @@ class CharacterStatistics:
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):
@@ -96,12 +97,13 @@ class CharacterStatistics:
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):
@@ -110,10 +112,11 @@ class CharacterStatistics:
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 =====")
@@ -177,14 +180,27 @@ class CharacterStatistics:
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"
@@ -194,7 +210,7 @@ class CharacterStatistics:
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
 
 
32
  ax.set_xlabel(attributes[i])
33
  ax.set_ylabel('Frequency')
34
  plt.tight_layout()
35
+ return fig
36
 
37
  # real_age、apparent_age、cultivation_level、cultivation_rank、孩子数量 统计平均数
38
  def calculate_average_attributes(self):
 
62
  axs[i].set_ylabel('Value')
63
 
64
  plt.tight_layout()
65
+ return fig
66
 
67
  def calculate_average_special_constitution(self):
68
  special_constitution_mean = np.mean(self.characters_array[:, 9:13], axis=0)
 
81
  def plot_sum_spiritual_root_distribution(self):
82
  spiritual_roots_sum = np.sum(self.characters_array[:, 13:18], axis=1)
83
 
84
+ fig = plt.figure()
85
  plt.hist(spiritual_roots_sum, bins=5, range=(0,5))
86
  plt.xlabel('Number of Spiritual Roots')
87
  plt.ylabel('Number of Characters')
88
  plt.title('Distribution of Spiritual Roots')
89
 
90
+ return fig
91
 
92
  # 各灵根人口分布(x轴:5种灵根,y轴:人数)
93
  def plot_spiritual_roots_distribution(self):
 
97
  means = np.mean(spiritual_roots, axis=0)
98
  roots = ['Metal', 'Wood', 'Water', 'Fire', 'Earth']
99
 
100
+ fig = plt.figure()
101
  plt.bar(roots, means)
102
  plt.xlabel('Spiritual Roots')
103
  plt.ylabel('Percentage of Characters')
104
  plt.title('Distribution of Spiritual Roots in Population')
105
 
106
+ return fig
107
 
108
  # 宗族人数分布图
109
  def plot_clan_size_distribution(self):
 
112
  clan_size[c.clan] = clan_size.get(c.clan, 0) + 1
113
 
114
  sizes = list(clan_size.values())
115
+ fig = plt.figure()
116
  plt.hist(sizes, bins=20)
117
  plt.xlabel('Clan Size')
118
  plt.ylabel('Number of Clans')
119
+ return fig
120
 
121
  def summarize(self):
122
  print("===== Character Statistics Summary =====")
 
180
  md += f"{root_names[i]}: {v:.2%}\n\n"
181
 
182
  # md += "### Plotting graphs...\n\n"
183
+ # 画图并保存
184
+ fig1 = self.plot_attribute_distribution()
185
+ # fig1.savefig('./attribute_distribution.png')
186
  # md += "#### Attribute Distribution\n\n"
187
  # md += "![Attribute Distribution](./attribute_distribution.png)\n\n"
188
+
189
+ fig2 = self.plot_spiritual_roots_distribution()
190
+ # fig2.savefig('./spiritual_roots_distribution.png')
191
  # md += "#### Spiritual Roots Distribution\n\n"
192
  # md += "![Spiritual Roots Distribution](./spiritual_roots_distribution.png)\n\n"
193
+
194
+ fig3 = self.plot_sum_spiritual_root_distribution()
195
+ # fig3.savefig('./sum_spiritual_roots_distribution.png')
196
  # md += "#### Sum Spiritual Roots Distribution\n\n"
197
  # md += "![Sum Spiritual Roots Distribution](./sum_spiritual_roots_distribution.png)\n\n"
198
+
199
+ fig4 = self.plot_clan_size_distribution()
200
+ # fig4.savefig('clan_size_distribution.png')
201
  # md += "#### Clan Size Distribution\n\n"
202
+ # md += "![Clan Size Distribution](clan_size_distribution.png)\n\n"
203
+
204
  md += "#### Top Cultivators\n\n"
205
  md += self.print_top_cultivators_markdown()
206
  md += "#### Attack Power Ranking\n\n"
 
210
  md += "#### Top Clans\n\n"
211
  md += self.print_top_clans_markdown()
212
 
213
+ return md, fig1, fig2, fig3, fig4
214
 
215
  def print_top_cultivators(self, top_n=10):
216
 
WorldSimulation.py CHANGED
@@ -30,6 +30,10 @@ class WorldSimulation:
30
  self.dead_characters = []
31
  self.nth_round = 0
32
  self.world_log = []
 
 
 
 
33
 
34
  def log(self, msg):
35
  self.world_log.append(msg)
@@ -40,7 +44,9 @@ class WorldSimulation:
40
 
41
  # 每人可用资源
42
  per_capita_resources = self.resources / len(self.characters)
43
- if per_capita_resources < self.resources_threshold:
 
 
44
  self.birth_plugin.set_birth_rate(LOW_BIRTH_RATE)
45
  self.battle_plugin.set_battle_rate(HIGH_BATTLE_RATE)
46
  else:
@@ -50,7 +56,7 @@ class WorldSimulation:
50
  self.resource_depletion_plugin.execute(per_capita_resources, self.characters, self.character_die)
51
 
52
  self.battle_plugin.execute(self.characters, self.character_die)
53
- self.birth_plugin.execute(self.characters)
54
  self.marriage_plugin.execute(self.characters)
55
  self.cultivation_plugin.execute(self.characters, self.world_spiritual_energy, self.init_world_spiritual_energy, self.consume_spiritual_energy)
56
 
@@ -58,22 +64,30 @@ class WorldSimulation:
58
  md = ""
59
  for _ in range(num_rounds):
60
  self.nth_round += 1
 
 
61
  print(f"第{self.nth_round}轮模拟:")
62
  md += f"第{self.nth_round}轮模拟:\n"
63
  self.simulate_round()
 
 
64
  print(f"当前世界灵气总量:{self.world_spiritual_energy}")
65
  print(f"当前存活角色数量:{len(self.characters)}")
66
  print("")
 
 
67
  md += f"当前世界灵气总量:{self.world_spiritual_energy}\n"
68
  md += f"当前存活角色数量:{len(self.characters)}\n\n"
 
 
69
  if len(self.characters) == 0:
70
  print("所有角色死亡,模拟结束")
71
  md += "所有角色死亡,模拟结束\n"
72
  break
73
  return md
74
 
75
- def add_custom_character(self, name, gender, special_constitution, spiritual_roots):
76
- character = Character(name, gender, special_constitution, spiritual_roots)
77
  self.characters.append(character)
78
 
79
  def create_population(self, initial_population, special_constitution_ratio, spiritual_roots_ratio):
@@ -85,7 +99,7 @@ class WorldSimulation:
85
 
86
  def character_die(self, character):
87
  # 成仙者不会死亡
88
- if character.cultivation_level > IMMORTAL_RANK:
89
  return
90
  character.die()
91
  self.world_spiritual_energy += character.consume_spiritual_energy # 灵气回归
@@ -94,6 +108,11 @@ class WorldSimulation:
94
  character.partner.partner = None # 解除配偶关系
95
  self.characters.remove(character)
96
  self.dead_characters.append(character)
 
 
 
 
 
97
 
98
  def consume_spiritual_energy(self, amount):
99
  self.world_spiritual_energy -= amount
 
30
  self.dead_characters = []
31
  self.nth_round = 0
32
  self.world_log = []
33
+ self.history_population = []
34
+ self.history_spi_energy = []
35
+ self.history_new_birth_count = []
36
+ self.history_dead_count = []
37
 
38
  def log(self, msg):
39
  self.world_log.append(msg)
 
44
 
45
  # 每人可用资源
46
  per_capita_resources = self.resources / len(self.characters)
47
+
48
+ # 资源较少时会降低生育率
49
+ if per_capita_resources < self.resources_threshold * 1.8:
50
  self.birth_plugin.set_birth_rate(LOW_BIRTH_RATE)
51
  self.battle_plugin.set_battle_rate(HIGH_BATTLE_RATE)
52
  else:
 
56
  self.resource_depletion_plugin.execute(per_capita_resources, self.characters, self.character_die)
57
 
58
  self.battle_plugin.execute(self.characters, self.character_die)
59
+ self.birth_plugin.execute(self.characters, self.register_character)
60
  self.marriage_plugin.execute(self.characters)
61
  self.cultivation_plugin.execute(self.characters, self.world_spiritual_energy, self.init_world_spiritual_energy, self.consume_spiritual_energy)
62
 
 
64
  md = ""
65
  for _ in range(num_rounds):
66
  self.nth_round += 1
67
+ self.history_dead_count.append(0)
68
+ self.history_new_birth_count.append(0)
69
  print(f"第{self.nth_round}轮模拟:")
70
  md += f"第{self.nth_round}轮模拟:\n"
71
  self.simulate_round()
72
+ print(f"共死亡{self.history_dead_count[-1]}人!")
73
+ print(f"共{self.history_new_birth_count[-1]}对夫妻生了孩子!")
74
  print(f"当前世界灵气总量:{self.world_spiritual_energy}")
75
  print(f"当前存活角色数量:{len(self.characters)}")
76
  print("")
77
+ md += f"共死亡{self.history_dead_count[-1]}人!\n"
78
+ md += f"共{self.history_new_birth_count[-1]}对夫妻生了孩子!\n"
79
  md += f"当前世界灵气总量:{self.world_spiritual_energy}\n"
80
  md += f"当前存活角色数量:{len(self.characters)}\n\n"
81
+ self.history_spi_energy.append(self.world_spiritual_energy)
82
+ self.history_population.append(len(self.characters))
83
  if len(self.characters) == 0:
84
  print("所有角色死亡,模拟结束")
85
  md += "所有角色死亡,模拟结束\n"
86
  break
87
  return md
88
 
89
+ def add_custom_character(self, name, gender, special_constitution, spiritual_roots, clan=None):
90
+ character = Character(name, gender, special_constitution, spiritual_roots, clan)
91
  self.characters.append(character)
92
 
93
  def create_population(self, initial_population, special_constitution_ratio, spiritual_roots_ratio):
 
99
 
100
  def character_die(self, character):
101
  # 成仙者不会死亡
102
+ if character.is_immortal:
103
  return
104
  character.die()
105
  self.world_spiritual_energy += character.consume_spiritual_energy # 灵气回归
 
108
  character.partner.partner = None # 解除配偶关系
109
  self.characters.remove(character)
110
  self.dead_characters.append(character)
111
+ self.history_dead_count[-1] += 1
112
+
113
+ def register_character(self, character):
114
+ self.characters.append(character)
115
+ self.history_new_birth_count[-1] += 1
116
 
117
  def consume_spiritual_energy(self, amount):
118
  self.world_spiritual_energy -= amount
app.py CHANGED
@@ -1,4 +1,6 @@
1
  import gradio as gr
 
 
2
  from CharacterStatistics import CharacterStatistics
3
  from WorldSimulation import WorldSimulation
4
 
@@ -6,17 +8,16 @@ from WorldSimulation import WorldSimulation
6
  simulation = None
7
  num_rounds = 0
8
 
9
- def initialize_world(world_spiritual_energy=1000000):
10
  global simulation
11
- simulation = WorldSimulation(world_spiritual_energy=world_spiritual_energy)
12
 
13
  return f"世界初始化成功:\n\n世界灵气能量:{world_spiritual_energy}"
14
 
15
-
16
- def add_custom_character(name, gender, special_constitution, spiritual_roots):
17
  special_constitution = [1 if i in special_constitution else 0 for i in range(4)]
18
  spiritual_roots = [1 if i in spiritual_roots else 0 for i in range(5)]
19
- simulation.add_custom_character(name, gender, special_constitution, spiritual_roots)
20
  return str(simulation.characters[-1])
21
 
22
  def start_simulation(c1, c2, c3, c4, r1, r2, r3, r4, r5, initial_population=3000):
@@ -33,6 +34,13 @@ def run_simulation(rounds):
33
  return "请先初始化世界"
34
  return simulation.run_simulation(num_rounds)
35
 
 
 
 
 
 
 
 
36
  def get_character_info(name):
37
  characters = simulation.find_characters_by_name(name)
38
  if len(characters) == 0:
@@ -50,6 +58,11 @@ def get_world_stats():
50
  stats = CharacterStatistics(simulation.characters)
51
  return stats.summarize_markdown()
52
 
 
 
 
 
 
53
  with gr.Blocks() as demo:
54
  # 初始化世界
55
  gr.Markdown("## 初始化世界")
@@ -64,13 +77,14 @@ with gr.Blocks() as demo:
64
  gr.Markdown("每次添加一个,添加完可以继续添加。")
65
  name_input = gr.Textbox(label="姓名")
66
  gender_input = gr.Radio(["男", "女"], label="性别")
 
67
  special_constitution_input = gr.CheckboxGroup(["战斗体质", "合欢体质", "灵龟体质", "蜉蝣体质"], label="特殊体质", type="index")
68
  spiritual_roots_input = gr.CheckboxGroup(["金", "木", "水", "火", "土"], label="灵根", type="index")
69
  add_character_button = gr.Button("添加角色")
70
  new_character_info_output = gr.Textbox(label="新角色信息")
71
  add_character_button.click(fn=add_custom_character, inputs=[name_input,
72
  gender_input,
73
- special_constitution_input, spiritual_roots_input], outputs=new_character_info_output)
74
 
75
  # 生成初始人口
76
  gr.Markdown("## 生成初始人口")
@@ -105,23 +119,66 @@ with gr.Blocks() as demo:
105
  run_simulation_button.click(fn=run_simulation, inputs=[rounds_input], outputs=[simulation_result_output])
106
 
107
  # 查看统计信息
108
- with gr.Accordion("查看统计信息", open=False):
109
- get_stats_button = gr.Button("查看统计信息")
110
  with gr.Box():
111
  world_stats_output = gr.Markdown("")
112
- get_stats_button.click(fn=get_world_stats, inputs=[], outputs=[world_stats_output])
 
 
 
 
 
113
 
114
  # 查看角色信息
115
- with gr.Row():
116
- character_info_output = gr.Textbox(label="角色信息", info="输入角色名字")
117
- get_character_info_button = gr.Button("查看角色信息")
118
- character_info_output_display = gr.Textbox(label="角色信息")
 
119
  get_character_info_button.click(fn=get_character_info, inputs=[character_info_output], outputs=[character_info_output_display])
120
 
121
- with gr.Row():
122
- dead_character_info_output = gr.Number(label="死亡角色信息", info="输入死亡角色序号(按死亡顺序排列)", precision=0)
123
- get_dead_character_info_button = gr.Button("查看死亡角色信息")
124
- dead_character_info_output_display = gr.Textbox(label="死亡角色信息")
 
 
 
 
 
 
 
 
 
125
  get_dead_character_info_button.click(fn=get_dead_character_info, inputs=[dead_character_info_output], outputs=[dead_character_info_output_display])
126
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  demo.queue().launch(debug=True)
 
1
  import gradio as gr
2
+ import pandas as pd
3
+ import numpy as np
4
  from CharacterStatistics import CharacterStatistics
5
  from WorldSimulation import WorldSimulation
6
 
 
8
  simulation = None
9
  num_rounds = 0
10
 
11
+ def initialize_world(world_spiritual_energy=1000000, resources = 100000, resources_threshold = 10):
12
  global simulation
13
+ simulation = WorldSimulation(world_spiritual_energy=world_spiritual_energy, resources=resources, resources_threshold=resources_threshold)
14
 
15
  return f"世界初始化成功:\n\n世界灵气能量:{world_spiritual_energy}"
16
 
17
+ def add_custom_character(name, gender, special_constitution, spiritual_roots, clan=None):
 
18
  special_constitution = [1 if i in special_constitution else 0 for i in range(4)]
19
  spiritual_roots = [1 if i in spiritual_roots else 0 for i in range(5)]
20
+ simulation.add_custom_character(name, gender, special_constitution, spiritual_roots, clan)
21
  return str(simulation.characters[-1])
22
 
23
  def start_simulation(c1, c2, c3, c4, r1, r2, r3, r4, r5, initial_population=3000):
 
34
  return "请先初始化世界"
35
  return simulation.run_simulation(num_rounds)
36
 
37
+ def find_character_by_clan(name):
38
+ characters = simulation.find_characters_by_clan(name)
39
+ if len(characters) == 0:
40
+ return f"没有找到名字为{name}的宗族"
41
+ else:
42
+ return "\n\n".join([str(c) for c in characters])
43
+
44
  def get_character_info(name):
45
  characters = simulation.find_characters_by_name(name)
46
  if len(characters) == 0:
 
58
  stats = CharacterStatistics(simulation.characters)
59
  return stats.summarize_markdown()
60
 
61
+ def plot():
62
+ y = simulation.history_population
63
+ df = pd.DataFrame({"x": np.arange(len(y)), "y": y, "spi_count": simulation.history_spi_energy})
64
+ return df
65
+
66
  with gr.Blocks() as demo:
67
  # 初始化世界
68
  gr.Markdown("## 初始化世界")
 
77
  gr.Markdown("每次添加一个,添加完可以继续添加。")
78
  name_input = gr.Textbox(label="姓名")
79
  gender_input = gr.Radio(["男", "女"], label="性别")
80
+ clan_input = gr.Textbox(label="宗族")
81
  special_constitution_input = gr.CheckboxGroup(["战斗体质", "合欢体质", "灵龟体质", "蜉蝣体质"], label="特殊体质", type="index")
82
  spiritual_roots_input = gr.CheckboxGroup(["金", "木", "水", "火", "土"], label="灵根", type="index")
83
  add_character_button = gr.Button("添加角色")
84
  new_character_info_output = gr.Textbox(label="新角色信息")
85
  add_character_button.click(fn=add_custom_character, inputs=[name_input,
86
  gender_input,
87
+ special_constitution_input, spiritual_roots_input, clan_input], outputs=new_character_info_output)
88
 
89
  # 生成初始人口
90
  gr.Markdown("## 生成初始人口")
 
119
  run_simulation_button.click(fn=run_simulation, inputs=[rounds_input], outputs=[simulation_result_output])
120
 
121
  # 查看统计信息
122
+ get_stats_button = gr.Button("查看统计信息")
123
+ with gr.Accordion("详细文字统计信息", open=False):
124
  with gr.Box():
125
  world_stats_output = gr.Markdown("")
126
+ plot1 = gr.Plot()
127
+ with gr.Row():
128
+ plot2 = gr.Plot()
129
+ plot3 = gr.Plot()
130
+ plot4 = gr.Plot()
131
+ get_stats_button.click(fn=get_world_stats, inputs=[], outputs=[world_stats_output, plot1, plot2, plot3, plot4])
132
 
133
  # 查看角色信息
134
+ with gr.Accordion("查看角色信息", open=False):
135
+ with gr.Row():
136
+ character_info_output = gr.Textbox(label="角色信息", info="输入角色名字")
137
+ get_character_info_button = gr.Button("查看角色信息")
138
+ character_info_output_display = gr.Textbox(label="角色信息")
139
  get_character_info_button.click(fn=get_character_info, inputs=[character_info_output], outputs=[character_info_output_display])
140
 
141
+ # 查看宗族信息
142
+ with gr.Accordion("查看宗族信息", open=False):
143
+ with gr.Row():
144
+ clan_name_input = gr.Textbox(label="宗族名字", info="输入宗族名字")
145
+ get_clan_characters_button = gr.Button("查看宗族角色")
146
+ characters_output_display = gr.Textbox(label="角色信息")
147
+ get_clan_characters_button.click(fn=find_character_by_clan, inputs=[clan_name_input], outputs=[characters_output_display])
148
+
149
+ with gr.Accordion("查看死亡角色", open=False):
150
+ with gr.Row():
151
+ dead_character_info_output = gr.Number(label="死亡角色信息", info="输入死亡角色序号(按死亡顺序排列)", precision=0)
152
+ get_dead_character_info_button = gr.Button("查看死亡角色信息")
153
+ dead_character_info_output_display = gr.Textbox(label="死亡角色信息")
154
  get_dead_character_info_button.click(fn=get_dead_character_info, inputs=[dead_character_info_output], outputs=[dead_character_info_output_display])
155
 
156
+ # 可视化
157
+ btn = gr.Button(value="查看人口图表")
158
+ plot_output = gr.LinePlot(
159
+ x="x",
160
+ y="y",
161
+ title="人口随时间变化图",
162
+ x_title="年份",
163
+ y_title="人口数量",
164
+ overlay_point=True,
165
+ tooltip=["x", "y"],
166
+ width=350,
167
+ height=300,
168
+ )
169
+ btn2 = gr.Button(value="查看灵气图表")
170
+ plot_output2 = gr.LinePlot(
171
+ x="x",
172
+ y="spi_count",
173
+ title="灵气随时间变化图",
174
+ x_title="年份",
175
+ y_title="灵气数量",
176
+ overlay_point=True,
177
+ tooltip=["x", "spi_count"],
178
+ width=350,
179
+ height=300,
180
+ )
181
+ btn.click(plot, outputs=plot_output)
182
+ btn2.click(plot, outputs=plot_output2)
183
+
184
  demo.queue().launch(debug=True)
attribute_distribution.png ADDED
clan_size_distribution.png ADDED
config.py CHANGED
@@ -1,14 +1,14 @@
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
 
1
+ P_DIE_WHEN_LOSE = 0.7 # 战败死亡的概率
2
  MAX_BATTLE_ROUND = 100 # 战斗最大回合数
3
  MARRIAGE_RATE = 0.3 # 每名适龄青年每次模拟找对象的概率
4
 
5
  # 当每人资源大于阈值时,生育率正常,战斗率正常
6
+ NORMAL_BIRTH_RATE = 0.15
7
  NORMAL_BATTLE_RATE = 0.3
8
 
9
  # 当每人资源低于阈值时,生育率线性下降,战斗率线性上升
10
  LOW_BIRTH_RATE = 0.05
11
+ HIGH_BATTLE_RATE = 0.9
12
 
13
  # 每10轮有5%概率发生灾难
14
  DISASTER_PROB = 0.05
plugins/BattlePlugin.py CHANGED
@@ -36,7 +36,8 @@ class BattlePlugin:
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)
 
36
  return (opponent, character)
37
 
38
  def perform_battles(self, characters, character_die):
39
+ # 按照年龄筛选出参战人员,且成仙者不参与战斗
40
+ eligible_characters = [character for character in characters if character.apparent_age > self.min_battle_age and character.check_is_alive() and not character.is_immortal]
41
  for _ in range(int(len(eligible_characters) * self.probability)):
42
  character = random.choice(eligible_characters)
43
  opponent = random.choice(eligible_characters)
plugins/BirthPlugin.py CHANGED
@@ -6,17 +6,13 @@ class BirthPlugin:
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
 
6
  self.birth_age = min_birth_age
7
  self.birth_age_range = birth_age_range
8
 
9
+ def perform_births(self, characters, register_character):
 
10
  for character in characters:
11
  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:
12
+ if random.random() < self.birth_rate:
13
  child = character.give_birth()
14
  if child:
15
+ register_character(child)
 
 
 
16
 
17
  def set_birth_rate(self, birth_rate):
18
  self.birth_rate = birth_rate
plugins/CultivationPlugin.py CHANGED
@@ -14,6 +14,11 @@ class CultivationPlugin:
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()
 
14
  elif character.special_constitution[3] == 1: # 蜉蝣体质
15
  cultivation_speed *= 2
16
 
17
+ # 消耗buff
18
+ if character.buff:
19
+ cultivation_speed *= 1.5
20
+ character.buff = False
21
+
22
  if world_spiritual_energy > 0:
23
  cultivation_speed *= world_spiritual_energy / init_world_spiritual_energy
24
  success_rate = 1 - 0.2 * random.random()
plugins/MarriagePlugin.py CHANGED
@@ -1,11 +1,12 @@
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)
@@ -14,6 +15,8 @@ class MarriagePlugin:
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
 
1
  import random
2
  class MarriagePlugin:
3
+ def __init__(self, marriage_rate, min_marriage_age=20):
4
  self.marriage_rate = marriage_rate
5
+ self.min_marriage_age = min_marriage_age # 最小结婚年龄
6
 
7
+ def perform_marriages(self, characters, callback=None):
8
  # 随机一些表观年龄>20的角色结婚
9
+ eligible_characters = [character for character in characters if character.apparent_age > self.min_marriage_age and character.partner is None and character.check_is_alive() and not character.is_immortal]
10
  new_couple_count = 0
11
  for _ in range(int(len(eligible_characters) * self.marriage_rate)):
12
  character = random.choice(eligible_characters)
 
15
  character.marry(partner)
16
  new_couple_count += 1
17
  print(f"{new_couple_count}对新人结婚了")
18
+ if callback is not None:
19
+ callback(new_couple_count)
20
 
21
  def set_marriage_rate(self, marriage_rate):
22
  self.marriage_rate = marriage_rate
plugins/ResourceDepletionPlugin.py CHANGED
@@ -30,6 +30,8 @@ class ResourceDepletionPlugin:
30
  character_die_callback(c)
31
 
32
  def execute(self, resources, characters, character_die_callback):
33
- # 检查资源是否耗尽,如果耗尽则触发灾难
34
  if resources < self.depletion_threshold:
35
- self.trigger_disaster(characters, character_die_callback)
 
 
 
30
  character_die_callback(c)
31
 
32
  def execute(self, resources, characters, character_die_callback):
33
+ # 检查资源是否耗尽,如果耗尽则有概率触发灾难
34
  if resources < self.depletion_threshold:
35
+ probability = random.random()
36
+ if probability < 0.3:
37
+ self.trigger_disaster(characters, character_die_callback)
spiritual_roots_distribution.png ADDED
sum_spiritual_roots_distribution.png ADDED