Гриндер: Ленточно-шлифовальный станок

       В последнее время в сети Интернет появилось достаточно много самодельных конструкций ленточно-шлифовальных станков, называемых в простонародье «гриндер». Вот и я решил не отклоняться от тенденции и сделать себе в мастерскую подобный станок. После изготовления этого станка он превзошел все мои ожидания.


Про превзошедшие ожидания, конечно, громко сказано, но получившийся станок действительно показал хорошие результаты, хоть и сравнить особо было не с чем, разве что с теми, которые самоделки показывали на YouTube.

Сам по себе станок довольно универсальный и может обрабатывать различные материалы (дерево, пластик, металл) с очень хорошей скоростью и поверхностной чистотой.

 В основе станка лежит шлифовальная лента, в моем случае она имеет размеры 50х900-1300 мм. Лента приводится в движение через шкив диаметром 128мм, установленный на вал асинхронного двигателя мощностью 1,1 кВт и максимальной частотой вращения 2980 об/мин. Исходя из этих данных можно рассчитать максимальную линейную скорость движения ленты, которая составит 1200 м/мин. Она ограничивается при помощи частотного преобразователя, подключенного к двигателю.

Конструкция.

Конструкция станка довольно простая, и при этом очень жесткая за счет своей массивности, так как в ее основу заложен лист толщиной 12 мм. Из него выполнено основание под асинхронный двигатель, к фланцу которого в свою очередь прикручена плита, образующая несущую раму всего станка. Чтобы хоть немного разгрузить фланец электродвигателя, основание и несущая рама связаны друг с другом через деталь — направляющую штанги. Далее в нее вставляется сама штанга, на один из концов которой крепится пластина, несущая на себе деталь в виде «полумесяца», а также направляющую для механизма установки рабочего столика. На концах «полумесяца» имеются два ролика, а через центр проходит ось, позволяющая поворачивать эту сборочную единицу под разными углами. Еще в состав сборочной единицы – «полумесяца», входит направляющий упор для шлифовальной ленты.

На несущей раме через ось закреплен рычаг с роликом для центрирования шлифовальной ленты. Этот рычаг так же играет роль натяжителя, в виду того, что между ним и рамой установлен газлифт.

Рабочие поверхности ведущего шкива и натяжного ролика имеют полукруглый усеченный профиль для лучшего удержания ленты на их поверхности.

Механизм крепления рабочего столика имеет несколько степеней свободы, это делает его позиционирование очень удобным для последующей работы.

Изготовление и сборка

Проектирование этого станка продолжалось довольно долгое время. Все как я люблю – смоделировал в CAD программе, и раскидал деталировку с чертежами. Механической обработки получилось много, ее отдал другу – он занимается металлообработкой. Кроме токарных и фрезерных работ, требовалось изготовить еще ряд деталей из листового железа. Как вы уже, наверное, догадались, эти детали заказал на лазерной резке. В итоге, через некоторое время у меня в мастерской появился увесистый ящик с железом. И тут я смекнул: — «Если толком ничего не заработает, то при нынешних ценах на металл, сдам все в чермет и выйду в нули» (шутка конечно). Некоторые детали дорабатывал сам: сверлил отверстия, нарезал резьбы, сваривал, даже немного фрезеровал на своем СФ – 16 (но это отдельная история, так как опыта и знаний маловато). В общем, всю слесарную работу делал сам. Двигатель был куплен заранее.

Началась сборка. Так как все было сделано по чертежам, то в целом собиралось хорошо — кайфанул. Но и без проблемных мест не обошлось, я все же человек, а людям, как известно, свойственно ошибаться. В паре деталях ошибся с размерами, в моделях, конечно, сразу все поправил, а вот с железом пришлось немного потрудиться, но и с ним все решилось.

После предварительной сборки и пробного пуска, последовала разборка и покраска. Красить сам не стал, отдал «специалистам», все детали были отпескоструены и разделены на те, которые надо покрасить и на те, которые надо покрыть хим. оксидом. Покрасил уже традиционно в синий глянец, полимерной порошковой краской.

Работа и настройка

Так как у меня имелся частотный преобразователь на 1,5 кВт, то настройка упростилась. Вся настройка сводится к тому, чтобы при раскручивании ленты она не слетала с роликов и находилась всегда в одном и том же положении при прикладывании к ленте обрабатываемой детали.

Для того чтобы ленту отцентровать, запустил вращение на малых оборотах и установочным винтом отрегулировал положение натяжного ролика. Далее постепенно увеличивал скорость вращения, чтобы убедиться, что лента отцентрована во всем диапазоне скоростей.

Приступил к испытаниям. После прикладывания обрабатываемой детали к ленте, она начала смещаться в сторону. Отрегулировал положение направляющего упора между двумя роликами, расположенными на детали в виде «полумесяца». Ролики и направляющий упор должны находиться в одной плоскости, для этого даже пришлось отфрезеровать упор в угол, так как после сварки его немного повело.

На этом основная настройка закончена, и можно приступать к работе. Тут многое зависит от обрабатываемого материала и требуемой шероховатости, которую необходимо получить, а, следовательно, для этого надо подбирать зернистость ленты и скорость ее вращения.

Работать на этом станке еще только предстоит учиться, но уже кое-какой опыт получен.

Выводы и рекомендации

В ходе эксплуатации также обнаружился пока один, но довольно весомый недостаток конструкции: не хватает мощности. Решения два: поставить мотор мощнее или уменьшить диаметр ведущего шкива. Второй вариант пока более предпочтителен, но с диаметром еще не определился.

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

 

Вопрос цены

Гриндер получился не из бюджетной категории. Подобного по качеству изготовления из того, что продается в Интернет-магазинах, я не видел. Местами можно конструкцию немного облегчить и тем самым удешевить, но не вижу особого смысла, так как станок изначально делался для себя. То, что продается в основном слеплено из листа заниженной толщины, нарезанного чпу лазером, все рассчитано на низкую себестоимость. Но самое главное то, что все они работоспособные и не важно, сколько металла в них заложено. 

ссылка на оригинал статьи https://habr.com/ru/post/565548/

Космический лифт. Как, зачем, из чего

Узнать замечательное слово «ретрофутуризм» и даже прочесть эту статью мне довелось уже в бытность активного существования хаброблога, когда под моим последним январским постом развернулась дискуссия об осуществимости и целесообразности воздвижения сферы Дайсона. Немного разочаровавшись реакцией на тот пост, я отложил в долгий ящик обзорную статью о технологии и применении космического лифта, но вот и она дождалась своего часа. Во многом я нашел нужные мысли и слова, готовя материал о фуллеренах и, соответственно, освежив знания об углеродных нанотрубках. Поэтому вас ждет пост, категорически не относящийся к научной фантастике.

Вступление

Автором идеи космического лифта является Константин Эдуардович Циолковский. В 1895 году, осматривая в Париже новенькую Эйфелеву башню, Циолковский задумался о том, насколько реально было бы построить башню высотой до геостационарной орбиты, чтобы доставлять по ней грузы прямо в космос. Конструкция получалась практически неосуществимой: мало того, что ее основание на земле было бы сопоставимо по площади со всем Парижем, так и даже самая прочная сталь не выдержала бы такой нагрузки. Тем не менее, идею башни или мачты, выходящей прямо на орбиту, можно отнести к «невозможностям первого класса» в соответствии с парадигмой Мичио Каку: создание такой конструкции не противоречит законам физики, мы просто не владеем материалами и технологиями для осуществления проекта.

Следующая, вполне прикладная попытка подступиться к идее космического лифта была предпринята уже в СССР в 1960 году. 31 июля в воскресном приложении к «Комсомольской правде» вышла статья «В космос – на электровозе», написанная Юрием Николаевичем Арцутановым (1929 – 2019), в ту пору учившимся в аспирантуре Ленинградского технологического института. Тогда (третий год продолжаются космические запуски, но человек на орбите еще не бывал) Юрий Николаевич справедливо отметил, что космический полет на ракете не сможет стать массовым явлением, так как оказывает запредельные нагрузки на человеческий организм, а также требует тратить непозволительно много ресурсов и энергии на преодоление гравитации. Поэтому, предположил Арцутанов, запуск ракет должен осуществляться с орбиты, там, где они с легкостью будут приобретать вторую космическую скорость и отправляться в нужном направлении. Для этой цели на орбите должен быть развернут «целый город с оранжереями, обсерваториями, гелиоэлектростанциями, мастерскими, складами горючего и взлетно-посадочными устройствами для межпланетных ракет». Доставка людей и грузов на такую орбитальную станцию должна осуществляться по вертикальной трассе длиной 50-60 тысяч километров, так как для металлической конструкции такого размера примерно на высоте 42 тысячи километров центробежная сила (обусловленная орбитальным вращением Земли) станет примерно равна силе тяжести, под которой конструкция могла бы рухнуть на землю. Соответственно, такую конструкцию потребовалось бы составить из «наземной» несущей части, которая имеет переменную, увеличивающуюся толщину на пути к геосинхронной орбите, и из противовеса, который начинается на высоте порядка 42 000 километров и уравновешивает силу тяготения собственной центробежной силой.

Ажурную конструкцию подобной мачты Арцутанов предполагал снабдить железнодорожными путями, действующими по принципу маглева (поезда на магнитной подушке). Поезд должен был бы постепенно разгоняться до тех пор, пока не достигнет первой космической скорости, причем, гнать его вверх должно было исключительно магнитное поле. Горючее при этом бы не тратилось.

Здесь вкратце остановлюсь на практических соображениях, позволяющих осознать пользу и даже необходимость космического лифта. Космический лифт технически нереализуем в настоящее время – прежде всего, потому что у нас нет технологии для промышленного производства нанотрубок или аналогичного легкого и крепкого материала, из которого можно было бы собрать такой лифт. Тем не менее, космический лифт в отличие, например, от гиперлупа, не является улучшением какой-либо существующей технологии. Это принципиально новый, экологически чистый, а в долгосрочной перспективе — еще и экономичный проект. Космический лифт  открывает реальные возможности долговременной колонизации околоземной орбиты, колонизации Луны с возможностью устраивать экспедиции в любую точку нашего спутника. Космический лифт является одной из самых реалистичных предпосылок для освоения точек Лагранжа, которые, в свою очередь, могут оказаться удобны для промышленной переработки астероидов. Наконец, космический лифт – незаменимая технология для высадки на суперземли и благополучного отбытия с них. Теперь давайте обо всем по порядку.  

Конструкция космического лифта           

Примерно в таком виде космический лифт представляли еще в 1960-е. Возвращаясь к «башенной» модели космического лифта, предложенной Циолковским, отметим, что сила тяготения будет противоположным образом воздействовать на секции башни, расположенные ниже и выше геостационарной орбиты: нижняя часть башни будет стремиться упасть на землю, а верхняя – улететь в космос. Поэтому для стабилизации башни достаточно расположить центр ее массы существенно выше геостационарной орбиты. Земное притяжение, воздействующее на лифт, будет наименьшим на поверхности Земли и наибольшим – на геостационарной орбите. Выше геостационарной орбиты притяжения уже практически не будет, и именно там уместно развертывать первый космопорт дальнего следования. 

Следующее принципиальное отличие космического лифта от традиционного является неподвижность «ствола» всей конструкции относительно Земли (естественно, относительно спутников и космических станций лифт будет вращаться с той же скоростью, что и Земля). Напротив, подвижной частью лифта будут одинаковые подъемники-вагоны, которые будут уравновешивать друг друга, если в каждый момент времени один из них будет двигаться снизу вверх, а другой – сверху вниз. Подобную идею выдвинули в статье 2021 года китайские ученые.  Путь такого вагона с поверхности Земли на геостационарную орбиту может занимать от нескольких дней до считанных часов. Поскольку подъемники будут выполнять не только транспортную, но и уравновешивающую функцию, они не могут нести с собой горючего. Во-первых, объем горючего относительно объема вагона был бы настолько же велик, как и объем горючего, необходимого для вывода ракеты-носителя на орбиту. Во-вторых, с выгоранием топлива менялась бы и масса всего подъемника, вернее, всех задействованных подъемников одновременно – что значительно дестабилизировало и раскачивало бы всю систему. Поэтому в модели Арцутанова предполагалось запитывать подъемники электричеством, пропущенным через кабели на протяжении всего лифта (нереализуемо), впоследствии высказывалась версия, что передавать энергию подъемнику можно было бы при помощи лазеров. В наше время гораздо логичнее выглядит конструкция, при которой лифт использует солнечную энергию, поскольку (например, по всей длине) облицован солнечными батареями. Ниже я упомяну, почему единственным реалистичным материалом для возведения космического лифта представляются углеродные нанотрубки. Тем не менее, уже здесь можно оговориться, что углеродные структуры, прежде всего, фуллерены, вполне могут применяться и в качестве фотоэлектрических элементов. Таким образом, принципиально возможно собрать из углерода как несущую конструкцию лифта, так и его энергетическое оснащение (солнечные батареи). Также упомяну ниже, почему это возможно, но не оптимально.

Базовая станция космического лифта должна располагаться на экваторе, поскольку вывод тела на геостационарную орбиту тем проще, чем ближе к экватору находится точка старта. При этом, благодаря закону Архимеда, вес плавучей морской платформы будет снижаться, даже если она будет обширна как искусственный остров.       

При этом на экваторе удобно расположить базовую станцию так, чтобы она находилась далеко от крупных течений, при этом была в нейтральных водах, и к ней без проблем подходили контейнеровозы любого размера, в том числе, подвозящие сборные и негабаритные грузы.

Итак, собрать наземную платформу для космического лифта можно уже на нынешнем уровне технологического развития. По-настоящему монструозная задача – именно дотянуть ствол лифта до 50 000-километровой высоты, так, чтобы он не разорвался задолго до геостационарной орбиты, а также найти, как (и из чего) собрать противовес на той стороне конструкции. При этом возводимая конструкция должна находиться в плотной земной атмосфере и выдерживать капризы погоды, солнечную радиацию, удары метеоритов, а выше атмосферы – и столкновения с космическим мусором. Наконец, необходимый для лифта материал ни в коем случае не должен быть горючим – потушить пожар на такой высоте будет практически невозможно.

Предполагается, что достаточной прочностью для сборки космического лифта обладают лишь углеродные нанотрубки. На сайте Роснано читаем, что коэффициент прочности одностенных углеродных нанотрубок составляет 50 ГПа. Этот коэффициент можно вычислить, поделив силу разрыва (70 нН для углеродной нанотрубки диаметром 1,5 нм) на площадь поперечного сечения. Такой расчет показывает, что прочность нанотрубок по пессимистичным оценкам составляет 40 ГПа, но может доходить и до 100 ГПа, то есть, кабель выдержит нагрузку 10 тонн на сечение площадью 1 мм2. Для сравнения: у стали этот показатель доходит до 0,4 ГПа (ближе к 0,34 ГПа), у монокристалла железа – 1,3 ГПа, для графена – 350 ГПа. Значения, достигнутые на практике для углеродных нанотрубок и графена к 2019 году, составляют 28 и 94 ГПа соответственно.

Несмотря на столь оптимистичные показатели, пока до промышленного применения нанотрубок еще очень далеко, поскольку к настоящему времени удалось вырастить нанотрубку длиной не более нескольких метров.

В качестве альтернативы углеродным нанотрубкам могут использоваться еще более прочные сверхтонкие алмазные волокна, полученные в 2017 году группой Джона Баддинга в Пенсильванском университете. Такую углеродную структуру удалось получить сжатием молекул бензола под давлением 200 000 атмосфер. В результате атомы углерода пересобирались в чрезвычайно прочную кристаллическую решетку, ячейка которой напоминает по форме тетраэдр.

С физической точки зрения длина углеродных трубок может быть практически неограниченной, но даже столь прочный материал как графен наверняка не выдержит наращивания до геостационарной орбиты и рухнет под собственной тяжестью.

Революционное решение, позволяющее решить эту проблему уже на современном уровне развития технологий, было предложено Зефиром Пенуаром и Эмили Сэндфорд в 2019 году. Возможно, первую очередь космического лифта было бы реалистичнее не возвести с Земли, а свесить с Луны.

Точки Лагранжа и космический лифт

В районе земной орбиты есть удивительные места, в которых гравитация практически не действует, поскольку в них гравитация Земли и другого небесного тела гасит друг друга. В 1772 году эти точки открыл французский математик Лагранж, заинтересовавшийся, есть ли в Солнечной системе такое место, где гравитация Солнца и Земли равны. Выяснилось, что таких точек, где гравитация Земли и Солнца и Земли и Луны гасят друг друга, целых 5. Их назвали L1, L2, L3, L4 и L5. Если поместить в точку Лагранжа космический аппарат или, например, космическую станцию, он(а) никуда оттуда не денется. Точки Лагранжа определенно есть и у других объектов в Солнечной системе – например, по-видимому, именно в такой точке между Марсом и Юпитером засел астероид Ахиллес.    

Идея Пенуара и Сэндфорд заключается в следующем. Если бы удалось построить на Луне базу для космического лифта, закрепить там тонкий углеволоконный трос, а затем протянуть его через точку Лагранжа в направлении Земли, то именно в этой точке можно было бы начать обустройство постоянной колонии на полпути между Землей и Луной.

Поскольку на такой станции естественная гравитация бы отсутствовала, оттуда можно было бы сравнительно легко добираться в любую точку Луны. Стали бы технически целесообразны регулярные лунные экспедиции, в том числе, за ценнейшим гелием-3, необходимым для развития термоядерной энергетики. С этой станции, в свою очередь, было бы удобно тянуть космический лифт в сторону Земли, собирая в нужной точке тот противовес, который обеспечит нужное натяжение для участка лифта «Земля – точка Лагранжа». Подробнее о потенциальном использовании точек Лагранжа в космонавтике и в особенности в освоении Луны рассказано в статье с сайта gagarin.ru, где на вопросы журналиста отвечает доктор технических наук Юрий Петрович Улыбышев, заместитель руководителя корпорации «Энергия».  

Я же в данном случае хочу подчеркнуть еще два важнейших аспекта, связанных со спусканием космического лифта из точки Лагранжа.

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

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

Более того, в будущем технология спускаемого космического лифта (с естественных спутников или из точек Лагранжа) могла бы стать незаменима при освоении суперземель. Как известно уже сегодня по результатам работы телескопа «Кеплер», в нашей Галактике широко распространены каменные планеты, подобные Земле по химическому и, возможно, геологическому составу, но превышающие ее по размеру в два-три раза. Существует предположение, что такие планеты могут оказаться сверхобитаемыми, так как смогут удерживать на поверхности больше воды и плотные насыщенные атмосферы. Но при этом они являются настоящими «гравитационными колодцами» как для любой пилотируемой экспедиции с Земли, так и для потенциальной аборигенной космонавтики. Первая космическая скорость на суперземле настолько велика, что для выхода на ее орбиту с использованием привычного нам топлива потребовалась бы ракета-носитель размером с пирамиду Хеопса. Поэтому, возможно, жители таких планет просто заперты в своих мирах. Соответственно, как с обитаемой, так и с необитаемой суперземли не мог бы улететь и случайно оказавшийся там земной корабль. Не хватило бы топлива.

Но освоение суперземель серьезно упрощается при наличии отлаженной технологии космического лифта. Даже если у суперземли не будет удобного спутника, близ нее наверняка удастся найти удобную точку Лагранжа и размотать углеволоконный (или аналогичный, более прочный) трос до горной вершины на этой планете – кстати, из-за усиленной гравитации горы на суперземле должны быть сравнительно низкими. Но здесь я уже слишком углубляюсь в научную фантастику.

Важной критичной уязвимостью углеродного космического лифта, которую здесь следует рассмотреть, является горючесть углеволокна. Углеродные нанотрубки не просто горят, а вспыхивают. Поэтому предполагается, что более безопасным и при этом крепким материалом для производства таких трубок может стать не углерод, а кремний, точнее, силицен – кремниевый аналог графена. Кристаллические решетки из кремния значительно сложнее получать, чем графен. Тем не менее, силицен удалось наблюдать в 2010 году, а в 2012 году – вырастить искусственно. Исходно с силиценом связывались определенные надежды в полупроводниковой промышленности, но практика показала, что он неприменим в микроэлектронике, так как слишком быстро распадается на обычный кремний. Мне не удалось найти материалов о практическом получении кремниевых нанотрубок, аналога углеродных, на основе кремния. С другой стороны, именно при армировании космического лифта силицен мог бы прийтись кстати, в том числе, и потому, что должен легко интегрироваться с микроэлектроникой, также создаваемой на кремниевой основе. Возможно, организовать поточное производство силиценового волокна удастся при помощи 3D-печати.

Заключение

Я отдаю себе отчет в том, что на момент подготовки этой публикации создание космического лифта – далеко за пределами возможностей человечества. Даже Илон Маск, известный своими масштабными проектами, отказался высказаться на тему космического лифта. Я намеренно обошел здесь сугубо экономическую выгоду такого проекта – потенциально космический лифт позволил бы удешевить доставку одного килограмма груза на орбиту с 20 000 долларов (сейчас) до 500 долларов; при описанных же здесь перспективах лифт мог бы работать «на спуск» не менее активно, чем «на подъем». Надеюсь, мне удалось парировать все или хотя бы некоторые критические замечания из статьи «Придется ли нам распрощаться с мечтой о космических лифтах?», вышедшей в 2015 году, и дать вам пищу для размышления.

ссылка на оригинал статьи https://habr.com/ru/post/565558/

Карго-культ HTML в современном фронтенде

Здравствуйте, меня зовут Дмитрий Карловский и я… люблю рвать шаблоны. А во фронтенде как раз крайне много заблуждений вокруг шаблонизации. Так что давайте порвём их на лоскуты снизу вверх и справа налево.

Разрыв шаблона

Далее мы разберём что такое шаблоны. Их ключевые достоинства и фатальные недостатки. Зачем они нужны и почему не нужны. Сформируем представление о правильном решении и проедемся катком по популярным. Так что полная гамма чувств нам обеспечена.

Прошу к столу..

А что такое шаблон?

Казалось бы, тут всё очевидно: это способ генерации кода на целевом языке. Однако, всё не так просто. Чтобы понять ключевое свойство шаблона, давайте рассмотрим пару примеров..

Это шаблон:

"Hello, ${name}!"

А это уже нет:

"Hello" + name + "!"

Оба кода делают одно и то же, но почему одно является шаблоном, а другое — нет? Всё дело в том, какой язык является первичным в коде, а какой является опциональной добавкой к нему. Шаблон предполагает написание кода сразу на целевом языке, вкрапляя в него специальные управляющие конструкции, которые тем не менее синтаксически согласованы с целевым языком.

Яркий пример синтаксически согласованных управляющих конструкций можно наблюдать в XSLT:

<xsl:template name="page">     <acticle>         <h1>             <xsl:copy-of select="./head" />         </h1>         <xsl:copy-of select="./body" />     </article> </xsl:template>

А вот такой код, не смотря на использование шаблонов в 1 и 3 строке, в целом шаблоном всё же не является, так как чтобы понять, каков будет результат, нужно мысленно корректно исполнить JSX-код:

const head = <h1>{ headContent }</h1> const body = 'Hello, World' const article = <article>{ head }{ body }</article>

Грубо говоря, если взять парсер целевого языка, то он справится и с парсингом шаблона, просто проигнорировав управляющие шаблонные конструкции, никак их не обрабатывая. И, соответственно, человек тоже может буквально видеть получающийся из шаблона результат, а не собирать его в уме.

Как видно в последнем примере, код на JSX может быть шаблоном, а может им и не быть. И как правило шаблоном он всё же не является, не смотря на синтаксическое подражание HTML.

Зловещая долина

А необходим ли HTML?

Во фронтенде целевым языком для шаблонов как правило является HTML. А HTML является не более, чем сериализованным представлением DOM дерева. И в прошлом именно HTML был языком коммуникации между клиентом и сервером. Поэтому серверу нужно было генерировать именно его.

Однако, в современном вебе клиент и сервер больше не обмениваются HTML, предпочитая JSON, ProtoBuf и другие более эффективные форматы. Более того, теперь клиент уже сам формирует DOM напрямую, через JS-API, минуя HTML представление. А это значит, что в качестве целевого языка описания DOM может быть использован не только HTML, но и иные форматы сериализации DOM.

Например, HAML:

!!! %html{ :lang => "ru" }     %head         %title= title         %meta{ 'http-equiv' => 'Content-Type', :content => 'text/html' }/     %body         %h1= title         %p= description

Или xml.tree:

! DOCTYPE html html     @ lang \ru     head         title ? title         meta             @ content \text/html; charset=utf-8             @ http-equiv \Content-Type     body         h1 ? title         p ? description

Или даже JSON. Без примера, ибо слишком уж он развесистый получается.

В этом свете использование HTML-шаблонизации является скорее данью традиции, чем реальной необходимостью:

<!DOCTYPE html> <html lang='ru'>     <head>         <title>{title}</title>         <meta             content='text/html; charset=utf-8'             http-equiv='Content-Type'         />     </head>     <body>         <h1>{title}</h1>         <p>{description}</p>     </body> </html>

Эффект штурмовика

А достаточно ли HTML?

Мощности HTML хватает лишь для описания DOM. Но современная разработка предполагает компонентную декомпозицию. А где декомпозиция — там и композиция. То есть нам необходим инструмент для создания экземпляров компонент, их настройки и соединения друг с другом реактивными связями разных направлений.

Тут не то что HTML, а даже DOM уже катастрофически не хватает, что неизбежно порождает чудовищ. Например, вам нужно вставить несколько компонент и провязать их состояния друг с другом.

Возьмём ангуляровский "шаблон":

<bi-panel class="example">      <check-box         class="editable"         side="left"         [(checked)]="editable"         i18n         >         Editable     </check-box>      <text-area         #input         class="input"         side="left"         [(value)]="text"         [enabled]="editable"         placeholer="Markdown content.."         i18n-placeholder="Showed when input is empty"     />      <div         *ngIf="text"         class="output-label"         side="right"         i18n         >         Result     </div>      <mark-down         *ngIf="text"         class="output"         side="right"         text="{{text}}"     />  </bi-panel>

Весьма похоже на HTML, но только это не HTML, чтобы там ни говорили Angular-евангелисты. DOM (и как следствие HTML) поддерживают лишь задание строк в качестве атрибутов. А для компонент нужны не только строки, но и другие типы данных: числа, объекты и даже другие компоненты. И их надо не только хардкодить в шаблоне, но и брать из свойств, класть в свойства, а то и вообще обеспечивать двустороннее связывание.

И тут начинаются кастомные расширения HTML. Каждый атрибут в примере выше имеет свою семантику, но синтаксически выглядят они все одинаково:

  • #input — это локальный идентификатор, для доступа через TS.
  • class="editable" — это имя класса для привязки стилей через CSS.
  • side="left" — это имя слота, куда этот элемент будет помещён.
  • [(checked)]="editable" — это двустороннее связывание свойств вложенного и внешнего компонентов.
  • [enabled]="editable" — это уже одностороннее.
  • text="{{text}}" — а это тоже самое.
  • placeholer="Markdown content.." — это какой-то захардкоженный текст.
  • i18n-placeholder="Showed when input is empty" — а это, внезапно, указание, что атрибут placeholder подлежит переводу, и пояснение переводчику.
  • *ngIf="text" — это же вообще к компоненту не относится, а регулирует будет ли компонент рендериться в родителе.

Все 4 компонента лежат вперемешку, не смотря на то, что часть из них относится к левому слоту, а часть к правому. То есть это мало того, что не HTML, так это ещё и вовсе не шаблон. Это — язык для компоновки компонент, мимикрирующий под HTML. Из-за этой мимикрии он преисполнен горой сомнительных решений, осложняющих изучение, разработку, чтение и поддержку как самого прикладного кода, так и инструментария, превращающего эти "шаблоны" во что-то, что может исполнить браузер, чтобы показать интерфейс.

А внутре у ней неонка

Но чем же HTML хорош?

Ключевое достоинство HTML — его декларативность. Вопреки расхожему мнению, декларативные языки описывают на самом деле не "результат", а некоторую семантическую структуру. И эта структура может быть использована для программного анализа с получением множества разных "результатов" в зависимости от потребностей.

Мы можем взять HTML и нарисовать на экране красивый плоский интерфейс. Можем в VR показать объёмный интерфейс, который можно потрогать. Можем реализовать голосовой интерфейс для не зрячих. Можем распечатать в виде книги. Можем собрать все заголовки для формирования оглавления и все термины для тезауруса. Можем собрать все ссылки и уведомить сайты, куда они ведут, о том, откуда на них ссылаются. Можем отправить уведомление всем упомянутым пользователям. И много чего ещё.

Но всё это многообразие возможностей крайне затруднено, а то и попросту не возможно при написании императивного кода, который описывает конкретные действия по получению одного конкретного результата. Что бы там ни говорили адепты функционального программирования, но оно ни в коем разе не является декларативным. ФП — это просто императивное программирование на иммутабельных структурах, описывающее конкретные действия, по трансформации заданных входных параметров в заданные выходные. Всё, что можно сделать с чистой функцией — это её исполнить. А всё, что может дать нам анализ её кода — это "ну, там вызываются какие-то функции, вот их сигнатуры".

Простой пример императивного функционального кода:

приготовить_яичницу = ()=> последовательность(     ()=> яйцо ,     яйцо => разбей( яйцо ) ,     разбитое_яйцо => уберать_скорлупу( разбитое_яйцо ),     яйцо_без_скорлупы => пожарить( сковорода )( яйцо_без_скорлупы ),     жаренное_яйцо => добавить_приправы( жаренное_яйцо ) )

А вот пример настоящего декларативного кода в модели RDF:

яичница     включает         жареное_яйцо         приправы жареное_яйцо     создаётся_посредством         горячая_поверхность скворода     является         горячая_поверхность жареное_яйцо     создаётся_из         яйцо_без_скорлупы яйцо     включает         яйцо_без_скорлупы         скорлупа

Это логические триплеты. Благодаря нормализованному представлению их очень просто парсить и анализировать.

Но вернёмся к нашим шаблонам. Возьмём популярный сейчас JSX, который мимикрирует не только под HTML, но и под JS, и даже под ФП, при этом ничем из упомянутого не являясь:

const Example = ( props: {     className?: string     text?: string     onTextChanged?: ( next: string )=> void     editable?: boolean     onEditableToggle?: ( next: boolean )=> void } )=> {      const [ stateText, setStateText ] = useState( props.text ?? '' )     const [ stateEditable, setStateEditable ] = useState( props.editable ?? true )     const [ inputElement, setInputElement ] = useState< HTMLTextAreaElement >( null )      const className = ( props.className ?? '' ) + ' example'     const text = props.text ?? stateText     const editable = props.editable ?? stateEditable      const setText = useCallback( ( next: string )=> {         setStateText( next )         props.onTextChanged?.( next )     }, [ props.onTextChanged ] )      const setEditable = useCallback( ( next: boolean )=> {         setStateEditable( next )         props.onEditableToggle?.( next )     }, [ props.onEditableToggle ] )      return (         <BiPanel              className={ className }              left={                 <>                      <CheckBox                         className="editable"                         checked={ editable }                         onToggle={ setEditable }                         >                         { l10n( 'Editable' ) }                     </CheckBox>                      <TextArea                         ref={ setInputElement }                         className="input"                         value={ text }                         onChange={ setText }                         enabled={ editable }                         placeholder={ l10n( 'Markdown content..' ) }                     />                  </>             }              right={                 text                     ? <>                          <div                             className="output-label"                             >                             { l10n( 'Result' ) }                         </div>                          <MarkDown                             className="output"                             text={ text }                         />                      </>                     : <></>             }          />     )  }

Закроем пока глаза на объёмность и сложность кода. Давайте подумаем, что мы можем получить из него без исполнения..

Можем ли мы при сборке вытащить все локализуемые тексты и заменить их на персистентные ключи?

Нет. Даже если мы распарсим весь код в AST, найдём все вызовы функции l10n и понадеемся, что передан ей всегда будет лишь строковый литерал, а не какое-нибудь выражение, нам всё равно неоткуда взять персистентную информацию для формирования ключей, чтобы они не менялись при каждом изменении вёрстки.

Можем ли мы в визуальном конфигураторе понять, что свойства CheckBox.checked, TextArea.enabled и props.editable связаны друг с другом двусторонней связью?

Нет. И не верьте адептам Реакта, утверждающим, что двустороннего связывания там нет, и что оно вообще не нужно. Оно и нужно, и есть, хоть и реализуется через костыли с парными пропсами вида checked={ editable } onToggle={ setEditable }.

Можем ли мы там же понять, что если не задать свойство editable, то текстария будет изначально редактируемой?

Нет. Разве что очень сильно заморочиться и реализовать data-flow анализ. И то он будет справляться далеко не со всем многообразием возможного кода.

Можем ли мы при сборке проверить, что CSS-селектор .example .output .link действительно на что-то матчится?

Нет. Так как имена классов собираются из строк в прикладном коде.

Продолжать можно долго, но суть уже должна быть ясна: императивные языки содержат слишком мало информации о высокоуровневых абстракциях и слишком много низкоуровневого шума. Это капитально осложняет программный анализ.

А король-то голый!

А возможна ли декларативность?

Чем меньше язык позволяет вольностей, тем проще его программно анализировать. Но обратная сторона этого — снижение гибкости. Чтобы достичь максимальной гибкости, нужен язык общего назначения. Во фронтенде таким языком обычно является JS и другие языки, в него компилирующиеся. Поэтому очень велик соблазн либо собирать компоненты сразу в нём, либо засовывать в "шаблоны" вкрапления на JS. Разумеется ни о какой декларативности в этом случае уже говорить не приходится.

Чтобы добиться гибкости, но не потерять декларативность, нужно разбивать код компонента на 2 части:

  • Декларативная, где происходит компоновка компонент друг с другом.
  • Императивная, где описывается логика работы.

Именно поэтому надо отделять "шаблоны" от "скриптов", а не потому, что одно как бы бизнес-логика, а другое — её отображение.

Для примера возьмём язык view.tree, используемый в $mol:

$my_example $mol_view     sub /         <= Panel $my_bipanel             left <= input /                 <= Editable $mol_check_box                     checked?val <=> editable?val true                     title @ \Editable                 <= Input $mol_textarea                     hint @ \Markdown content..                     value?val <=> text?val \                     enabled <= editable             right <= output /                 <= Output_label $mol_paragraph                     sub / <= output_label @ \Result                 <= Output $mol_text                     text <= text

Он мало того, что в несколько раз меньше эквивалентного JSX кода, так из него ещё и легко вычленять локализацию, собирать статистику использования, проверять переопределения стилей и много чего ещё. Можно даже построить конфигуратор позволяющий взять произвольное существующее приложение и, не написав ни строчки кода, собрать из него что-то новое. Ну а когда декларативных возможностей не хватает — всегда можно написать комплексную логику в отдельном скрипте, используя всю мощь языка общего назначения:

export class $my_example extends $.$my_example {      output() {         return this.text() ? super.output() : []     }  }

К сожалению, с подачи Фейсбука вместо чего-то такого мы имеем сейчас повсеместный императивный JSX и кучу костыльных проектов, пытающихся его программно анализировать. А в тех фреймворках, где есть отделение скриптов от шаблонов, вместо шаблонов мы видим императивный недо-DSL мимикрирующий под HTML, что приверженцы Реакта справедливо считают бессмысленным.

Dart, да не Дарт

Что опять за наезды на JSX?

Раз уж мы уже наехали, то не будем останавливаться и проедемся до конца, по всем недостаткам дизайна JSX помимо недекларативности…

Push семантика

Вложенное поддерево вычисляется безусловно, даже если оно завёрнуто в компонент, который показывает своё содержимое лишь иногда. Решаться это могло бы через передачу замыкания вместо VDOM:

return (     <Dialog visible={ opened } >         { ()=> <>Heavy content</> }     </Dialog> )

Но, как всегда, есть "но":

  • Заворачивать всё подряд в замыкания банально не удобно.
  • Замыкания нужно мемоизировать через useCallback, чтобы избежать лишних рендеров.
  • Без автоматического трекинга зависимостей это просто не будет работать.
  • Изменение получения VDOM на замыкание меняет API компонента.

В результате реальный код становится куда более страшным:

const dialogContent = useCallback( ()=> (     <>Heavy content</> ) )  return userObserver( ()=> (     <Dialog visible={ opened } >         { dialogContent }     </Dialog> ) )

Сравнение push и pull семантики — это отдельная большая тема. Поэтому вкратце обрисую преимущества pull: она позволяет просто и эффективно реализовать ленивые вычисления, рендеринг, загрузку и вообще экономить ресурсы. У push семантики же с этим всем серьёзные проблемы.

Неэффективность

JSX компилируется в крайне не удачный JS код, который из-за своей мегаморфности крайне сложно поддаётся оптимизации JIT-компилятором:

Сверху — то, каким он мог бы быть быстрым при мономорфности. А снизу — суровая реальность в FireFox.

Слабые возможности связывания

JSX заточен под проталкивание значений. Но любые другие связывания — это боль. Хочешь передать замыкание — изволь завернуть его в useCallback и описать отдельным массивом всё, от чего оно зависит (и счастливой отладки, если что-то забудешь):

const setName = useCallBack( ( name: string )=> {     setInfo({ ... info, name }) }, [ info, setInfo ] )  return <Input value={ info.name } onChange={ setName }>

Самое забавное, что useCallback тут должен спасать от лишних рендеров, но так как замыкание зависит от info, то его приходится указывать в зависимостях, что приводит к обновлению замыкания при каждом изменении данных, даже если info.name фактически не поменялся. А следовательно рендер Input будет происходить при каждом изменении любого поля info.

Про двустороннее связывание я ранее уже упомянул, что оно делается через костыли с прокидыванием пары свойств. Это мало того, что многословно, так ещё и легко разъезжается, приводя ко крепким обнимашкам с дебаггером.

Неконсистентность

Из-за подражания HTML константные строки прокидываются одним синтаксисом, а все остальные типы и неконстантные строки — другим:

<input type="password" minLength={ 5 } className={ 'password ' + className  } />

Дочерние компоненты могут быть переданы двумя совсем разными способами:

<Dialog>     <Hello />     <World /> </Dialog>

<Dialog     children={[         <Hello />,         <World />,     ]} />

А уж сколько есть вариантов условного рендеринга — один хуже другого.

Всё это — следствие попытки усидеть сразу на двух стульях: HTML и JS.

Костыли для комментариев

Набирать и читать их просто неудобно:

<Dialog>     <Hello />     {/* World */} </Dialog>

Волшебные атрибуты

JSX никак не форсирует простановку уникальных идентификаторов вложенным компонентам. А потребность получать ссылку на конкретный DOM элемент есть. Поэтому в вёрстке появляются волшебные атрибуты:

<Dialog>     <Hello ref={ setHelloRef } />     <World ref={ setWorldRef } /> </Dialog>

По той же причине, функция рендеринга не может отличить перемещённый элемент от нового, что приводит к лишнему рендерингу. Чтобы этого избежать вводится ещё один волшебный атрибут:

<Dialog>     <Message key="hello">Hello</Message>     <Message key="world">World</Message> </Dialog>

Правда, при переносе в другого родителя, не спасает и он.

И беда даже не в том, что эти атрибуты вообще существуют, а в том, что синтаксически они неотличимы от любых других.

Много мусора в вёрстке

Мало нам закрывающих тегов из HTML. Давайте добавим ещё и лесенку из контекстов:

<ThemeContext.Provider value={theme} >     <UserContext.Provider value={signedInUser} >         <Layout />     </UserContext.Provider> </ThemeContext.Provider>

<ThemeContext.Consumer>     { theme => (         <UserContext.Consumer>             { user => (                 <ProfilePage user={user} theme={theme} />             ) }         </UserContext.Consumer>     ) } </ThemeContext.Consumer>

Отсутствие ограничений

Отсутствие синтаксических ограничений мало того, что затрудняет программный анализ, так ещё и неизбежно приводит к ухудшению качества кода. Даже если код пишет не говнокодер, порой бывает, что некогда или лень делать правильно, а срезать угол ничего не мешает, и выглядит это вроде бы проще. Но разбитое окно тут, покосившееся там, и вот у нас уже не чётко структурированный код, а лютая тормозящая лапша, где всё связано со всем, лежит вперемешку, но концы с концами фиг сведёшь:

<div className="tag-list">     {tags.map((tag) => (         <button             key={tag}             className="tag-pill tag-default"             onClick={() =>                 dispatch({                     type: 'SET_TAB',                     tab: { type: 'TAG', label: tag },                 })             }         >             {tag}         </button>     ))} </div>

В цикле хреначим немемоизированное замыкание, код которого тут же по среди "вёрстки" и всё, что он делает, — меняет формат события. Не, ну а что, подумаешь ререндер всех элементов на каждый чих. Процессоры сейчас быстрые, данных мало, переход к определению работает везде..

А view.tree прям такой идеальный?

Нет, конечно, педаль в пол, давим и его..

Слабая интеграция с IDE

Microsoft добавила поддержку JSX прямо в компилятор TypeScript, что дало не только хороший тайпчек, но и интеграцию в тайпскриптовый Language Server. А это значит отличную интеграцию не только с их же VSCode, но и с другими IDE.

К сожалению, Microsoft не озаботилась простотой интеграции сторонних языков с TS. view.tree, конечно, компилируется в TS, что даёт тайпчек при сборке, но IDE этого всего не видит. Соответственно, не работают подсказки, рефакторинги и тп. Хорошо хоть подсветка синтаксиса есть.

Неявная типизация

Во имя простоты и наглядности в языке почти нет возможности задать тип явно. Типы выводятся из значений по умолчанию, что не всегда даёт ожидаемый результат.

Например, значение null имеет тип any:

/**  * Placeholder null  */ Placeholder() {     return null as any }

Как и аргументы методов:

/**  * name!id?next \Unknown  */ @ $mol_mem_key name(id: any, next?: any) {     if ( next !== undefined ) return next as never     return "Unknown" }

Но это всё компромиссы конкретного языка, а не декларативного подхода в целом. Ведь можно же было сделать, например, так:

/**  * Placeholder null $mol_view  */ Placeholder() {     return null as null | $mol_view }  /**  * name!number?string \Unknown  */ @ $mol_mem_key name(id: number, next?: string) {     if ( next !== undefined ) return next     return "Unknown" }

Что тут ещё сказать?

Фух, покатались на славу. Пришло время остановиться и перевести дух, поразмыслить над смыслом бытия, и двинуться дальше..

В выступлении "Tree — единый AST чтобы править всеми" можно познакомиться с форматом tree. В выступлении "Свой язык с поддержкой sourcemaps за полчаса" с его пайплайном. А в выступлении "$mol — лучшее средство от геморроя" можно найти краткое введение конкретно в язык view.tree.

Заглядывайте в чат "Разработка языков программирования" всё это обсудить. Или даже в чат "$mol: Разработка" если заинтересовал фреймворк $mol.

Ну и, конечно, предлагайте в комментариях свои идеи как упростить жизнь разработчика интерфейсов, не водружая инвалидные коляски поверх многоэтажных костылей.

То, что тебя не убивает, делает тебя… страннее!

Скука

ссылка на оригинал статьи https://habr.com/ru/post/565414/

Лихие девяDOSтые. Во что мы играли в начале 90-х (часть 2)


В прошлой заметке я вспомнил несколько популярных игр, в которые мы самозабвенно рубились на «Поисках» и «Искрах» на заре 90-х. Но время шло, и постепенно парк доступной нам техники обновлялся, а вместе с «хардом» менялся и «софт». Свой первый 386-й компьютер я приобрел совершенно случайно: на дворе стоял 1995 год, и я по знакомству подрядился ремонтировать офис одной мелкой фирмы. К тому моменту, когда отделка была завершена, контора успела скоропостижно разориться. Вместо денег с нами рассчитались оставшейся офисной техникой — мне досталась та самая «трешка». Вернее, машина на Am386 в стильном «десктопном» корпусе, работавшая на 33 мегагерцах, оборудованная 2 мегабайтами оперативной памяти и винтом на 40 мегабайт. На компе стояла MS-DOS, но я накатил туда Windows 3.11, которая запускалась в случае необходимости командой win. Впрочем, для большинства задач привычного «доса» вполне хватало.

В комплект к компьютеру, я приобрел «бэушный» цветной четырнадцатидюймовый VGA-монитор — и это был шик, поскольку многие мои друзья еще сидели на EGA (а один оригинал — на «Геркулесе»). Помню, как в магазине мне запаковали его в коробку, заклеили ее скотчем, но стоило выйти с драгоценной ношей на крыльцо, как скотч разорвался, коробка открылась, и монитор с грохотом полетел на асфальт дисплеем вниз. У меня буквально замерло сердце, когда в разные стороны брызнули осколки. Асфальта. Монитор, который по моим ощущениям весил полтонны, не только успешно выдержал приземление, но еще и исправно работал потом очень долго — я заменил его на «пятнашку» много лет спустя, когда собрал свой первый «пентиум».

Ассортимент игрушек под 386-е машины был уже не в пример шире, чем для старых добрых 8088, да и трехдюймовых дискет по карманам можно было распихать куда больше, чем пятидюймовых «картонок». Мы все еще пользовались «флоппинетом», потому в гости к друзьям я ходил с сумкой, набитой пивом и дискетами под завязку — с меркантильной целью чего-нибудь у них «переписать» или поделиться собственными софтверными богатствами. На «трёхе» у меня уже вертелись нужные для работы программы — MS Word 5.0 и одна из первых версий Adobe Photoshop, но играм я по-прежнему уделял немало времени. В этой заметке я решил вспомнить те из них, в которые играл сам, а читатели наверняка припомнят и другие.

▍ Wolfenstein 3D

Серый потолок и пол, квадратные коридоры и квадратные же фашисты с собаками породы «овчарка немецкая пикселизованная», которых главный герой, американский разведчик Би-Джей Бласковиц, мочит направо и налево квадратно-гнездовым способом — вот и весь антураж замечательной игры от ID Software под названием Wolfenstein 3D, которую я первой установил на свою «трешку». Не могу назвать себя фанатом шутеров от первого лица, но после черно-белого CGA-дисплея на цветном VGA-мониторе хотелось играть во что угодно, главное — подольше. Первое время я играл без звука, чем очень радовал родственников и соседей. Чуть позже для «трешки» была докуплена изначально отсутствовавшая 16-битная звуковая карта размером с двуспальную кровать, подключавшаяся к шине ISA, и жить стало немного веселее.

«Вольфенштейн» был отличным способом расслабиться после институтских лекций и работы — ходишь по бесконечной анфиладе комнат, убиваешь врага, собираешь патроны, аптечки и прочий разбросанный по локациям лут. Иногда удается подобно Гарри Поттеру найти Тайную Комнату, в которой спрятано что-то ценное. Главное — победить в конце каждого уровня Самого Главного Босса, иначе прохождение локации придется начинать сначала. Больше всего в Wolfenstein 3D мне нравилось то, что эту игру можно было проходить, не включая мозг: жмешь на кнопки и думаешь в это время о чем-то своем. Лепота!

▍ DOOM

Чтобы скопировать на мою машину легендарный DOOM, пришлось потратить целую пачку дискет, но результат меня все равно немного разочаровал. То ли проблема была в установленном на моей «трешке» процессоре от AMD, то ли машине банально не хватало памяти (в системных требованиях указано 4 Мбайта, а у меня имелось всего лишь 2), но в полноэкранном режиме DOOM превращался на моем компе в слайд-шоу. С нормальной скоростью игра шла, только если я выставлял в ее настройках минимальное экранное разрешение — и тогда она запускалась в «окошке» с черными рамками по краям. Но даже в таком виде графика здесь была намного круче, чем в Wolfenstein 3D, а геймплей оказался намного более продвинутым!

Действие игры разворачивалось в зданиях Объединенной Аэрокосмической Корпорации (ОАК), которая, судя по всему, попыталась построить «Суперджет», но вместо этого случайно открыла врата в ад. После чего помещения этой уважаемой организации заполонили эффективные менеджеры из параллельного мира в лице монстров и какодемонов, с которыми в меру своих скромных сил и борется главный герой. Здесь ребята из ID Software постарались на славу. Красивые текстуры стен, пола и потолка, разный уровень освещенности в различных локациях, широкий арсенал оружия (особенно радовала бензопила!), монстры, которые, подобно диким обезьянам из Бразилии — ка-а-ак прыгнут! — в общем, игра затягивала. Часик-другой поDOOMать долгими зимними вечерами стало для меня доброй традицией.

Антураж игрового мира тоже сделал значительный шаг вперед по сравнению с Wolfenstein 3D. Порталы, мгновенно переносившие игрока из одной локации уровня в другую, лифты, лава и кислота вместо пола, или даже пол, на глазах превращающийся в лаву. Красота, да и только!

Правда, маленькое экранное разрешение откладывало свой отпечаток на игровой процесс и сильно снижало эффективность отстрела монстров. Спасало волшебное IDDQD, IDKFA. Впрочем, даже без читов игрушка казалась чем-то невообразимым — именно она заставила меня начать копить деньги на компьютер помощнее. Если бы не тормозящий DOOM, я бы, наверное, не нашел для себя стимула устроиться на работу в редакцию компьютерного журнала, куда я ежедневно бегал после институтских занятий. Это очень помогло мне потом в окончательном выборе профессии.

▍ UFO: Enemy Unknown

Прилетело НЛО и оставило здесь эту запись. Вернее, оно оставило импульсный излучатель, часть гиперпривода и еще несколько странных артефактов, которые теперь нужно отнести в лабораторию для дальнейших исследований. Именно так следовало поступать игроку в пошаговой стратегии UFO: Enemy Unknown (известной также под названием X-COM: UFO Defense) от MicroProse, которую я прошел полностью, от начала и до конца. Эта стратегия стала моей самой любимой игрой в 1995 году!

По сюжету нашу планету ни с того ни с сего стали регулярно посещать инопланетяне на летающих тарелках разного калибра — от крошечных двухместных блюдечек до двухэтажных суповых кастрюль борщеизмещением в несколько тонн. Для борьбы с этими аномальными явлениями мировые правительства создали команду элитных бойцов X-COM (eXtraterrestrial Combat Unit — подразделение по борьбе с внеземными угрозами). Оказывается, из далекого космоса к нам прилетают представители сразу нескольких рас, строят тайные базы на Земле, воруют коров нападают на города и готовятся к полномасштабному вторжению.

При обнаружении в атмосфере Земли очередной инопланетной посудины следовало отрядить на ее перехват истребитель. Если он упускал тарелку, она успешно завершала свою миссию и тем самым приближала мрачный час захвата колыбели человечества гуманоидами. Если же инопланетный корабль удавалось сбить, к месту его жесткого приземления нужно было направить отряд бойцов X-COM, предварительно вооружив их различными смертоносными девайсами из имеющегося арсенала — на выбор игрока. Также требовалась зачистка мест посадки тарелок, если им удавалось приземлиться невредимыми — но сначала нужно было узнать, где именно она села. Рейды следовало устраивать при обнаружении наземной базы инопланетян или в случае их нападения на населенный пункт, либо собственную базу игрока.

И вот тут начиналось самое интересное! Гуманоиды могли прятаться вокруг корабля — в близлежащих капустных грядках — или внутри самой тарелки, и при виде явившихся по их душу солдат открывали огонь. Управляя своими солдатами в пошаговом режиме, нужно было аккуратно перебить всех пришельцев, не потеряв при этом ни одного бойца, или взять их в плен, собрать уцелевшие в тарелке артефакты и передать их ученым. По мере исследования инопланетных технологий в арсенале отряда появлялись новые виды вооружений — более мощные и продвинутые.

Игра имела еще и экономическую составляющую: если действия игрока оказывались успешными, ему увеличивали финансирование, он мог строить новые базы в разных уголках земли (чтобы сократить время подлета к кораблям врага и местам посадки тарелок), нанимать больше солдат и покупать больше оружия. В случае провальных миссий денежный поток сокращался и начинался финансовый кризис. Кроме того, инопланетяне могли напасть на базы X-COM, которые следовало защищать. Базу можно было расширять, выбирать наиболее интересные для исследования технологии, покупать и продавать оружие и амуницию, строить новые перехватчики и транспортные корабли для перевозки солдат. Цель игры — хорошенько изучить технологии пришельцев, соорудить межпланетный корабль и раздолбать их базу на Марсе.

Игра была настолько потрясающей, что оторваться от нее казалось невозможным. Разработчики тщательно продумали все: и стратегию (размещение баз на поверхности Земли, представленной в игре вращающимся глобусом), и экономику, и дерево технологий, и тактические бои на сгенерированной компьютером карте. Причем каждый солдат обладал своим набором характеристик: например, дальность его перемещений напрямую зависела от того, сколько амуниции ты на него нагрузил, а точность стрельбы определялась опытом. Помимо лучевого оружия в игре присутствовали пси-излучатели, с помощью которых осуществлялись «психотронные атаки». Последний оставшийся в живых пришелец в локации мог запаниковать и сныкаться, после чего его очень долго приходилось искать, а потом выковыривать из убежища. А иногда в бой вмешивались и мирные жители, явившиеся поглазеть на дивное зрелище — истребление инопланетных гостей.

Эта чудо-игра оставила глубокий след не только в истории гейм-девелопмента и психике тысяч юных поклонников стратегий, но и хорошенько наследила в культуре. Именно на ней основывался сюжет одной из первых отечественных Лит-РПГ— романа Владимира «Вохи» Васильева «Враг Неизвестен».

Пройдя до конца «Enemy Unknown», я с предвкушением ожидал выхода второй части: «Terror from the Deep». Но приключения инопланетян, внезапно отрастивших жабры и нападавших на человечество из глубин океанов, показались мне таким откровенным фуфлом, что свое знакомство с серией X-COM я решил на этом закончить. Возможно, и зря: вышедший в 1997 году ремейк под названием «X-COM: Apocalypse» очень хвалили, но я в него, к сожалению, не играл.

▍ Дюна-2

Харвестр! Это забавное слово — пожалуй, единственное, что накрепко засело в моей памяти после знакомства со стратегией реального времени Dune II. Первая игра цикла от Cryo как-то прошла мимо меня, да и вторая от Westwood Studios почему-то не особенно впечатлила. Наверное, чтобы стать фанатом этой стратегии, сначала нужно было прочитать книгу Фрэнка Герберта. Но книгу я так и не осилил, а потому оценивал игру исключительно с точки зрения стороннего наблюдателя, совершенно не погруженного в мир Дюны.

В качестве стороны, за которую буду играть, я выбрал ребят с финской фамилией Харконнен. Дальше события развивались традиционно: строительство базы, перерабатывающего завода, сбор спайса с использованием харвестров, напоминавших трактор «Беларусь», вид сверху, сражения с соседями и «песчаными червями», так и норовящими проглотить очередной трактор… Пардон, харвестр. В общем, грусть. До цели игры — завоевания всей планеты Арракис – я так и не дошел, во-первых потому, что в процессе игры чуть не окочурился от тоски, а во-вторых потому, что на какой-то очередной тусовке друзья показали мне совершенно обалденную игруху, от которой у меня тут же напрочь снесло крышу — настолько классно она была нарисована. Игра называлась…

▍ Warcraft: Orсs and Humans

Насколько мне не зашел инопланетный мир Арракиса, ровно настолько меня покорил волшебный мир Азерота. Эта игра от совершенно незнакомой мне тогда компании Blizzard Entertainment могла похвастаться не только чудесной графикой, она открывала перед игроком целый мир со своей историей и мифологией. Согласно сюжету игры, в Азероте внезапно стали открываться порталы между мирами людей и орков, что привело к жестокой войне этих двух рас. В целом, история этого конфликта неплохо показана в одноименном фильме, вышедшем в прокат спустя 22 года после появления игры.

Играть можно было как за людей, так и за орков — я, разумеется, успешно прошел обе компании. При этом миссии объединялись сквозным сюжетом, и чтобы перейти к следующему заданию, следовало завершить предыдущее. Геймер должен был не только управлять войсками, но также стpоить поселения, собирать ресурсы и развивать технологии, чтобы добиться превосходства над противником. В некоторых миссиях обходилось без строительства: например, командуя небольшим отрядом, игрок должен был исследовать какую-то локацию или отыскать и спасти героя. В общем, все то, что сейчас можно назвать традиционной составляющей любого сингл-плеера RTS, в Warcraft: Orсs and Humans было реализовано впервые.

Искусственный интеллект в игре отличался некоторой туповатостью: самая выигрышная стратегия в первом «Варкрафте» сводилась к тому, чтобы собрать толпу побольше и идти топтать врага. Срабатывало безотказно, лучше всякой хитрой тактики. У игры был и многопользовательский режим, которым я, впрочем, не пользовался.

Первый «Варкрафт» стал, пожалуй, одной из самых успешных франшиз в истории мирового игростроя. Через пару лет я в точности так же полностью прошел WarСraft II, отличавшийся продвинутым приключенческим сюжетом, наличием новых персонажей, более качественной графикой и новыми юнитами (особенно веселили меня гномьи подводные лодки, с помощью которых было здорово топить ладьи противника). Серия, как известно, жива до сих пор — благодаря вселенной World of Warсraft. Кроме того, недавно Blizzard зачем-то переиздал классический Warсraft III, не нашедший, впрочем, понимания у поклонников сеттинга и олдфагов вроде меня.

▍ А что потом?

К 1996 году скромных ресурсов 386-го стало катастрофически не хватать, и мне пришлось изыскивать возможность раздобыть технику помощнее. Тогда велись ожесточенные дискуссии по поводу плюсов и минусов классических процессоров 80486 от Intel по сравнению с am486 от AMD, конкуренцию которым составляли более дешевые аналоги от Cyrix. В 1996-м я стал обладателем машины на полудохлом Cyrix Cx486S (486SX) с 8 Мбайтами оперативной памяти, на которой едва-едва ворочалась Windows 95. Позже эту коматозную конструкцию удалось проапгрейдить до полноценного 486DX2-66, а спустя еще год с небольшим — до первого «пня».

На этих машинах мы уже рубились в Command & Conquer и Red Alert, первых «Героев меча и магии», Duke Nukem, Heretic и Quake, познавали таинства любви вместе с Ларри и исследовали пластилиновый мир в компании смешного персонажа The Neverhood (эх, какая волшебная там была музыка!). Но это — уже совершенно другая эпоха и совершенно другая история…


ссылка на оригинал статьи https://habr.com/ru/company/ruvds/blog/564688/

Генератор фракталов и математика внутри нас

Три стихии: огонь, вода и Милла Йовович (ниже будут спекуляции о процессе её воссоздания в фильме «Пятый элемент»)
Три стихии: огонь, вода и Милла Йовович (ниже будут спекуляции о процессе её воссоздания в фильме «Пятый элемент»)

Приглашаю отведать салат из разнородных, но неожиданно связанных друг с другом тем:

  • Почему нам нравится симметрия и фракталы? И как это влияет на выживаемость?

  • Как математика связана с эмбриональным развитием?

  • Сколько старинных программ ещё надо спасти от неумолимого времени?

  • Конкурс красоты среди фракталов.

А не странно ли, что нам приятно видеть симметричные объекты? Но если симметрии чрезмерно много, то это почему-то начинает раздражать. Возможно, мы найдём в этом смысл, если приблизимся к пониманию вычленяемых мозгом принципов формирования всего вокруг. А для этого мы поиграем с очередным генератором фракталов, в котором удобно творить почти всё: от островов в океане и облаков на небе до кровеносной системы, от галактик до обоев на рабочий стол мельчайших частиц.

Сердечный след от лопатки для перемешивания теста
Сердечный след от лопатки для перемешивания теста

Даже в рекомендациях по композиции кадра начинающим фотографам напоминают, что нельзя забывать про симметрию, если хочется сделать приятный снимок. Архитекторы и дизайнеры тоже редко обходятся без симметрии, причём не только из-за физических ограничений мира и требований к оптимальности конструкции, но и ради удовлетворения эстетических предпочтений заказчиков.

А уж если речь заходит о продолжении рода, то большинство почему-то предпочитает людей с симметричными лицами, например. Одно из объяснений этого явления состоит в том, что миллионы лет эволюции научили нас считать несимметричность признаком болезни или опасности. Почему так вышло?

Наш мозг привык легко распознавать правила, по которым построен симметричный объект, поэтому скорее относит его к классу «понятных». Получается, что симметрия — это простота и элегантность, дающие нам экономию усилий. Кроме того, на многих уровнях познания мы видим что-то подобное:

Иллюстрация из статьи Бозон Хиггса и Наделение Массой
Иллюстрация из статьи Бозон Хиггса и Наделение Массой

Возможно, миллионы лет естественного отбора научили наш мозг избегать непонятные случайные штуки, из-за чего он и недолюбливает несимметричность. Это могло получиться, потому что в природе кроме беспорядка есть вполне внятные структуры. Соответственно, мы стремимся разглядеть закономерность/симметричность/фрактальность в том, что видим вокруг, чтобы хотя бы мысленно переместиться из реального окружающего нас хаоса во что-то предсказуемое, тем самым почувствовав себя в большей безопасности.

Конечно, маркетологи этим тоже пользуются, см. примеры фотографий с симметричной подачей блюд. Даже немножко раздражает, да?

Почему же мы не любим, когда всё-всё симметрично? Есть предположение, что эволюция и тут всё придумала за нас. Простое объяснение звучит так: в природе мало чрезвычайно симметричных объектов, поэтому мозги к такому просто не привыкли. Соответственно, оказавшись в микрорайоне из одинаковых домиков, мы начинаем паниковать, ведь смотрим на что-то противоестественное.

Другое объяснение можно считать совсем выдуманным из пальца, но какая-то красота и в нём всё же есть. Представьте, как давным-давно неудачники не умели распознавать правила симметрии, поэтому тратили больше ресурсов на понимание простых объектов. Так они проиграли гонку более смышлёным нашим предкам, которые легко видели подобные простые закономерности.

Но далее ситуация продолжила усложняться. Шансы на выживание зависят в том числе и от способности понимать мир. И можно предположить, что те древние люди, которые погрязли в специализации на простейшей симметрии, стали проигрывать нашим предкам, научившимся видеть красоту/смысл/закономерности во фракталах.

Конечно, дело не в распознавании фракталов, а в более развитой способности узнавать и понимать сложные структуры, что критично для выживания. Наши с вами предки видели, что симметрия всё же тривиальна, но они оказались способны разглядеть куда более интересные зависимости. Фракталы, возможно, как раз достигают той самой точки, в которой уже исчезает тривиальность, но ещё сохраняется структура.

Но откуда же кругом в мире симметрия и тем более фракталы?

Для разных объектов есть схожие объяснения. Давайте вникнем в этот вопрос, взглянув через призму крупных пикселов на процесс эмбрионального развития. Для этого мы попробуем из одной клеточки восстановить целую Миллу Йовович, как и договаривались в самом начале.

Сразу оговорюсь, что я специально не поставил тэг «Биология», потому что про все эти гомеозисные гены и градиенты концентрации белков-морфогенов понимаю очень поверхностно (желающим погрузиться в этот мир могу рекомендовать «Нужны ли эмбрионам гены?», но начать всё же стоит с Википедии).

Природа не станет зря тратить драгоценные биты на отдельное описание правых и левых конечностей или, например, одинаковых лепестков, поэтому изобрела всякие ловкие механизмы, от которых у специалистов по рефакторингу не только волосы в жилах стынут. Речь о том, что из клетки может развиться многое, но получается мизинец левой ноги, раз уж соседи этой клетки формировали в тот момет именно стопу и именно левой ноги.

Раз так, то давайте поймём, как это всё работает хотя бы в нашей выдуманной модели, а не в настоящем фантастическом фильме.

Чудесное преврашение одного пиксела в гордо звучащего человека
Чудесное преврашение одного пиксела в гордо звучащего человека

Кстати, поздравляю, мы наконец-то подошли к математике, системам итерируемых функций (про IFS на Хабре ранее было здесь), системам Линденмайера (см. «L-системы и что они себе позволяют» и «L-Systems — математическая красота растений») и всему такому. Ниже ещё будет десяток ссылок для желающих познакомиться ближе, но здесь, чтобы не повторяться, я предлагаю лишь примеры с минимальными пояснениями. Да, у меня нет цели ещё раз изложить многократно описанную теорию. Напротив, мы сейчас занимаемся практикой и построением умеренно корректных аналогий.

Итак, формирование человечка выше выполняется по очень простому принципу — каждая клетка 1×1 заменяется на блок из 3×3 клеток по девяти элементарным правилам:

Девять правил для иллюстрации процесса эмбрионального развития
Девять правил для иллюстрации процесса эмбрионального развития

Начинается всё с одной единственной красной клетки, из которой на первом шаге мы получаем две синих (будущие руки), четыре зелёных (будущие кисти и стопы), две жёлтых (голова и туловище) и т.д. Обратите внимание, что рядом с синими квадратиками есть как в зеркало глядящие друг на друга треугольнички (они выделены кружками) — таким образом задаётся ориентация этих двух клеток, чтобы из них в будущем получились симметричные конечности.

Далее это всё продолжает делиться, становясь всё более гладким и человекообразным. Например, на втором шаге синие клетки (будущие руки) по центральному правилу превращаются в последовательность из розовой-красной-розовой клеток, под которыми шесть белых (пустых) ячеек. Затем красные клетки будут оставаться красными навсегда (т.е. заменяться на блок из 3×3 таких же красных клеток). Короче, всё как у людей, только гены заменены на весёлые картинки.

Вместо чтения словесного описания запустите генератор с этими правилами! Просто пройдите по ссылке, чтобы разглядеть процесс развития человечка на всех этапах. Меняя параметр Depth, вы задаёте количество итераций. Слева палитра цветов и ориентаций, а рядом с нею все правила, которые можно свободно менять. И сразу всё станет ясно!

Получается, что этот набор правил можно считать аналогом ДНК, определяющим развитие организма на протяжении произвольного количества итераций. В текстовом виде инструкции для построения человечка записываются также коротко: {«depth»:3,»n»:3,»rules»:[[106,3,706,4,3,404,6,5,406], [1,1,1,1,1,1,1,1,1], [1,308,7,1,1,7,1,708,7], [8,7,408,308,7,508,2,7,402], [608,7,408,1,1,1,1,1,1], [708,502,108,7,1,7,7,1,7], [1,1,1,1,1,1,1,1,8], [7,7,7,7,7,7,7,7,7],[1,1,708,8,7,7,7,7,7]], «colors»:[«#ff0000», «#ffffff», «#f7bfbf», «#E6B333», «#3366E6», «#999966», «#99FF99», «#d24b81», «#e585bd»]}.

Другой пример перистых облаков устроен ещё проще: всего три правила на матрицах 2×2:

Не похоже на облака? По-моему, это куда больше похоже на перистые облака, чем тот красный человечек на Лилу.
Не похоже на облака? По-моему, это куда больше похоже на перистые облака, чем тот красный человечек на Лилу.

Да, оказалось, что всего трёх простых правил хватает, чтобы построить несимметричную, но вполне регулярную конструкцию, которую глазом легко отличить от хаоса. В окружающем нас мире подобного много, что и неудивительно, учитывая элементарность правил.

Опять же, тут мы имеем очень короткий JSON с текстовым описанием, а поиграть с этим фракталом можно тут:
{"depth":10,"n":2,"rules":[[200,1,100,600],[1,102,100,100],[2,102,2,2]],"colors":["#9fbae9","#735cc7","#ffffff"]}

Любители классической математики могут вспомнить общеизвестный ковёр Серпинского (как обычно, по этой ссылке на генератор можно менять все параметры и правила):

Такой ковёр при бесконечном количестве итераций хоть и имеет бесконечный периметр, нулевую площадь, а также дробную размерность (ln 8/ln 3 ~ 1,89), но всё же глазу не кажется особо интересным, поскольку он одинаковый и понятный во все стороны. Как было показано выше, самое разнообразное и красивое происходит, если доворачивать и отражать треугольнички ориентации клеток. Попробуйте!

История генератора фракталов и благодарности

Идея реализовать эту систему возникла после встречи со старинной программой Changer2 (​1997 Юрий Хан, лицензия CC0 v.1.0 или старше), которая основана на ещё более давней программе Changer (её найти не удалось, но есть свидетельства, что сделал её Евгений Кашменский). Программа Changer2 реализована больше двух десятилетий назад, так что для её запуска может понадобиться старая версия Windows или эмулятор. Примерно так это всё раньше выглядело (здесь же виден пример симпатичного фрактала):

В очередной раз запустив эту чудесную программу, я вспомнил о том, как добрые люди недавно спасли прекрасную японскую игру «Jelly no Puzzle» (выглядела она как-то так). Они перенесли основную логику в браузер. Да, пропала анимация и музыка, но продуманные уровни сохранены, а это важнее.

Увы, многие замечательные программы уходят, потому что, как бы нелепо это ни звучало, современные компьютерные системы для них не подходят. Профессионал запустит что угодно в эмуляторе, но большинство остаётся без древних волшебных программ. Прогресс неумолим, так что нам остаётся только успевать спасать то, что лично нам нравится и кажется правильным. А какую программу из своего детства вы бы хотели воскресить, чтобы поделиться с потомками?

Кадр из фильма «The Hudsucker Proxy»
Кадр из фильма «The Hudsucker Proxy»

Я постарался повторить Changer2 в браузере, чтобы современные дети от 7 до 107 лет смогли приобщиться к исследованию фракталов ещё и таким образом. Если формулировать мечту совсем серьёзно, то я хотел предложить детям среду для эстетически-математических экспериментов, а через 30-40 лет случайно узнать, что один из нобелевских лауреатов в своей речи вспоминает, как заинтересовался наукой, играя с генератором фракталов с Хабра, но уже не помнит, с каким.

Да, это для детей! И для всех нас.

Конкурс красоты среди фракталов

Эксперименты на живых людях показали, что в этом генераторе фракталов удаётся строить самые неожиданные конструкции. Поэтому я приглашаю вас попробовать создать что-то предельное: радующее глаз и поражающее простотой правил, но удивляющее замыслом и не дающее покоя.

Делитесь в комментариях ссылками на свои фракталы, а также изображениями с интересными их фрагментами. А ещё, пожалуйста, проголосуйте за понравившиеся фракталы в чужих комментариях, чтобы коллективное и бессознательное Хабра выбрало самый красивый фрактал!

Ссылки

Если вам интересна эта статья, то, вероятно, коллекция ссылок тоже порадует:

Присылайте свои фракталы в комментарии! Полный адрес фрактала можно взять как в адресной строке браузера, так и скопировав его из ссылки «Link to this configuration» на странице генератора. Изображение же проще всего получить, выбрав пункт «Copy image» или «Save image as…» в контекстном меню сгенерированной картинки. Кнопка «Back» браузера работает как «Undo», так что вы всегда сможете откатиться на предыдущее состояние своего набора правил. Если попробуете построить изображение больше, чем 2200×2200 точек, то система переспросит, так как это всё же может быть долго (для работы в таком высоком качестве рекомендую отключить автоматическую перерисовку).

ссылка на оригинал статьи https://habr.com/ru/post/565416/