这两天去电影院看了《星际穿越》,作为大刘的磁铁发现里面有许多元素和《三体》近乎一样,只是小说文字被好莱坞完美视觉化了,很怀疑导演诺兰在拍这部片子之前是否看过了《三体》。不过无论如何,效果很好,至少有这样的导演能拍出这样的影片,我也才能放心他们把《三体》排成电影而不至于毁了神作。
韩松评论说:看完《星际穿越》,相信任何人都不再怀疑刘慈欣真的是以一己之力把中国科幻提升到了世界水平。他写危机,写末日,写人性的残酷,写世界的恐惧,他把物理学转换为了宇宙级别的画面感,浓墨重彩书写了太空时代男人和女人的情感,并讲述了对终极存在的深入思索。无论在主题主线上,还是在故事情节上,《三体》都与《星际穿越》相得益彰、暗通款曲、密丝严扣。特别是,《三体》到结束时,突破硬科幻的设定,超越物理学,描写了一个只有爱才能拯救宇宙的主题,这也正是《星际穿越》最根本的命题。
好啦,接下来是我从豆瓣“黄药师的日记”那里转载来的对《三体》中提出的黑暗森林理论猜想的Java版简单实现(附上链接:http://www.douban.com/note/319427663/)分享给同样爱好科幻的朋友们。
看过小说《三体》的人应该对黑暗森林这个概念不会陌生,它讲的是在宇宙中文明如果想存活下来,必须对遇到的任何文明发动攻击,并认为这是宇宙的唯一准则。这个理论争论很大。支持的人认为能想出来黑暗森林实在是太伟大了。反对的人认为这不过是科幻小说家的胡思乱想罢了。我认为两者都不对,黑暗森林不过是博弈的一般性推论之一而已。它即切实存在,也不是唯一的存在。
为了说明这一点,我将用程序来模拟实际的情况。
一、文明的外交策略
1、进攻的文明,战争解决一切(attack)
2、友好的文明,提倡互相帮助(friend)
3、以牙还牙的文明,遇到进攻则反击,遇到帮助则互助(revenge)
二、文明的探索策略
1、保守的文明,被动等待其他星球的文明来联系(passive)
2、好奇的文明,主动访问其他文明(active)
三、规则
每个文明初始都是1000000点文明值,当受到攻击时,文明倒退,文明值减少;当受到其他文明帮助时,文明加速进步,文明值增加。当文明值减少到0时,文明消失。
四、参数
文明会随时间发展,每经过一轮,文明会增长d%。
高文明对低文明有高攻击力,好像拿着长矛的军队无论无何也打不过拿着枪的军队。
高文明对低文明也有更多的帮助,发达国家对落后国家不仅有金钱的投资还会带动他们的科技发展。
所以设定:
对其他文明的攻击力 = 自身文明 * a%
对其他文明的帮助力 = 自身文明 * h%
由于文明会随时间按百分比成长,所以这样的简单设定,低文明对高文明影响的百分比会比较小,和上面的要求一致。
五、猜想
当文明间攻击力a相对比较高的时候,进攻的文明更有优势,黑暗森林成立。当文明间帮助力h相对比较高的时候,互助的文明更有优势。当文明增长d相对比较高时,保守的文明更有优势。
附上代码:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
public class BlackForest {
//public static void main(String[] args) {
//Culture c1 = new Culture(VisitType.active, ForeignType.attack);
//Culture c2 = new Culture(VisitType.active, ForeignType.friend);
//for (int i = 0; i < 10000; i++) {
//try {
//c1.develop();
//} catch (RuntimeException e) {
//System.out.println(i);
//throw e;
//}
//}
//foreign(c1, c2);
//System.out.println(c1.toString2() + ":" + c2.toString2());
//}
public static void main(String[] args) {
// 随机建造10000个文明
Random random = new Random();
VisitType[] visitTypes = VisitType.values();
ForeignType[] foreignTypes = ForeignType.values();
List<Culture> activeCultures = new ArrayList<Culture>();
List<Culture> allCultures = new ArrayList<Culture>();
for (int i = 0; i < 10000; i++) {
VisitType visitType = visitTypes[random.nextInt(visitTypes.length)];
ForeignType foreignType = foreignTypes[random
.nextInt(foreignTypes.length)];
Culture c = new Culture(visitType, foreignType);
allCultures.add(c);
if (visitType == VisitType.active)
activeCultures.add(c);
}
result(allCultures);
// 经过500次的轮回
for (int j = 0; j < 500; j++) {
// for (int j = 0; j < 10; j++) {
// 每个文明都能自己发展
for (Culture c : allCultures) {
c.develop();
}
// 激进的文明开始探索
for (Culture c1 : activeCultures) {
if (!c1.isExist())
break;
Culture c2;
while (true) {
c2 = allCultures.get(random.nextInt(allCultures.size()));
if (c2 != c1 && c2.isExist())
break;
}
foreign(c1, c2);
}
// 清除消失的文明
allCultures = delete(allCultures);
activeCultures = delete(activeCultures);
if (j % 50 == 0) {
System.out.print("第" + j + "轮:");
result(allCultures);
}
// 只有一个文明时,进化结束
if (allCultures.size() == 1) {
System.out.print("仅存一个文明,第" + j + "轮:");
result(allCultures);
break;
}
// 所有好奇的文明消失,进化结束
if (activeCultures.size() == 0) {
System.out.print("主动的文明全灭,第" + j + "轮:");
result(allCultures);
break;
}
}
result(allCultures);
}
private static List<Culture> delete(List<Culture> allCultures) {
List<Culture> temp = new ArrayList<Culture>();
for (Culture c : allCultures)
if (c.isExist())
temp.add(c);
return temp;
}
// 文明间交流
private static void foreign(Culture c1, Culture c2) {
// long cc1 = c1.getCulture();
// long cc2 = c2.getCulture();
if (c1.foreignType == ForeignType.revenge) {
// 必须等别人进攻自己后才能报复
c2.foreignType.visit(c2, c1);
c1.foreignType.visit(c1, c2);
} else {
c1.foreignType.visit(c1, c2);
c2.foreignType.visit(c2, c1);
}
// if (c1.getCulture() < 0 || c2.getCulture() < 0)
// System.out.println("c1=" + cc1 + ":" + c1.toString2() + " c2="
// + cc2 + ":" + c2.toString2());
}
// 统计结果
private static void result(List<Culture> allCultures) {
Map<Culture, Integer> result = new HashMap<Culture, Integer>();
for (Culture c : allCultures) {
if (result.containsKey(c)) {
Integer a = result.get(c);
a++;
result.put(c, a);
} else {
result.put(c, 1);
}
}
System.out.println(result);
}
}
// 探索策略:主动探索,被动等待
enum VisitType {
active, passive
}
// 外交策略:进攻,友好,以牙还牙
enum ForeignType {
attack {
public void visit(Culture c1, Culture c2) {
if (c1.getCulture() > 0 && c2.getCulture() > 0) {
// 进攻这个文明
long s = (c1.getCulture() * Culture.a / 100);
if (s < 0)
throw new IllegalStateException("s=" + s + " c1="
+ c1.toString2());
c2.setCulture(c2.getCulture() - s);
// System.out.println(c1 + "把" + c2 + "消灭了"
// + (c1.culture * Culture.a / 100));
}
}
},
friend {
public void visit(Culture c1, Culture c2) {
if (c1.getCulture() > 0 && c2.getCulture() > 0) {
// 帮助这个文明
long s = (c1.getCulture() * Culture.h / 100);
if (s < 0)
throw new IllegalStateException("s=" + s + " c1="
+ c1.toString2());
// System.out.println("s=" + s + " c1=" + c1.toString2());
c2.setCulture(c2.getCulture() + s);
// System.out.println(c1 + "把" + c2 + "帮助了"
// + (c1.culture * Culture.h / 100));
}
}
},
revenge {
public void visit(Culture c1, Culture c2) {
if (c2.foreignType == attack)
attack.visit(c1, c2);
else
friend.visit(c1, c2);
}
};
// c1对c2进行作用
public abstract void visit(Culture c1, Culture c2);
}
class Culture {
public final static int a = 1;
public final static int h = 1;
public final static int d = 0;
private long culture = 1000000;
VisitType visitType;
ForeignType foreignType;//
Culture(VisitType visitType, ForeignType foreignType) {
this.visitType = visitType;
this.foreignType = foreignType;
}
public boolean isExist() {
return culture > 0;
}
public long getCulture() {
return culture;
}
public static long max = Long.MAX_VALUE / 10000;
public void setCulture(long culture) {
// System.out.println("culture="+culture);
if (culture > max)
throw new IllegalStateException();
this.culture = culture;
}
@Override
public int hashCode() {
return visitType.ordinal() * 10 + foreignType.ordinal();
}
@Override
public boolean equals(Object o) {
Culture c = (Culture) o;
return c.visitType == visitType && c.foreignType == foreignType;
}
@Override
public String toString() {
// return visitType + ":" + foreignType + ":" + culture;
return visitType + ":" + foreignType;
}
public String toString2() {
return visitType + ":" + foreignType + ":" + culture;
}
public void develop() {
setCulture(culture * d / 100 + culture);
}
}
六、程序运行
1、由于按百分比的成长是非常快速的。单纯考虑发展时,当将发展参数d设为1%,经过2074轮文明值会超出计算机可正常运算的范围。d设为7%,仅经过305轮文明值会超过计算机的正常运算范围。
考虑到文明还有互相帮助增加发展速度,为了程序能稳定运行500轮左右,将d和h都设为1%。
2、文明的负面效应都是大于正面效应。比如有了刀以后,可能打猎方便了,但刀也能轻易把人杀死。有了核能以后,靠核电站能提供一些电能,但核武器已经足够把地球毁灭多少次了。
所以进攻参数a我设为150%,因为每个文明都拥有足以摧毁自己的力量。
运行结果如下:(参数:a=150, d=1, h=1)
第0轮:{active:attack=1659, active:friend=1604, active:revenge=1643, passive:attack=1681, passive:friend=1668, passive:revenge=1688}
第50轮:{active:attack=831, active:friend=699, active:revenge=713, passive:attack=871, passive:friend=833, passive:revenge=867}
第100轮:{active:attack=328, active:friend=245, active:revenge=245, passive:attack=352, passive:friend=301, passive:revenge=344}
第150轮:{active:attack=50, active:friend=22, active:revenge=17, passive:attack=49, passive:friend=43, passive:revenge=44}
仅存一个文明,第175轮:{active:attack=1}
开始时,基本每种类型的文明都会随机到一千七左右的数量:(请参考最开始说的三种外交策略和两种探索策略,排列组合后一共有6种类型的文明)
运行一段时间后,各类文明都均匀地减少,到175轮时,只剩下一个主动进攻的文明。
这就是黑暗森林的结果,文明只能存在一个。主动进攻的文明未必能比别人活得久,但不主动进攻的文明生存的可能性是0。
3、如果攻击力减少,受到攻击的文明不被一轮秒杀,就能有机会反击了。黑暗森林应该就不成立了。
将攻击参数a由150%降低到100%,运行结果如下:(参数:a=100, d=1, h=1)
第0轮:{active:attack=1675, active:friend=1631, active:revenge=1620, passive:attack=1702, passive:friend=1642, passive:revenge=1637}
第50轮:{active:attack=847, active:friend=777, active:revenge=772, passive:attack=1034, passive:friend=1081, passive:revenge=1063}
第100轮:{active:attack=286, active:friend=280, active:revenge=244, passive:attack=536, passive:friend=616, passive:revenge=621}
第150轮:{active:attack=31, active:friend=31, active:revenge=18, passive:attack=197, passive:friend=248, passive:revenge=264}
第200轮:{active:attack=2, passive:attack=111, passive:friend=115, passive:revenge=126}
主动的文明全灭,第201轮:{passive:attack=111, passive:friend=115, passive:revenge=126}
果然,有机会反击后,主动探索宇宙的文明锐减,最后全部消失。只剩下安于在自己星球的文明生存下来。此时黑暗森林法则不成立。安于在自己星球生存的文明更容易存活的情况,我们暂且称之为乌龟文明。记得霍金就警告过人们不要随便探索宇宙寻找其他文明,看来他是比较同意这种看法的。
4、自身发展d减少,文明主要靠互相帮助来进行进化时(闭关锁国的发展一定是很慢的,所以推测闭星锁球的文明发展也比较慢)
进攻参数a调为1%,发展参数d调为0%,帮助参数h仍为1%,运行结果如下:(参数:a=1, d=0, h=1)
第0轮:{active:attack=1669, active:friend=1680, active:revenge=1648, passive:attack=1649, passive:friend=1701, passive:revenge=1653}
第50轮:{active:attack=1669, active:friend=1680, active:revenge=1648, passive:attack=1649, passive:friend=1701, passive:revenge=1653}
第100轮:{active:attack=1669, active:friend=1680, active:revenge=1648, passive:attack=1649, passive:friend=1701, passive:revenge=1653}
第150轮:{active:attack=1643, active:friend=1680, active:revenge=1648, passive:attack=1649, passive:friend=1701, passive:revenge=1653}
第200轮:{active:attack=1440, active:friend=1680, active:revenge=1648, passive:attack=1649, passive:friend=1701, passive:revenge=1653}
第250轮:{active:attack=1192, active:friend=1680, active:revenge=1648, passive:attack=1649, passive:friend=1701, passive:revenge=1653}
第300轮:{active:attack=919, active:friend=1680, active:revenge=1648, passive:attack=1638, passive:friend=1701, passive:revenge=1653}
第350轮:{active:attack=675, active:friend=1680, active:revenge=1648, passive:attack=1559, passive:friend=1701, passive:revenge=1653}
第400轮:{active:attack=486, active:friend=1680, active:revenge=1648, passive:attack=1370, passive:friend=1701, passive:revenge=1653}
第450轮:{active:attack=327, active:friend=1680, active:revenge=1648, passive:attack=1086, passive:friend=1701, passive:revenge=1653}
第500轮:{active:attack=210, active:friend=1680, active:revenge=1648, passive:attack=834, passive:friend=1701, passive:revenge=1653}
到500轮运行结束时,所有类型的文明都存在,主动进攻的文明最惨,只存活了210个;被动进攻的文明第二惨,存活了834个;其他文明都和开始时没变,存在1700左右的数量。互助的文明胜出。
这称为互助文明,基本就是人类社会的现况吧。光靠自己根本就不能活下去,想要活下去必须靠别人的帮助。和别人交流知识,交易物品,互爱互助。这就是人类社会的准则吧。
七、总结
1、由上面我们可以看出根据不同的参数就会有不同的博弈方式。不管是黑暗森林、乌龟文明,还是互助文明,都是只需要满足一定条件就会成立的法则。坚持其中一个无疑是迂腐的。到底应该何时使用何种策略,具体看当时相互间的利害参数而定。
2、运行结果最出乎意料的是黑暗森林下,所有的文明都死的很快,就算是你看到什么文明就消灭什么文明,但对别的文明探索并消灭你的概率基本没影响。黑暗森林只是保证最后幸存的文明一定是主动进攻型的文明而已。
3、对费米悖论的解释。在人类还没有探索宇宙的时候,我们认为火星上面都是有文明存在的。但探索了以后才发现,原来宇宙里面文明存在概率那么低,低到到目前为止一个都没发现。
为什么宇宙中文明存在如此之少?目前想到的原因是文明的存在条件非常苛刻,所以只有地球上偶然有了文明。
但有没有人想过另外一种可能性:黑暗森林。如果我们附近有其他文明的话,地球就不存在了。这也是基于人择定理的一种推论。也是对费米悖论的一种合理的解释。
4、我们目前最可能存在于何种宇宙规则下的推测:
如果我们存在于互助文明中,宇宙中应该存在大量的文明,我们广播后应该早就被发现,或者干脆还没广播,我们就被其他文明访问了。这也是费米悖论。
如果我们存在于乌龟文明中,广播是最危险的,被保守的好战文明发现,我们就是个死。
如果我们存在于黑暗森林中,宇宙中几乎没有文明,而我们广播暴露自己的可能性就很小了。
事实上我们也正在宇宙中广播自己,并且我们还好好地活着,所以我们存在于黑暗森林的可能性非常大。
5、为什么程序会如此简单?你的模型是否过于简单?面对这样的问题我引用原作中的一句话来作为答复:
“星星都是一个个的点,宇宙中各个文明社会的复杂结构,其中的混沌和随机的因素,都被这样巨大的距离滤去了。那些文明在我们看来就是一个个拥有参数的点,这在数学上就比较容易处理了。”——《三体II 黑暗森林》
6、遗漏的条件。
原作中认为黑暗森林的存在条件是:
i、生存是文明的第一需要
ii、文明不断增长和扩张,但宇宙中的物质总量保持不变
iii、技术爆炸
iv、猜疑链
为什么我的程序中只考虑了第一点。因为我觉得黑暗森林只需要第一点就能实现了。把其他因素考虑进去也能实现黑暗森林,不考虑也能实现黑暗森林的话,按剃刀原理就去除了。
另外猜疑链不是一种实现,而是一个概念,它只代表你无法在事先确认别人的行动而已。其实日常生活中一样存在猜疑链,我们的思维全都自动简化了,所以你没感觉而已。