Небольшое вступление
Да-да, я опоздал с темой тёмного леса лет на десять. Хайп прошёл, пыль уляглась, обсуждения закончились, читатели переключились на другие книги, зрители посмотрели сначала один сериал, потом, возможно, другой.
Но мне всё никак не давал покоя вопрос: а реалистично ли описан мир в книге? Действительно ли цивилизации ведут себя рационально, или, может быть, у них есть какой-то другой выбор? Понятно, что исключительно умозрительно этот вопрос не решишь, надо опираться на какие-то данные. Именно поэтому я и решил написать простенький симулятор галактики, в которой рождаются и умирают разные цивилизации, для того, чтобы погонять его с разными настройками и увидеть, какая же стратегия самая разумная (если такая вообще найдётся).
Спойлер для тех, кто вообще не понимает, о чём речь
Гипотеза "Тёмного леса" взята из книги (вы не поверите) "Тёмный лес", которая, в свою очередь, является частью трилогии "Воспоминания о прошлом Земли". Саму трилогию я рекомендую вам прочитать, она небезынтересна (хотя ближе к концу, конечно, складывается ощущение, что автор начал принимать наркотики (осуждаем)). Если в двух словах и без спойлеров, то это серия про контакт людей с инопланетянами, развернувшуюся на этом фоне политическую борьбу, технологии и простых советских китайских учёных и инженерах, которые пытаются как-то вырулить из непростой ситуации.
Сама же гипотеза -- один из вариантов ответа на парадокс Ферми, который можно сформулировать так: "Если во вселенной существуют другие цивилизации, то почему мы их не видим?". Лю Цысинь (автор книги) формулирует ответ так: "Мы их не видим, потому что все сидят и ну жужжат".
Но почему они так поступают? Сразу по нескольким причинам.
Во-первых технологический прогресс происходит не линейно. Вчера (по космическим меркам) мы палкой землю ковыряли, а сегодня ракеты в космос запускаем.
Во-вторых угадать намерения каких-нибудь ануннаков с Нибиру крайне сложно.
Наконец, в-третьих в космосе никто не услышит твой крик нет ни полиции, ни судов, а только право сильного. Сплошной анархо-капитализм, в общем.
Суммируя эти тезисы, автор приходит к выводу, что если одна цивилизация находит другую, то самым разумным выбором будет как можно скорее её экстерминировать.
Давайте же пройдёмся по некоторым особенностям реализации для того, чтобы лучше понимать, откуда чего взялось, когда дело дойдёт до чисел и графиков.
Создаём цивилизации
Вот они:
class systems():
def __init__(self, x, y, r, theta, phi, number):
self.x = x
self.y = y
self.r = r
self.theta = theta
self.phi = phi
self.color = '#ffff00'
self.inhabited = False
self.tech = 0
self.radius = 0
self.id = number
self.discovered = []
self.shots = []
self.deathworld = False
self.friendliness = np.random.uniform(0, 1)
self.friendlist = []
self.age = 0Давайте быстренько пробежимся по полям.
X, y, r, theta, phi нужны для того, чтобы вращать планеты нашей галактики.
Color -- это цвет планет. Необитаемые рисуются жёлтым цветом, обитаемые -- красным, а уничтоженные особо изощрённым способом (об этом ниже) -- синим.
Inhabited -- флаг, который говорит нам о том, появилась ли жизнь на планете или она пока свободна от вращения колеса Сансары.
Tech и radius -- соответственно уровень технологий и радиус обнаружения других цивилизаций.
Id, ну... id, тут особо добавить нечего.
Discovered -- список цивилизаций, которые обнаружила данная.
Shots -- список снарядов, отправленных на уничтожение других цивилизаций.
Deathworld -- флаг, говорящий, уничтожена ли планета без возможности зарождения жизни вновь.
Friendliness -- степень дружелюбности. Я посчитал, что симуляция тотального космоцида не слишком интересна, потому оставил цивилизациям некоторые шансы на кооперацию. Впрочем, про механики будет ниже.
Friendlist -- список друзей цивилизации. Друзей мы не атакуем.
Age, как многие уже догадались, это возраст цивилизации. В сущности, критерий её успешности.
Тут стоит сделать некоторое количество оговорок.
Я считаю, что цивилизация всегда тусует на одной планете, не занимаясь колонизацией. Конечно, можно было бы угореть и реализовать космическую экспансию с колонизационными кораблями, перехватом разведданных и прочим, но в какой-то момент в моей голове кристально чисто сформировалась мысль: "Мы тут не "Стелларис" делаем". Я её даже перевёл на английский ("We are not creating "Stellaris") и сделал акронимом: WANCS. И с его помощью объяснял себе (а теперь и вам) любые разумные упрощения. Примерно так вот выглядел мой внутренний диалог время от времени:
-- Почему уровень технологий это одно число? Ведь науки разные!
-- Знаешь, делать разные технологии это WANCS
Исходя из того же принципа у планет только две координаты. Да, галактика трёхмерна, но она скорее длинная и широкая, так что мне показалось уместным представить её плоским блином.
Да, кстати, дело теперь происходит в галактике (абстрактной), а не во вселенной вообще. Впрочем, всё равно это выглядит как много кружочков, так что можете представлять себе и вселенную, если так будет приятней.
Ну и другие упрощения тоже присутствуют: значения дружелюбия, например, никогда не меняется для одной цивилизации, на планетах не случаются катаклизмы и военные перевороты, а наука всегда движется вперёд.
Вдыхаем в цивилизации жизнь
Чем же наши цивилизации занимаются?
Мне совесть как-то не позволяет вываливать код сомнительного качества на читателя целиком, так что ограничусь поверхностным обзором.
Во-первых цивилизации наращивают свой радиус обнаружения других и технологии.
Радиус вот так:
def radius_inc(planet):
n = np.random.uniform(1e3 + 1)
if n >=1e3:
return 1
if planet.tech < float(tech_plato) and planet.radius < float(radius_plato):
return (planet.tech / 10) * ((1 + len(planet.friendlist)) * friend_mul if len(planet.friendlist) != 0 else 1)
else:
return np.random.uniform(0, 0.001) * ((1 + len(planet.friendlist)) * friend_mul if len(planet.friendlist) != 0 else 1)А технологии вот так:
def tech_inc(planet):
n = np.random.uniform(1e3 + 1)
if planet.tech <= float(tech_plato):
if n >= 1e3:
return 1
else:
return np.random.uniform(0, 0.01) * ((1 + len(planet.friendlist)) * friend_mul if len(planet.friendlist) != 0 else 1)
else:
return np.random.uniform(0, 0.01)Что тут можно заметить?
Во-первых я оставляю место для некоторого технологического скачка, прорыва в науке. Он должен происходить не очень часто, но если цивилизации подфартит (можно отыгрывать в голове плеяду выдающихся учёных), то она двинет свою науку куда дальше, чем другие, за то же самое время. Почему это важно -- расскажу чуть ниже.
Во-вторых можно заметить, что прирост зависит от количества друзей и некоего friend_mul. Это множитель, который показывает, насколько цивилизациям выгодно сотрудничать друг с другом. И в самом деле: если уж мы подружились с какими-то осьминожками с другого конца галактики так давайте с ними меняться технологиями! Ценители могут выбрать другой вариант взаимодействия, конечно. Но потом -- меняться технологиями! Ну и тут же отметим, что радиус обнаружения зависит от уровня технологий, что, как мне кажется, логично.
В-третьих величина радиуса достигает некоторого значения radius_plato, а потом прирастает в час по чайной ложке. Это такой способ показать какие-то фундаментальные ограничения, предел, за которым быстрое получение сведений и взаимодействие вообще невозможно. Впрочем, в трилогии (осторожно, спойлер!) встречаются n-мерные пространства и прочая техномагия, так что этот параметр можно со спокойной душой крутить туда-сюда.
Что же происходит, когда одна планета попадает в радиус другой? Они решают, дружить или не дружить следующим образом:
def friend_or_foe(planet_one, planet_two):
global friend_chance
chance = np.random.uniform(0, 1)
if (planet_one.friendliness + planet_two.friendliness) / float(friend_chance) >= chance:
return True
else:
return FalseТут friend_chance по умолчанию равен 1, то есть чтобы цивилизации подружились они не должны быть совсем уж отмороженными сторонниками ксеноцида. Даже более того, я исхожу из предположения, что добрые и вежливые пришельцы убедят поборников чистоты не геноцидить хотя бы их. Но мы, конечно, на стадии экспериментов, покрутим это значение вверх.
Что происходит, если цивилизации подружились понятно: их технологии получают бонус к скорости роста. А что если они встали на путь войны? В дело вступают
Орудия космоцида
Вот такие вот:
class shot():
def __init__(self, shooter, target):
self.x = shooter.x
self.y = shooter.y
self.shooter = shooter
self.target = target
self.theta = shooter.thetaТут, я думаю, всё довольно просто и в каких-то отдельных пояснениях не нуждается. Гораздо интереснее посмотреть на то, что же происходит, когда наш выстрел долетает до цели:
if distance(shot, shot.target) <= 10:
chance = 1 / (1 + 10 ** ((shot.target.tech - shot.shooter.tech)/4.5))
probability = np.random.uniform(0, 1)
if chance >= probability:
shot.target.inhabited = False
shot.target.tech = 0
shot.target.radius = 0
shot.target.color = '#ffff00'
shots.remove(shot)
shot.shooter.discovered.remove(shot.target.id)
deathworld = np.random.uniform(0, 1)
chance = np.random.uniform(0, 1)
if deathworld > chance:
shot.target.deathworld = True
shot.target.color = '#4F4FD9'
else:
shot.shooter.discovered.remove(shot.target.id)
shots.remove(shot)
if shot.shooter.id not in shot.target.discovered:
shot.target.discovered.append(shot.shooter.id)
shots.append(s(shot.target, shot.shooter))Обращу внимание на вот эту строку:
chance = 1 / (1 + 10 ** ((shot.target.tech - shot.shooter.tech)/4.5)Тут мы, используя логистическую функцию, определяем вероятность успешной атаки. Если показатели технологии цели и стрелка равны, то шанс составляет 0,5 (что, вроде бы, разумно).
Но даже если уровень технологии стрелка 10, а цели всего 1, то у неё есть мизерный шанс отразить нападение. Можно представить себе, что цивилизация, заприметив несущееся на неё... эээ... что-то начала учить физику, вкладываться в технологии, переводить бабушек через дорогу и в героическом порыве отразила атаку. И если ей это удалось, то она узнаёт координаты стрелка и расчехляет уже свои орудия уничтожения.
Здесь же заметим, что с некоторым шансом цивилизацию можно уничтожить настолько на отличненько, что её планета станет миром смерти.
Вот, кажется, и всё из интересного и необходимого для понимания механики. А, ну стоит ещё сказать, что я буду крутить настройки при генерации 100 цивилизаций (как раз в проценты будет удобно переводить) и останавливать симуляцию когда положение вещей более-менее устаканится.
Давайте же взглянем на примеры.
Тотальная резня
Прежде всего, конечно же, мне было интересно покрутить параметры вражды и вероятности появления жизни вверх и посмотреть, что выйдет.
Здесь можно увидеть гифку

А тут просто посмотреть на результат

Я, конечно, ждал чего-то такого, но чтобы осталась только одна цивилизация... Впрочем, может быть дело в том, что я выкрутил пределы развития технологии и радиуса обнаружения слишком высоко? Давайте попробуем то же самое, но с более низким пределом.
Гиф

Картинка

Интереса ради построим зависимость возраста (вертикальная ост) от дружелюбия (горизонтальная ось):

Дружат все!
Теперь давайте посмотрим на другой вариант: враждовать никто не стремиться, а сотрудничать выгодно.
Гиф

Картинка

Теперь выживших гораздо больше и по графику просто так не поймёшь, есть ли какая-то закономерность между дружелюбием и возрастом. Впрочем, скользящее среднее показывает, что, вроде бы, злым быть чуть выгоднее даже когда все вокруг добрые (особенно если все вокруг добрые?):

Но это всё, конечно, баловство. Давайте посмотрим, что мы увидим в условиях, когда жизнь зарождается редко а вселенная умеренно враждебна (что-то похожее на мир вокруг нас).
Согласны? Узнали?
Я конечно, не большой специалист по космическим цивилизациям, но вышло очень похоже на наш мир
Гиф

Картинка

Одинокая цивилизация, раскинувшая сенсоры, навострившая уши, смотрящая во все глаза (и во все стороны), не способная найти другой жизни вокруг.
На несколько мгновений мне стало даже грустно, а потом я подумал, что, пожалуй, лучше быть одним, но живым, чем с соседями, но с friendliness 0,001.
Вместо выводов
Как ни странно, даже такая грубая симуляция навела меня на некоторые мысли. Итак, если вы космическая цивилизация и ещё не определились со своей стратегией, то записывайте:
Постарайтесь появиться на окраине галактики. Так меньше шансов, что вас кто-то найдёт.
Если завели хотя бы одного друга, то постарайтесь заводить друзей и дальше, это выгодно скажется на вашей науке и технике.
Всё, конечно, зависит от настроек вселенной, но если вы в принципе возникли и не видите никого вокруг, то это, возможно, значит, что никого и нет. Грустить тут или радоваться зависит от вашего взгляда на жизнь.
Быть злым параноиком в целом нормальная стратегия, если вокруг вас куча других цивилизаций.
С другой стороны, вообще по барабану какой ты: добрый или злой, важно насколько ты продвинутый технологически.
Возможно, вы живёте в симуляции с ��е очень хорошим кодом
Ссылка на гит, если вдруг захотите позалипать самостоятельно.
