В рубрике DOU Проекторвсе желающие могут презентовать свой продукт (как стартап, так и ламповый pet-проект). Если вам есть о чем рассказать — приглашаем поучаствовать. Если нет — возможно, серия вдохновит на создание собственного made in Ukraine продукта. Вопросы и заявки на участие присылайте на editors@dou.ua.
Идея
День добрый, друзья! Вопросы возникновенияи развития жизни беспокоят наши умы уже очень давно. Почему? Да потому что это одни из фундаментальных загадок человечества, стоящие рядом со «смыслом жизни», «кто мы такие» и так далее... Вот что об этом пишет википедия:
Возникновение жизни или абиогенез — процесс превращения неживой природы в живую.
Очень простое и емкое определение, не так ли? Разумеется, для понимания того, что такое «живая» и «неживая» материя нужно их как-то разграничить. С точки зрения физики — разницы нет. И то, и то набор электронов, протонов и нейтронов, взаимодействующих между собой по особым правилам. Разница появляется на более высоком (абстрактном) уровне. По сути, живым можно назвать что-то, что существует, размножается и приспосабливается к среде. А этим все живые организмы как раз и занимаются. Но что если биологический сценарий не единственный в своем роде? Споры по этому поводу ведутся и по сей день. В желании доказать тот факт, что живыми могут быть не только клетки, но и машины, — программисты и ученые со всей планеты трудятся над созданием Искусственного Интеллекта. В некотором смысле — это и есть одна из форм альтернативной жизни, речь о которой пойдет далее...
Идея создания эмулятора виртуальной биологической системы возникла у меня пару лет назад. Сложно сказать, что именно стало этому причиной. Вероятно — это результат чтения различной литературы по биологии и генетике, а также лекции профессора Маркова. Для меня изучение и наблюдение природных явлений не сравнится с созданием собственного виртуального мира, где ты обладаешь полным контролем над системой. В общем, я испытываю некое балагоговение при мысли о такого рода программах :) Но давайте по порядку...
Обо мне
Ничего особенного. Обычный программист :) Со школьной скамьи интересуюсь компьютерами. Но помимо кодирования, меня всегда увлекали фундаментальные вопросы: «почему ток бежит по проводам?», «как работает гравитация?», «почему законы физики такие, а не какие-нибудь другие?» и так далее и тому подобное... 5 лет назад меня заинтересовала биология, генетика и эволюционная теория. Такие знания, сами по себе, не применимы в жизни, если ты не ученый или не участник программы «О, счастливчик» с темой «биология» ;) В основном они отталкивают от тебя людей, и ты становишься занудой и ботаном. Но если ты программист :-P, то как велик соблазн попробовать себя в роли создателя :) и понеслась... И все же, когда пыл осядет, а амбиции успокоятся, нужно заглянутьв интернет и проверить что же думает об этом научное сообщество. Так, я узнал о существовании цифровых организмов.
Цифровые организмы
Для начала, дадим определение:
Цифровой организм — самовоспроизводящаяся компьютерная программа, которая мутируети развивается. Цифровые организмы используют в качестве инструмента для изучения динамики эволюции по Дарвину, для тестирования или проверки конкретных гипотез и математических моделей эволюции. Эти исследования тесно связаны с областью создания искусственной жизни.
По сути, мы говорим о маленьких программках, которые выступают в роли биологических организмов. Они живут в памяти компьютера, размножаются, питаются, двигаются, охотятся, в общем, делают все, что присуще их биологическим братьям. Но самое главное — они подчиняются тем же правилам, которым следует все живое на этой планете. Каким? А вот каким:
— размножаться, как можно эффективнее;
— периодически мутировать (меняться);
— передавать все свои свойства следующему поколению.
Эти три принципа лежат в основе виртуального мира, о котором и пойдет речь в этой статье, но об этом немного позже... Что дает нам такая система? Теоретически мы можем прийти к тем же результатам, которыми сами являемся. Я имею ввиду — эволюционный прогресс, и как побочный эффект — сложность живых существ. Почему это важно? По нескольким причинам. Во-первых, мы можем получить различные формы Искусственного Интеллекта в цифровом виде. Во-вторых, такую систему можно использовать, как для изучения эволюции в школах, так и для изучения самой эволюционной теории. И в третьих — это невероятно круто и непонятно к чему именно можно прийти в такого рода экспериментах. А нас всегда манит неизведанное, ведь так? :) Но разумеется, не все так просто. Почему? Потому что, для просчета такой системы, потребуются невероятные вычислительные ресурсы. И даже всех компьютеров планеты для этого не хватит. Да, наша природа обладает невероятно мощным интерпретатором :) Но не стоит унывать, ведь у компании Intel далеко идущие планы, да и виртуальный мир мы можем значительно упростить...
Давайте определимся с базовыми терминами. Каждый раз, когда я ввожу новую концепцию или обсуждаю существующую из обсуждаемого виртуального мира цифровых организмов, Вы можете проводить аналогии с биологической эволюцией. Так, намного проще понимать, о чем идет речь. Например:
— программный код — это то же самое, что ДНКв ядрах наших клеток
— цифровой организм (программа) — это то же, что живой организм (микробы, собаки, мы, бобры и т.д.)
— мутации (изменения) в коде — это мутациив ДНК
— программа, стирающая не приспособленные организмы из памяти — это естественный отбор.
— создание копии цифрового организма с копированием всех свойств — это наследственность.
— функция в коде — ген.
— кроссовер — перемешиваниеженского и мужского генетического материала
— фитнес функция у цифрового организма — приспособленностьу живого
— популяция цифровых организмов — популяцияживых организмов (все суслики на континенте, все люди на планете и т.д.).
Генетический алгоритм
О нем стоит поговорить отдельно, так как это сердце такой системы. Давайте взглянем на эти рисунки:
Это Чарлз Дарвин, которого рисуют с помощью ГА :) На рисунке одна из промежуточных стадий (справа). Компьютерная программа совершенно не знает, что она делает, но, следуя простым правилам, можно нарисовать что угодно. Давайте разберемся, как это работает. Во-первых, программа может рисовать только круги, случайного диаметра и случайного цвета (только оттенки серого). Во-вторых, также случайно, выбирается позиция для рисования. И в-третьих, специальная фитнес функция проверяет, как изменилась картинка после добавления нового кружочка. Если картинка «ближе» к оригиналу Дарвина, то мы говорим о том, что «приспособленность» (или схожесть, по нашему) этого рисунка немного выросла. Если «дальше», то приспособленность уменьшилась и такое решение отбрасывается. Это очень простой пример, но он показывает, как именно работает алгоритм. Еще непонятно? Тогда взгляните на эти примеры:
Кстати, вы можете сами посетить этот сайтгенератора мотоциклов, чтобы все попробовать. Суть данного примера в следующем: программа генератор, на основе генетического алгоритма случайным образом создает круги, треугольники и крутящиеся круги. Они могут крепиться между собой в произвольном порядке. Так создается случайная, первая популяция. Мотоцикл, который проедет дальше всего, будет считаться альфа-мотоциклом, и на его основе будет создана вторая популяция. В этой новой популяции будут только его «дети», но с небольшими изменениями в каждом. И так до бесконечности... Фитнес функция здесь — это расстояние от начальной точки до той, куда новый альфа-мотоцикл сможет доехать. Такая система должна давать все лучшие и лучшие мотоциклы. Второй пример еще интересней :) Некий Карл Симсв далеких
— научиться двигаться от точки А к точке В;
— научиться двигаться по кругу;
— научиться бегать;
— научиться «преследовать» точку (курсор мыши);
— научиться соперничать за куб (кто ближе к кубу, тот выиграл);
— научиться плавать;
— и так далее...
И вот, что из этого получилось:
Теперь, давайте попробуем визуализировать ГА в качестве некоторой последовательности действий:
1. INITIALIZE random organisms 2. EVALUATE each organism (fitness) 3. while !terminated do 4. SELECT parents organisms for next generation 5. RECOMBINE parents 6. MUTATE children 7. EVALUATE each organism (fitness) 8. end
Что это такое? Это имплементация генетического алгоритма на абстрактном языке программирования. Сначала мы создаем рандомную популяцию организмов с пустым кодом (шаг 1). Далее, подсчитываем их «приспособленность» (в нашем случае это количество энергии, шаг 2). Потом, крутимся в цикле, пока не выполнится какое-то условие выхода, будь то время или получение нужного результата... (шаг 3). Находясь внутри цикла, мы выбираем родителей для получения потомства (шаг 4), рекомбинируем их генетический материал — код (шаг 5), немного мутируем этот код (шаг 6) и подсчитываем приспособленность новой популяции (шаг 7). Под новой, в данном случае, подразумевается старая + родившиеся «дети». И так до бесконечности... Напоследок, нужно упомянуть о практическом применении этого алгоритма. Существует множество направлений, где его используют для решения конкретных задач. Ну что, все еще непонятно? Тогда смотрите образовательные видео здесь.
Самой известной программой, реализующей указанные выше принципы, является Avida. По этой ссылке Вы можете ознакомиться с небольшим пояснением того, как она работает. Если захотите понять больше деталей, то вам сюда. Думаю, также стоит упомянуть о прародителях — программах, которые появились задолго до того, как написали Avida. А именно: Tierraи Core Wars, которые внесли свой вклад в развитие этой области. Но все же, я бы хотел представить вашему вниманию свой проект — jevo.
Реализация
Читается, как «джево» или «джей иво» и означает «Julia Evolution». Ничего особенного в этом названии нет, и это никак не связано с эволюцией тех прекрасных особ, которых Мы так любим :) Просто Julia — это язык программирования, а Evolution — ну, сами понимаете. Суть системы проста — это эмулятор виртуального мира, где живут, размножаются и приспосабливаются упомянутые цифровые организмы. Если спросите, как выглядит эта система? Пожалуйста:
Вот, что здесь происходит. Программа, представленная на рисунке — это клиент-серверное приложение. Видите, окошко по центру справа? Это 2D-визуализатор (клиент), который «показывает», что происходит в «их» мире. Цвета означают родство. Чем ближе цвет — тем роднее сосед :) Мир организмов может быть цикличным. Это означает, что, когда кто-то выходит за его пределы, он появляется на другой стороне экрана. Также, как если бы вы ходили вокруг земли. Разноцветные точки — это и есть цифровые организмы (маленькие программы). Небольшое количество зеленых точек — это энергия или еда. Форма рисунка не имеет для нас никакого значения, хотя и может указывать на различные закономерности. Окно слева — сервер. На нем происходит вся магия...
jevo сервер
До тех пор, пока не реализовано распределенное вычисление одной популяции разными инстансами, сервер — это автономный процесс внутри операционной системы, который следит за виртуальным миром организмов и, разумеется, за ними самими. Вот что он делает:
— параллельное выполнение кода всех цифровых организмов (на основе green threads);
— обслуживание столкновений организмов между собой и организмов с энергетическими точками;
— периодические мутации, как всей популяции, так и конкретных организмов;
— уничтожение менее приспособленных: существует как периодическая очистка самых слабых, так и удаление организмов по критерию возраста (По сути это старость. Возраст задается в начальной конфигурации администратором системы);
— управление виртуальным 2D-миром;
— обслуживание удаленных соединений (сюда входят как другие серверы, так и клиенты визуализатора, терминала и модуля статистики);
— парсинг параметров командной строки при запуске;
— и т.д..
Чтобы лучше понять, чем именно занят сервер, давайте взглянем на эту картинку:
Слева — виртуальный 2D-мир, где живут все цифровые организмы. Каждая точка этого мира что-то означает. Черные означают пустоту (ничего нет). Зеленые — это энергия или еда. Все остальные цветные — это организмы. Идем далее. Средний блок. Каждый организм — это набор из параметров и кода. Он управляется виртуальным процессором сервера (virtual CPU), мутирует, рожает себе подобных (clones), содержит энергию, имеет позицию на поле (position) и, наконец, имеет внутреннюю память (memory). С момента создания данной презентации, организмы значительно усложнились и сейчас их свойств больше. Самую важную часть нашего виртуального животного представляет его код. Он формируется из набора поддерживаемых элементов. На текущий момент их 54. А именно:
— математические операции для работы с переменными: +,-,/,%,sqrt,log
;
— функции движения: Creature.stepLeft()
, Creature.stepRight()
, Creature.stepUp()
, Creature.stepDown()
;
— питания: Creature.eatLeft()
, Creature.eatRight()
, Creature.eatUp()
, Creature.eatDown()
;
— бинарные операции: xor
, or
, and
, rshift
, lshift
, not
;
— тригонометрия: sin
, cos
, tan
, cot
, sec
, csc
;
— разные типы: Bool
, Float64
, String
, Int8
, Int16
, Int64
;
— работа с памятью: toMem()
, fromMem()
;
— определение своих и чужих параметров: myX()
, myY()
, energyLeft()...energyDown()
, idLeft()...idDown()
, codeSizeLeft()...codeSizeDown()
, cloneEnergyPercentLeft()...cloneEnergyPercentDown()
;
— возможность примитивного зрения: lookAt(x,y)
;
— элементы языка Julia: циклы — for
, переменные, функции, условия — if
.
Теперь, когда мы знаем, чем именно орудует сервер, давайте опишем общую последовательность действий при его запуске:
1. запускаем сервер;
2. считываем параметры командной строки;
3. если нет сохраненных бекапов, создаем случайную популяцию, исходя из настроек, иначе загружаем все из последнего бекапа;
4. запускаем TCP сервер;
5. создаем 2D-мир;
6. создаем «зеленый поток» для каждого организма и запускаем виртуальный процессор для их выполнения;
7. запускаем основной цикл где мы:
— переключаемся между организмами (псевдопараллельность);
— обновляем их энергию;
— вносим мутации;
— убиваем самых слабых либо состарившихся;
— периодически сохраняем бекапы;
— проверяем, не закончилась ли энергия в 2D-мире и, если нужно, «добрасываем» её.
jevo организм
Давайте поговорим о самих организмах. Как вы помните, это разноцветные точки (кроме зеленых), представленные небольшой программой на языке Julia. Центральным понятием в жизни любого цифрового существа является энергия. Если она заканчивается — организм умирает. Также смерть наступает в результате старости. Поэтому отбор уничтожает тех, кто не смог «найти» пропитание (эту функцию выполняет сервер). Напротив, те у кого энергии хоть отбавляй, имеют значительно больший шанс завести потомство. Почему? Потому что система выбирает с большей вероятностью именно их для создания «детей». Этот факт имеет важные последствия для популяции. Если у небольшой группы организмов появляется признак, который дает им возможность быстрее находить и «съедать» энергию, чем другие, то эти организмы вытесняют всех остальных. Хорошим примером из нашей жизни являемся мы, люди. Мы вытеснили и уничтожили очень многих животных из их привычных ареалов. Таким образом формируется вектор развития всей популяции — «найти как можно больше еды». На системном уровне организм — это структура данных с различными свойствами. Давайте подробнее опишем из чего он состоит:
— Уникальный идентификатор. Этот идентификатор используют функции Creature.idLeft()...Creature.idDown()
. Теоретически, так они могут узнавать своих сородичей или врагов, находящихся слева, справа, сверху и снизу.
— Код. ASTдерево с нескомпилированным кодом организма. Именно в него вносятся мутации.
— Размер кода. Размер считается в строках.
— Мета информация о коде. Техническая информация об AST.
— Вероятностные коэффициенты. Это массив чисел (например: [50,100,1,0,1,1,1,1,1,1]
), который используется для создания вероятностей появления различных видов мутаций. Каждая из позиций определяет определенный вид мутации. Например, число 100 означает, что количество изменений будет наиболее частым, нежели добавлений (50) или удалений (1). Полная расшифровка всех чисел: [добавление,изменение,удаление,маленькое-изменение,процент-мутаций-при-клонировании,период-мутаций,процент-мутаций-с-периодом,мутация-этого-массива,процент-отдачи-энергии-при-клонировании,процент-мусора]
.
— Процент мутаций, которые будут добавлены после деления. По сути — это то, сколько мутаций получит ребенок после рождения. Если это значение высоко (близко к 100), то будет добавлено столько мутаций, сколько строк кода содержит организм.
— Период времени для периодических мутаций. Как часто будут вноситься периодические мутации. Например, каждые 1000 итераций.
— Процент от размера кода периодических мутаций. По сути, это количество мутаций, которые случатся по происхождению времени из предыдущего пункта. Оно зависит от размера кода. Чем длиннее код, тем больше мутаций будет внесено.
— Количество энергии. Именно поэтому система определяет, кто самый успешный.
— Цвет. Меняется каждый раз, когда организм набирает определенное количество мутаций. К примеру, можно менять цвет каждые 50 мутаций.
— Внутренняя память. Сейчас работает, как MAP. Организмы могут записывать и считывать числа из\в нее.
— Позиция (x,y) в 2D-мире.
— Возраст. Оператор может задать возраст организма, при достижении которого он умирает и удаляется из системы.
— Процент энергии, которая будет отдана ребенку после деления. Этим организм регулирует сколько энергии получит его ребенок.
— Процент хранения мусора. Мусор — это случайный код, который добавляется мутатором. Из него иногда получаются новые важные функции. Так, в одной из моих популяций возникло «условное поведение». Читай об этом здесьи здесь.
— Количество мутаций с рождения. Просто счетчик мутаций. Используется в статистике.
Также каждый организм представлен своим собственным кодом, который полностью решает, чем занято виртуальное животное. Этот самый код дописывается системой на основе генетического алгоритма (ГА). Мы говорили о нем в предыдущих разделах. В общем, ГА ищет оптимальное решение для нашей задачи — поиска еды. Причем едой могут быть как энергетические блоки (зеленые точки), так и сами организмы. Пока все понятно? Окей, тогда пришло время глянуть на систему в динамике (смотреть на полный экран и в 1080, иначе ничего не увидите):
Что же мы увидели? Там было много зеленых точек, которые не двигались (это энергия, которую нужно съесть). Около пяти фиолетовых островков — это один из видов цифровых организмов, которые выжидают тех, кто постоянно двигается, и съедают их при приближении. И много движущихся с разной траекторией точек (другие виды организмов — назовем их «бегунцы»). Стоит пояснить, что это результат примерно двухдневного запуска системы. Причем я никак не влиял на процесс их обучения и никак не вмешивался. По сути, мы видим, что эволюционировали две стратегии: «жди и кусай» и «беги и кусай». Давайте ответим на такие вопросы: «Как именно они двигаются?», «Какого размера и какой именно код эволюционировал?», «Почему они все это делают?». Итак, по порядку:
— «Как они двигаются?». В основном «Бегунцы» двигаются по диагонали — потому что она дает возможность «просканировать» все поле и найти максимум энергии. Представьте, что будет, если кто-то двигается только вверх? Рано или поздно он проел бы длинный коридор,в котором бы кончилась энергия. Поэтому диагональное движение имеет значительное преимущество перед прямолинейным. Вторым важным фактом является так называемая форма движения. Они не просто двигаются по диагонали. Их движение напоминает шатающегося влево-вправо человека. Почему это так? Потому что обычное прямолинейное диагональное движение не даст вам возможности выбраться из «засад», созданных другим видом организмов (помните «жди и кусай»). Они формируют так называемые «островки смерти» (в видео выше — это фиолетовые точки). Попав в такой островок, организм будет съеден по прошествии некоторого времени. Вот так:
Рисунки выше показывают две стратегии при встрече с организмами-недругами. Белые стрелки — это траектория движения во время одной итерации (одного выполнения кода организма). Синие квадратики — это «бегунцы». Красные — «организмы охотники». На рисунке слева вы видите, как «бегунец» (синий организм с прямолинейным диагональным движением) попадает в «засаду», созданную «охотниками». Так как в его коде не предусмотрено смены траектории — он точно будет съеден. С другой стороны, на правом рисунке, вы можете видеть, как синие организмы «научились» избегать «островки смерти» — обходя их. Разумеется, при столкновении с таким островком организмы-недруги откусят немного от жертвы. Но тем не менее окончательно они ее не убьют. Эту борьбу вооружений мы также наблюдаем в биологической природе. Например, между охотниками и жертвами. Именно поэтому гепард и антилопа — отличные спринтеры... Стоит также отметить, что данная стратегия движения появилась не сразу. В самом начале, организмы двигались очень примитивно (а при старте системы — они вообще стояли на месте). Прямолинейно вправо, влево, вниз или вверх. Немного позже, появилось диагональное движение. И уже после этого появились приведенные на рисунке «шатания».
— В основном, программы короткие. Почему? Потому что большие программы тратят больше энергии на свое содержание и тем самым энергонеэффективны. Если программа большая, то она должна быть «оптимальна». Ее код должен оправдывать такой размер. В некотором смысле она должна быть умней или хитрей своих коротких сородичей. Пример программ будет приведен чуть ниже в этой статье.
— Почему они это делают? Ответ прост: потому, что их код управляет их поведением полностью.
Мы ведь все тут программисты, правда? Тогда, взглянем на код «затаившегося охотника»:
function (c::Config.ConfigData,o::Creature.Organism) local var_1::Int8 = 110 Creature.eatUp(c,o,Int(var_1)) Creature.eatDown(c,o,Int(var_1)) Creature.eatDown(c,o,Int(var_1)) Creature.eatUp(c,o,Int(var_1)) return true end
Следует также упомянуть, что все начиналось с пустого кода, а если быть точным, то с пустой функции. А пример выше сформировался в результате нескольких десятков тысяч поколений. Что он делает? Эти функции Creature.eatUp()
и Creature.eatDown()
означают «укуси» сверху и снизу относительно собственной позиции. Последний параметр, var_1
— это то, сколько «откусить». Он равен 110. По сути, он просто сидит и ждет пока к нему кто-то подползет, после чего жертва будет съедена. Более того, такие организмы собираются в небольшие кучки, из которой жертве будет выбраться тем сложнее, чем больше охотников в ней будет. Мы называли их «островки смерти». Вы спросите: «Откуда организм знает, какие функции нужно вызывать?» или «Какие функции вообще существуют?». Мутации (или базовые элементы из которых «пишется» код) формируются на основе предустановленного списка, о котором мы говорили немного выше (помните те 54 элемента). Элементы из этого набора вставляются в код случайным образом в разные места по прохождению определенного времени. Как часто мутировать решает сам организм. На самом деле мутации бывают нескольких видов. Основные это: добавление, удаление и модификация кода. Окей, а что по поводу тех «бегунцов», которые все время двигаются? Пожалуйста:
function (c::Config.ConfigData,o::Creature.Organism) local var_1::Int8 = 110 Creature.stepRight(o) Creature.eatRight(c,o,Int(var_1)) Creature.stepRight(o) Creature.eatRight(c,o,Int(var_1)) Creature.eatDown(c,o,Int(var_1)) return true end
В этом листинге вы видите другую стратегию поведения — «беги и кусай». Причем очень важно то, что кусать нужно перед собой. Иначе, наткнувшись на препятствие, организм застрянет и скорей всего умрет от недостатка энергии. Все те, кто так делал, давно вымерли. Небольшим бонусом здесь является «откусывание» снизу — Creature.eatDown()
. Оно дает небольшое преимущество перед теми, кто кусает только впереди себя, так как иногда под тобой может лежать энергия или сосед. Я намеренно показываю простые примеры, чтобы не забивать ваши лобные доли всякой дрянью :) В реальности, как наш ДНК, так и код организмов невероятно сложны. Но именно этого мы и хотим, ведь правда? :) Окей, давайте посмотрим еще немного видео. В нем я покажу, как формируются «переходные формы» и что вообще эволюционировало у меня на домашнем компьютере (смотреть до 34:40):
jevo статистика
В видео презентации, я показывал переходные формы и рассказывал, как эволюционировало движение цифровых организмов. Но что, если взглянуть на этот процесс с высоты птичьего полета и постараться увидеть общую картину? Именно для этого система работала целую неделю в режиме сбора статистики. На её основе были построены графики того, что происходило «под капотом». Горизонталь — это возраст популяции. Вертикаль — значение текущего параметра(ов). Давайте посмотрим:
Этот график показывает, как менялись частоты вызовов функций движения и еды у лучших организмов популяции. По сути, мы видим, что обе функции росли со временем. Примечательно, что рост наблюдается у большинства параметров системы. Взгляните на частоту использования функций:
Красный график явно больше синего, почему? Потому что это количество вызовов функции. Он логически должен быть больше их количества (объявлений). И, пожалуй, последний график на сегодня — использование циклов и условных конструкций в коде:
Результаты
У тебя есть план, мистер Фикс?
Конечно, у меня есть план:
— Упершись в производительность моих домашних компьютеров, я вынужден написать распределенную систему для «больших» вычислений, тогда можно будет говорить о действительно сложном поведении и все станет намного интересней.
— Усложнить мир организмов: добавить день и ночь, камни, третье измерение и другие природные феномены нашего мира. Это заставит организмы вести себя более сложно.
— Добавить примитивы для «общения».
— Реализовать crossover.
— Усложнить язык, на котором пишется код организмов. Сейчас это только 54 элемента языка.
— Добавить третье измерение. Сделать из 2D, 3D-мир.
— Провести оптимизацию системы.
— Если получится, то засунуть лучший код в ардуино робота, как сделалиэти ребята.
— и т.д.
Чего я ожидаю от системы?
— В общем я жду значительного усложнения. Рано или поздно оно должно появиться. Например, это условное поведение: если справа другой организм, убегай; если возле тебя еда, кусай, и т.д.
— Появление примитивного зрения. Это очень важное эволюционное приобретение, сами понимаете ;)
— Появление примитивной коммуникации.
— Кооперация.
— Разнообразие цифровых организмов.
Чего я достиг?
Пока немного. И это только потому, что производительность моего PC очень низкая для такой задачи. А еще у меня очень мало свободного времени :( Но тем не менее, проект растет и усложняется. На данном этапе я работаю над версией 1.1-rc1. После выйдет 1.1. Вся разработка ведется в github. Так вот, список:
— Максимально длинный код, который эволюционировал, составлял 370 строк. Его особенностями были: оптимизированность, реиспользование функций, использование циклов и т.д. Смотри здесьпохожие организмы.
— Появились примитивные алгоритмы сложного движения (смотри презентациюдля деталей), при котором вероятность нахождения энергетических точек значительно увеличивается.
— Эволюционировали две противоборствующие стратегии: «бегунцы» и «затаившиеся охотники», которые борются за ресурсы. Причем интересно то, что одни хищники, а другие, по сути — травоядные :)
— Появилась простейшая кооперация, где от того, как двигается твой сосед зависит, сколько энергии ты найдешь. Если бы они двигались по одиночке, это было бы не так эффективно.
— Во время написания этой статьи появился первый организм, который научился выполнять примитивные логические действия! Для меня это был настоящий праздник! :) Давайте взглянем на ту часть его кода, которая выполняет условную конструкцию:
... var_33 = Creature.energyDown(o) # взять количество энергии "под собой" var_20 = var_20 * var_20 # мусор var_2 = if 127 >= abs(var_2) # мусор Int8(var_2) else 127 end var_2 = if 127 >= abs(var_33) # если снизу энергия/другой организм, то var_2 = 127 иначе var_2 = 0 Int8(var_33) else 127 end for i::Int8 = 1:div(var_2,16) # если var_2 !== 0 (снизу кто-то есть) то крутимся здесь 7 раз local var_36::Int8 = 29 var_36 = if 127 >= abs(1571) # var_36 = 127 всегда Int8(1571) else 127 end Creature.eatDown(c,o,Int(var_36)) # откусываем 127 "энергетических юнитов" от соседа снизу end ...
В двух словах, о том, что здесь происходит. Сначала наш организм проверяет есть ли что-то под ним с помощью функции Creature.energyDown()
. Она возвращает количество энергии (это может быть как обычная энергия, так и другой организм). И если это число не ноль, то организм входит в цикл, где он 7 раз откусывает от жертвы 127 энергетических юнитов. Если же под ним ничего нет, то в цикл мы не заходим и выполнение кода продолжается. Если объяснить это более простыми словами, то выходит вот что: если под нами кто-то есть, то кусай его 800 раз. Прекрасно :) Как я выяснил позже, на основе этого алгоритма родился как минимум еще один. Вы можете прочесть о нем здесь.
Если Вы заинтересованы в такого рода экспериментах, вы биолог или просто программист, которому интересно, пишите мне на email, и мы объединим наши усилия для создания своего skynet ;)
Материалы:
— презентация;
— видео-презентация;
— статья-комиксо jevo;
— мой блог;
— мой youtube канал;
— я сам;
— группав facebook, посвященная jevo;
— код проекта.