有没有办法程序化地产生一个世界的历史?

我在这里发现了一个代表1800年文化史的图表,在某个人创造的想象世界中,我有点兴趣。

在这里输入图像描述

在世界devise方面,这样的东西似乎对游戏开发有很强的应用。

看起来他是亲手做这个图的。 我感兴趣的是看看是否有办法以编程方式创建这种图。

如果你的任务是用随机值的方式生成上述的图表,那么你会怎么做呢? 是否有任何特定的数据结构或algorithm,你会考虑?

你想成为多less准确? 一个好的但复杂的select将模拟所有的历史:

  1. 生成一个随机区域列表和这些区域之间的邻接关系。
  2. 生成具有人口,好战,技术等特征的随机文明,并填充地区。
  3. 根据您的需要模拟多年的历史,根据文明特征确定结果。

例如:两个相邻的好战文明彼此发动战争的概率较高,导致随着时间的推移人口减less。 商人文明拥有更多的资源,但却是入侵的一个很好的目标。 人口密度高的人会增长得快,但也有更多的饥饿机会。 文化异质文明的内部战争的可能性较低(可能导致分裂)。等等…结果也会改变文明的特征:高科技导致更好的交易,更强的武器等等。

这也允许进行一些程序化的叙述:不仅可以输出领土图,而且可以输出历史的文字描述。 你可以使这个系统像你想要的那样复杂。


编辑:这里的挑战不是技术性的,而是调整现实和有趣的历史一代的启发式。 仔细观察,并考虑上述三点……这几乎是你的技术解释! 把它翻译成一个循环(每次迭代可以代表你想要的时间,1年,半年,1个月……)就是这样。 你将不得不工作的内部(数据结构,启发式),并适应你的具体问题和需求。 这是困难的一部分, 没有人可以帮助你,因为它是关于想象力,反复试验。

对于这个问题,除了那些几乎用于任何问题的数据结构之外,没有任何常见的数据结构:列表,队列,树……这些将被绑定到你的具体实现中(我是否需要一个家谱树?文明列表在战争?每个文明的任务队列?)当然,你也需要一个文明清单。 这些select是显而易见的,非常常识。

模拟是一个机会/概率的问题,你可以使用随机数字的方式使它成千上万个不同的方法。 想想其他的模拟游戏,比如足球经理,角色扮演游戏(毕竟,关卡/统计只是战斗模拟 ),策略游戏…这只是特点 (所以你需要一种方式来存储文明特征和数据)并根据统计结果随机产生结果(因此您必须根据这些特征随机更改模拟状态)。

这就是你的algorithm的本质:难以调整启发式:在每个文明的开始时如何分配特征,以及如何根据它们统计地改变模拟状态。

简而言之:您的algorithm只是一个循环,在任何期望的增量范围内模拟时间。 更短的增量导致更好的历史模拟,但显然需要更长的时间。 在你的循环里面会有一些启发式的(粗略的):

for each civilization if civ.isAtWar civ.population -= civ.population * 0.05; civ.wealth -= 1000.0; civ.belligerence += 1.0; if civ.population < 100 civ.negotiatePeace() 

在所有这些工作之后(或者在你不想存储数据的时候),你必须将所有的模拟状态解释为人类可读的格式,如文本,图像或任何你想要的东西。 这也是试验和错误,对于您的实施非常具体。

具体到你的问题:要生成一个像你的问题的图,你将不得不跟踪世界地区(图顶部,x轴,这是第1点:生成区域列表在我的答案)和他们的文明(颜色图2 )通过时间(y轴, 点3的模拟循环)。

状态机在模拟广泛的主题(上面的代码示例是一个硬编码状态机的近似值)方面相当出色 – 所以您可以从实现一个总体上易于调整的简单状态机框架开始。 每个文明将从这些状态机器中的一个开始,并且模拟将在每个回合中运行每个状态机器。 每个状态机需要能够与其他状态机交互:例如,发起战争会影响另一个文明的状态机,可能根据其内部状态产生不同的结果 – 例如,如果它们处于“饥荒”状态,他们可能想和平谈判,但是一个文明“寻找麻烦”可能会报复。 在每一个“框架”(财富,好战,大众等)期间,机器中的每一个状态都将对上文所述的文明指标产生有意义的影响。 最重要的是,您不需要在每一帧都进行状态转换 – 只要有机会和/或随机机会出现时:这就允许发生长时间的事件(如战争)。

就在这里。 这是一个简单的历史生成器:

 #!/usr/bin/env python # to create a visualisation, run like this: # ./timeline.py --dot | dot -Tpng > filename.png import sys import random from pprint import pprint # Names is a newline separated list of nation names. file = "names.txt" names = open(file, "r").read().split("\n") history = [] dot = False if len(sys.argv) > 1 and sys.argv[1] == "--dot": dot = True def wrap(str, wrap='"'): return wrap+str+wrap def merge(states, names): number = random.randint(2,3) mergers = [] if number < len(states): mergers = random.sample(states, number) new_name = random.choice(names) states = list(set(states).difference(set(mergers))) states.append(new_name) names.remove(new_name) if dot: for state in mergers: print '"%s" -> "%s"'%(state, new_name) print '{rank=same; %s }'%wrap(new_name) else: print "MERGE %s ==> '%s'"%( ", ".join(map(wrap,mergers)), new_name) return states, names def split(states, names): number = random.randint(2,3) if number < len(names): splitter = random.choice(states) states.remove(splitter) new_states = random.sample(names, number) names = list(set(names).difference(set(new_states))) states = list(set(states).union(set(new_states))) if dot: for state in new_states: print '"%s" -> "%s"'%(splitter, state) print '{rank=same; %s }'%("; ".join(map(wrap, new_states))) else: print "SPLIT '%s' ==> %s"%(splitter, ", ".join(map(wrap,new_states))) return states, names def revolt(states, names): old = random.choice(states) new = random.choice(names) names.remove(new) states.remove(old) states.append(new) if dot: print '"%s" -> "%s"'%(old, new) print '{rank=same; "%s"}'%new else: print "REVOLT '%s' ==> '%s'"%(old, new) return states, names def conquest(states, names): if len(states) > 1: loser = random.choice(states) states.remove(loser) winner = random.choice(states) if dot: print '"%s" -> "%s" [label="conquered by"]'%(loser, winner) else: print "CONQUEST '%s' conquered '%s'"%(winner, loser) return states, names #ignore empty names names = [name for name in names if name] #yes, really. origin = random.sample(names, random.randint(1,3)) names = list(set(names).difference(set(origin))) history.append(origin) #random starting states if dot: print "digraph g {" print "{rank=same; %s}"%("; ".join(map(wrap,origin))) else: print("BEGIN %s"%(", ".join(map(wrap,history[0])))) while names: func = random.choice([merge, split, revolt, conquest]) states, names = func(history[-1], names) history.append(states) if dot: print '{rank=same; %s}'%("; ".join(map(wrap,history[-1]))) print "}" else: print "END %s"%(", ".join(map(wrap,history[-1]))) 

它产生这样的输出:

在这里输入图像描述

调整启发式来创建不同的图表。

最简单的方法是将func = random.choice([merge, split, revolt, conquest])行更改为具有多个同名的函数。 例如, func = random.choice([merge, split, revolt, conquest, merge, merge])会导致国家更频繁的合并。