Почему Дуолинго

Хотелось бы немного продолжить тему про «Дуолинго». Мне кажется, надо ответить на вопрос почему я выбрал именно приложение, а не нанял репетитора или не выбрал любой другой метод.

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

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

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

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

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

Оставить комментарий

Девочка Кинсу

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

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

Получилась по-детски наивная, но довольно интересная история про девочку Кинсу.


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

Всем привет! Это моя книга, и сегодня я расскажу о себе. Меня зовут Кинсу, мне 18 лет. Я ухожу из дома и ищу работу. Вы, наверное, спросите, какая работа у меня будет? Не знаю, наверное, скучная, как я в детстве себя представляла. Начинаем рассказ.

Кинсу ушла с работы и вдруг нашла странный предмет. Она посмотрела на него: он был жёлтый и какой-то очень странный. Он был похож на камень, но нет, у него были очень странные узоры. Она подумала: «Что это? Надо загуглить в интернете». И пошла домой. Пошла она домой, легла спать, а предмет начал светиться. Из него пошёл красный дым. Под утро этот предмет испарился, и Кинсу его не нашла. Она подумала: «Ну, не знаю, может это грабители». Но оказалось, что в доме никого не было. Она посмотрела на свою руку и вдруг заметила очень странный знак. Он напоминал созвездие Большой Медведицы. Она подумала: «Откуда это у меня? Может, я татушку нарисовала, но забыла?» И пошла дальше.

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

На следующий день её уволили. Она очень расстроилась, но пошла в зоомагазин. Там она увидела красивую собаку. У неё осталось немного денег, и она решила её купить. Собака оказалась очень красивой и послушной овчаркой. Кинсу даже заплакала от счастья, когда её купила, и пошла домой со своей новой подругой.

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

В общем, Кинсу пришла с работы и сказала собаке: «Привет, Галя!» — так она её назвала. Вдруг неожиданно собака ответила: «Привет, Кинсу!» Кинсу подпрыгнула от страха. Собака сказала: «Спасибо, что не боишься меня. Мы с тобой друзья, не бойся». Кинсу ответила: «Я не испугалась, но почему ты говоришь?» Собака объяснила: «Я всегда умела говорить, только ты теперь научилась меня слышать». Кинсу удивилась: «Понятно, наверное, я сплю». Но собака ответила: «Нет, ты не спишь». Кинсу спросила: «Тогда почему ты говоришь? Ты же никогда раньше не говорила, и другие собаки не умеют говорить». Собака ответила: «Ты научилась нас слушать». Кинсу задумалась: «Ага, понятно. Значит, я каким-то образом научилась вас понимать. Объясни, моя чудесная собачка Галя, как это произошло?»

Галя спросила: «Помнишь, ты подобрала камешек на улице, когда шла на свою первую работу?» Кинсу ответила: «Да, помню. А что он сделал со мной?» Галя объяснила: «Он волшебный. Его создали, чтобы восстановить вселенную, которая погибла из-за страшной болезни. Тебе надо подружиться с духами стихий, чтобы спасти всё». Кинсу не совсем поняла, но согласилась: «Ага, спасибо, Галя». Собака добавила: «Тебе надо начать с Жизнь, с ним легче всех». Кинсу спросила: «А где его искать?» Галя ответила: «Ищи там, где живёшь. Это твоя жизнь».

Кинсу жила в однокомнатной квартире и никого там не видела. Галя объяснила: «Он приходит к тебе каждую ночь». Кинсу удивилась: «А почему именно ночью?» Собака ответила: «Он боится, что его увидят». Кинсу взяла Галю на поводок, и они пошли на прогулку. Гуляли долго, пока не наступил вечер. Галя сказала: «Пошли домой, уже поздно. Скоро будем встречать его». Они вернулись домой, Кинсу всё подготовила и стала ждать.

Вдруг она услышала голос: «Привет, все ли живы? Кому пора наверх?» Это был голос Жизни. Он звал своего брата, Смерть, и говорил, что они создают новые жизни. Кинсу спросила: «А мне можно тоже ребёночка?» Галя ответила: «Есть у меня один на примете». Кинсу заинтересовалась: «Кто это?» Галя сказала: «Энит». Кинсу спросила: «Где он живёт и как мне с ним познакомиться? У меня столько вопросов, но я стесняюсь и не хочу замуж». Галя успокоила её: «Тише, он пришёл».

Жизнь подошёл к столу и прочитал записку, написанную красивым аккуратным почерком: «Мы ждём тебя». Он сказал: «Выходите, кто меня ждал, но вы меня ещё не увидите, потому что я невидимка и не услышите». Вдруг из-за дивана вылезла Кинсу и сказала: «Я тебя вижу и слышу». Жизнь удивился: «Почему?» Кинсу ответила: «Не знаю, моя собака говорит, что я подобрала какой-то камешек, из-за него я научилась видеть духов и говорить с животными». Жизнь спросил: «Это жёлтый, немного прямоугольный камень?» Кинсу подтвердила: «Да». Жизнь объяснил: «Тебе надо подружиться со всеми духами. Я первый».

Вдруг из-за дивана вылезла Галя и сказала: «Здравствуйте, уважаемый Жизнь». Жизнь удивился: «А вы кто?» Галя ответила: «Я Галя, а вас зовут Жизнь, правильно?» Жизнь подтвердил: «Да, правильно. А тебя как зовут, девочка?» Кинсу ответила: «Меня зовут Кинсу». Жизнь сказал: «Понятно, а я — Жизнь. Вот и познакомились. А кто у вас следующий по списку или у вас нет списка?» «Нет» — ответили они. Жизнь сказала: «Следующий — Смерть» и предупредил: «С ним будет посложнее. Вы не боитесь кладбищ и ужастиков?» Кинсу и Галя ответили: «Нет». Жизнь сказал: «Тогда пошлите в его дом. У него там страшновато». «А что там такого, наверняка дом как дом» — спросили Кинсу и Галя. «Не просто дом, у него там страшно, как на кладбище, вы точно не боитесь идти к нему знакомиться?» — спросил Жизнь.

Они пошли к дому Смерти. По дороге Жизнь вёл себя странно. Кинсу спросила: «Ты что, испугался?» Жизнь ответил: «Нет». Кинсу удивилась: «Тогда почему ты дрожишь?» Жизнь ответил: «Я не дрожу, это кто-то другой». Кинсу и Галя засмеялись. Жизнь сказал: «Как по-моему, нет ничего смешного в том, что человек боится Смерти». «Ну ты же Жизнь, а не человек, разница в том, что люди умирают, а ты — нет» — сказали Кинсу с Галей. Вдруг из-за их спины появилась Смерть. Все закричали: «Ааа!» Смерть спросил: «Ладно, хорошо, зачем пришли?» Кинсу выступила вперёд и смело сказала: «Я случайно подобрала камешек, который говорит, что вы создали Жизнь. Я пришла, чтобы объединиться с вами и что-то спасти». «А что спасти?» — спросила она у Гали. «Спасти вселенную» — шепнула Галя на ухо подруге. «А, точно, вспомнила, чтобы спасти вселенную» — сказала Кинсу. Смерть ответил: «Понятно. Тогда действуйте быстрее, у нас времени нет, чтобы знакомиться. Тебе надо собрать всех духов и восстановить вселенную. У тебя уже есть две суперсилы».

Они пошли дальше. Жизнь шепнул Кинсу: «Я же говорил, что будет сложно». Кинсу отмахнулась: «Ты много чего говоришь». Они нашли Ночь, которая облетала землю, чтобы везде был покой. Кинсу крикнула: «Привет!» Ночь удивилась: «Кто ты и почему видишь меня и почему с тобой Жизнь и Смерть?» Кинсу объяснила: «Мы собираем все суперсилы, чтобы восстановить вселенную». Ночь согласилась помочь.

Они пошли по поиски ещё одной суперсилы и не заметили, что за ним следят агенты. Агенты следили, пытаясь понять, что делает Кинсу с собаками и суперсилами.

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

Жизнь, Смерть, День, Ночь и Галя пошли на поиски следующей суперсилы, а девочка осталась одна. Увидев это на неё накинулись агенты и пытались поймать её сетью. Они удивились, увидев, как Кинсу превратилась в лошадь и убежала. Агенты позвонили начальству по рации и сообщили: «Девушка сбежала из наших сетей и превратилась в лошадь». Кинсу и её друзья продолжали поиски. Они нашли все суперсилы: Жизнь, Смерть, Утро, День, Вечер, Ночь, Воздух, Землю, Огонь и Воду. Кинсу сказала: «Я очень устала, может мне использовать свою магию?» Смерть ответил: «Как хочешь». Кинсу использовала магию и создала палатку, спальники и даже костюмы всем.

Потом они сказали: «Может ты нам лучше дом сделаешь?», она убрала созданное и сделала большой красивый замок с лошадьми и остальными животными, которых она очень любила, и отдельные комнаты для каждой суперсилы.

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

Вот и конец этой истории. Наверное, будут и следующие рассказы. Этот был первым. Кинсу — девочка, которая начала новую вселенную. Вы тоже сможете добиться своих мечтаний, если будете стараться, дружить и делать хорошие поступки. Учитесь на отлично, работайте хорошо и никогда не сдавайтесь. У вас всё получится! До свидания. Я заканчиваю на сегодня этот рассказ, но завтра, возможно, напишу продолжение.

3 комментария

Лупа для пайки

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

Ну что я могу сказать? Зрение уже не то, мне нужна лупа. Запаял полтора резистора наощупь, начал паять четвёртую ножку, не припаивается нормально. У основания олова нет, это я разобрать могу, но толком ничего не вижу, тыкаю припоем почти наугад.

Интересно, есть ли обзоры луп для паяния, надо бы посмотреть. Хочется купить что-нибудь нормальное.

Рабочее место радиолюбителя: серая антистатическая подставка с паяльной станцией, паяльником, пинцетом, кусачками, платой, припоем и компонентами на деревянном столе.

25 комментариев

99 бутылок: калькулятор bc

Разбирал одну старенькую научную статью с некоторым количеством математики, а внутри увидел вычисления на bc.

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

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

82. bc — интерактивный интерпретатор Си-подобного языка, появившийся ещё в 1975 году как интерфейс для утилиты dc, на котором «песню о пиве» я уже писал. Утилита dc выполняла вычисления с произвольной точностью, используя обратную польскую запись, а bc предоставила более привычный Си-подобный синтаксис, транслируя его в команды dc. В 1991 году утилита bc была стандартизирована POSIX, и сегодня существует несколько её реализаций.

/* Beer song. Evgeny Stepanischev, Jan 2025 */

define void bottles(b) {
    if (b) print b else print "No"
    " bottle"
    if (b-1) print "s"
    " of beer"
}

for(beer = 99; beer;) {
    bottles(beer); " on the wall, "
    bottles(beer); print "!\n"

    print "Take one down, pass it around,\n"
    bottles(--beer); print " on the wall!\n\n"
}

print "No more bottles of beer on the wall,\n"
print "No more bottles of beer!\n"
print "Go to the store and buy some more,\n"
bottles(99); " on the wall!"

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

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

Добавлено позднее: как оказалось, у языка есть свои особенности о которых нелишне знать. Например, подключение математической библиотеки меняет точность, определяемую переменной scale, что влияет, например, на операцию вычисления модуля, она начинает работать иначе.

Другая странность — операции сдвига работают в десятичной системе. Не понимаю какой от этого толк. Например, 1<<2 даст 100.

Оставить комментарий

Зелёная зима

Зима в этом году, конечно, удивительная. Во дворе уже всё меньше снега и всё больше травы, даже на кустах уже набухли почки. Немудрено — температура прыгает около нуля, чаще выше, чем ниже. Говорят весь склон под кремлём покрыт травой. У меня была мысль сходить туда, сфоткаться в футболке, когда я ещё в Казани в январе на зелёном газоне посижу? Но поленился, а сегодня, смотрю, уже снег выпал — температура упала до −1°C.

Оставить комментарий

Игра «Виселица» на bc

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

В силу специфики обработки ввода bc, писать нужно что-то пошаговое — фоновое выполнение не поддерживается, программа может работать только от ввода до ввода. Долго не размышляя, я как-то сразу решил написать игру «Виселица». Я её уже писал под «Флиппер», если помните.

Интерфейс игры «Виселица»: алфавит с угаданными буквами t, a, d, e; слово «t _ _ _ t _ d»; виселица с фигурой; запрос ввода буквы или команды exit.
Игровой процесс игры «Веселица», написанной на bc

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

К счастью, «выражения» — это ещё и переменные. Если задать значения всем однобуквенным переменным, мы сможем определить какую именно букву нажал пользователь.

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

a=1;b=2;c=3;d=4;e=5;f=6;g=7;h=8;i=9;j=10;k=11;l=12;m=13;n=14;o=15;p=16;q=17;r=18;s=19;t=20
u=21;v=22;w=23;x=24;y=25;z=26

co[a]="a";co[b]="b";co[c]="c";co[d]="d";co[e]="e";co[f]="f";co[g]="g";co[h]="h";co[i]="i";co[j]="j"
co[k]="k";co[l]="l";co[m]="m";co[n]="n";co[o]="o";co[p]="p";co[q]="q";co[r]="r";co[s]="s";co[t]="t"
co[u]="u";co[v]="v";co[w]="w";co[x]="x";co[y]="y";co[z]="z"

exit = -1

Заодно я задал значение переменной exit, это слово пользователь может ввести, чтобы выйти.

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

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

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

define get_word(c) {
    if(!--c) return 4328588043
    if(!--c) return 4328588820
    /* и так далее */
    if(!--c) return 437194509

    return -c
}

word = get_word(irand(get_word(0)) + 1)

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

Функция irand, используемая тут, является расширением bc, у меня на «Маке» она поддерживается, но под «Линуксом» её нет, так же как и вообще любой другой функции для работы со случайными числами.

С такими «строками» можно уже как-то работать, например, считать длину, чтобы вывести подходящее количество «окошек», в которых будут появляться буквы:

define word_len(c) {
    scale=10
    return ceil(log(c, 256), 0)
}

Или вывести на печать:

define void print_word(c) {
    auto word, i, mod

    scale=0
    for (i = 0; c; i++) {
        c = divmod(c, 256, mod[])
        word[i] = mod[0]
    }

    while (i--) {
        print co[word[i]]
    }
}

В общем, всё как с обычными строками, только чуть-чуть очень сильно неудобно.

Остальное, в общем-то, писать было просто — логика игры очень простая, пишется за несколько минут. На результат можно посмотреть в моём репозитории на «Гитхабе».

В теории, игру можно портировать и на «Линукс», надо только избавиться от хранения строк в переменных, заменить генерацию случайных чисел на внешний генератор, заменить log() на l(), а divmod() на деление и взятие модуля и избавиться от length() — массив в качестве аргумента в «Линуксе» не поддерживается.

Оставить комментарий

Игра «Виселица» на bc под «Линукс»

Я планировал заняться адаптацией «Виселицы» на bc под «Линукс» на следующий день, то есть сегодня, но не выдержал и вчера просидел над этим почти до полуночи. Линуксовый bc, конечно, гораздо скромнее по возножностям, было где поломать мозг, но больше всего времени я, кажется, потратил на рандомизацию.

Я вчера писал уже, что в документации для линуксового bc нет упоминаний функций для генерации случайных чисел, но чтение исходников показало, что документации не всегда можно верить. Функция есть, называется она random(), но не работает так как хочется — при вызове генерирует всегда одну и ту же последовательность.

Фрагмент кода с функцией Random, содержащий вызов ct_warn, generate и присваивание $$ = EX_REG

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

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

Для этого я изменил способ запуска программы — сделал его шелл-скриптом, который передаёт в bc на инициализации цикл, генерирующий случайное количество вызовов random():

#!/bin/bash
x=/*
BC_LINE_LENGTH=0 bc -l -q <(/usr/bin/seq -f "x=random()+%g" $RANDOM) "$0"
exit; */1

Обвязка с комментарием сделана так, чтобы и шелл, и bc не увидели в коде ничего странно и не выдали ошибку синтаксиса, а вся мякотка происходит в строке /usr/bin/seq -f "x=random()+%g" $RANDOM. Команда seq генерирует последовательность x=random()+число столько раз, сколько указано в переменной $RANDOM. $RANDOM — это специальная переменная шелла, которая содержит случайное значение.

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

Ещё одной крупной проблемой стали строки — в этой версии bc не поддерживается присваивание их переменным. Из-за этого код пришлось сильно переделать.

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

define void print_letter(c) {
    if(!--c){"a"}
    if(!--c){"b"}
    if(!--c){"c"}
    /* …тут все 26 букв */
    if(!--c){"y"}
    if(!--c){"z"}
}

Я не стал ставить return, чтобы сделать функцию более визуально компактной, тем более, что на производительность мне, по большому счёту, наплевать.

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

define read_letter() {
    auto z, b
    b = ibase
    ibase = 36

    z = read()
    ibase = b
    return z - 9
}

Переменная ibase отвечает за систему исчисления при вводе чисел.

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

Остальные проблемы решались попроще. Ещё я немного поломал голову чем заменить ceil (округление вверх), потом догадался прибавить единицу и, выставив через специальную переменную scale нулевую точность для цифр после запятой, разделил получившееся значение на один, чтобы отбросить дробную часть:

define word_len(c) {
    auto r
    scale=10
    r = l(c) / l(256) + 1
    scale=0
    return r/1
}

Функцию логарифма log() тут пришлось заменить на натуральный логарифм l() — это одна из немногих математических функций, которые поддерживаются в этой версии bc.

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

Оставить комментарий

Англо-русский словарь на bc

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

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

Сделал так же, как в версии под «Линукс» — bc переводится на ввод 36-ричных чисел. В таком режиме слова у нас становятся числами.

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

Так что я поступил иначе — проверяю версию bc и, если она достаточной новая (как под «Маком»), запускаю bc через tr, который заменяет буквы в нижнем регистре на буквы в верхнем. В этом случае, начало программы выглядит так:

#!/bin/sh
c=/*
tr -u a-z A-Z | bc -R "$0"
exit; */1

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

Скриншот терминала с англо-русским словарём 2025: ввод слов abalienate, absorbing, cat и их переводы — передавать, поглощать/абсорбция/абсорбирующий, кошка.

Сам словарь нашёлся в интернете. Чтобы не заливать в свой репозиторий чужую интеллектуальную собственность, я сделал make-файл, генерирующий мне программу на bc — словарь скачивается, распаковывается и обрабатывается специально написанной программой на Пайтоне. В итоге получается программа на пятьдесят тысяч с гаком строк.

В результате всё работает шустро, несмотря на линейный поиск. Я вообще не замечаю проблем с производительностью у bc, любопытно. Умели же делать!

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

while(c) while (c) {
ibase=36;c=read();ibase=A

if(c==19976){"Несколько";break}
/* тут очень много строк */
if(c==2813515210532){"Сухарь";break}
if(c==2174201762){"Зигота";break}
"Неизвестное слово";}
quit()

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

Результат, как обычно, можно увидеть в моём репозитории.

3 комментария

Дочкино печенье

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

Замешала тесто, нанесла всё на противень, подстелив бумагу для готовки, и поставила выпекаться в духовку.

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

Печенье оказались вкусными, мы их съели почти сразу, еле успел сфотографировать.

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

1 комментарий

Использую ли я «Флиппер»

Рука держит оранжево-белый клонировщик ключей с экраном «Emulating Home» у панели домофона с кнопками 0–9, SOS и C.

У меня тут спросили, использую ли «Флиппер Зеро», — давно ничего про него не рассказывал. Использую, конечно, и очень интенсивно! С тех пор как потерял магнитный ключ от подъезда, каждый день туда и обратно прохожу, прикладывая вместо него «Флиппер». Всё недосуг заняться этим вопросом.

Хорошо, что ещё в самом начале я записал на «Флиппер» данные всех магнитных ключей, которые у меня были — домашний, рабочий, родственников и так далее.

7 комментариев

Ещё немного про random() в bc

Как я уже рассказывал, bc под «Линуксом» очень старый, — на всех машинах, куда у меня есть доступ, установлена версия 1.07.1 2017-го года. Непонятно с чем связан такой консерватизм, но чем богаты. В этой версии отсутствует до печального много удобных вещей, например, функция для получения случайного числа.

Ранее я обнаружил недокументированную функцию random(), но генератор случайных чисел в линуксовом bc не инициализируется и функция выдаёт на старте всегда одно и тоже число. Её можно покрутить снаружи случайное число раз и это исправляет ситуацию, но способ, который я тогда придумал для этого, так себе.

Сегодня, пока ехал в такси, придумывал ещё более так себе способы это сделать.

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

#!/usr/bin/env -S -i seed_="0${XDG_SESSION_ID};while(seed_--).=random()#" bc /proc/self/environ
print random()
quit()

Здорово, правда?

Вся чёрная магия сосредоточена в первой строке. Файл /proc/self/environ формируется в «Линуксе» для каждого запущенного процесса и содержит унаследованные переменные окружения. Так как там много ненужного нам мусора, очищаем его целиком при помощи ключа -i утилиты env.

Далее мы создаём переменную окружения seed_, а внутри её формируем небольшую программу, которая запустится до нашего кода. Для bc результат будет выглядеть так:

seed_=0123456
while(seed_--).=random()
#^@
print random()
quit()

Я развернул односрочную программу в многострочную для удобства.

Вместо 123456, конечно, будет подставлено число из переменной окружения $XDG_SESSION_ID, которая содержит число. Ноль там впереди, чтобы не случилось ничего страшного, если эта переменная в вашем дистрибутиве «Линукс» отсутствует.

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

В конце файла /proc/self/environ всегда есть символ с кодом ноль, который мог бы нам всё испортить, но мы спрятали его за символом комментария — #.

Как видно, функция random() вызывается seed_ раз, что позволяет остановиться на каком-то случайном значении. Точка (.), которой я присваиваю random(), — специальная переменная bc. У неё есть значение, но, фактически, её частенько используют, чтобы присвоить куда-нибудь ненужные возвращаемые значения; иначе они попадут на экран.

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

18 комментариев

Контент смертен, это полбеды, плохо, что он смертен внезапно

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

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

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

Но никакой поиск — это полбеды. Хуже всего, что со временем этот контент исчезнет навсегда. «Телеграм» помрёт, как умерла когда-то сверхпопулярная «аська», «Фейсбук» исчезнет, как исчез МайСпейс. Никакой «Веб-архив» это всё не сохранит.

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

18 комментариев

Лампочка во рту

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

Неясно было правда это или нет, но дураков экспериментаторов пробовать не было. Тогда другие времена были — интернет ещё не придумали. Но сейчас-то он есть, а в нём есть экспериментаторы!

В общем, я посмотрел много роликов на «Ютубе», где люди пытаюсь засунуть себе в рот лампочку.

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

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

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

Вердикт: лампочка во рту — это не всегда проблемы и поездка в врачу, но ручаться за это я бы не стал.

14 комментариев

Необычная система счисления в bc

В моём временно любимом bc есть интересная, но не сразу понятная особенность работы с числами. Даже в режиме ввода десятичных чисел принимаются буквы в верхнем регистре, то есть число может состоять из цифр в диапазонах 0…9 и A…Z. Буквы при этом обозначают цифры от десяти до тридцати пяти.

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

Расшифровка слов LEET и CODE в числовые значения (21,14,29 и 12,0,13,14) и их суммирование: 22569 и 12144.

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

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

def convert(num):
    if num == 0: return 0
    out, orig_num = "", num

    while num:
        num, r = divmod(num, 10)
        v = min(2 if r > 5 else 3, num)
        if (digit := v * 10 + r) > 9:
            out = chr(digit - 10 + ord('A')) + out
        else:
            out = str(digit) + out

        num -= v

    return out if len(out) < len(str(orig_num)) else orig_num

А потом мы решили развлечься ещё одним способом — аккуратно сформулировать эту задачу в тексте и решить её искусственным интеллектом. Взяли топовые сети — ЧатГПТ, ДипСик и так далее.

Я намеренно не показываю получившийся промпт, вдруг вы захотите тоже попробовать, но скажу сразу — с первого или даже пятого раза сформулировать задачу так, чтобы хоть какая-нибудь нейросеть решила её правильно у нас не получилось. Я, в итоге, сдался, а братишка добился-таки код, который её решает, от ДипСика. Листинг, правда, получился вдвое длиннее, чем у меня.

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

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

Оставить комментарий

Артём Поликарпов

Не знаю как о таком писать. Сегодня я узнал, что несколько лет назад погиб один из моих старых друзей — Артём Поликарпов. Мы знали друг друга больше десяти лет.

В 2022-м году я потерял с ним связь — в «Телеграме» он не отвечал, трубку не брал, а через какое-то время его контакт в мессенджере стал удалённым. В том году это не особо удивляло, многие сильно меняли свою жизнь, часть вместе с кругом своих друзей.

Я тогда как-то не догадался написать нашим общим знакомым. Наверное потому, что придуманная мной версия казалось мне полностью логичной и всё объясняла, а сегодня, в разговоре с одним из них как-то случайно узнал, что в тот год Артём погиб в ДТП.

Мужчина в полосатой рубашке жестикулирует, обращаясь к группе слушателей с бейджами на мероприятии; на заднем плане виден баннер с надписью «404».
Я нечасто фотографирую людей, смог найти только одно фото с Артёмом, его чуть-чуть закрывает козырёк кепки Кураж-Бомбея. Самара, 2012-й год

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

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

Очень странно, что его больше нет.

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

5 комментариев

Ускорение тригонометрических и прочих функций в bc

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

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

Посмотрел разные реализации, в итоге портировал функцию, которую взял из одной из статей на «Хабре», получилось так (используется многочлен Чебышёва):

define mod(a, b) {
    auto s, m
    s = scale; scale = 0; m = a$ % b$; scale = s; return m
}

define s(x) {
    auto sign, xf, per, xx, y

    x *= 0.63661977236758134308
    if (sign = (x < 0)) x = -x

    xf = x$
    x -= xf

    if (mod(xf, 2)) x = 1 - x

    per = mod(xf / 2, 2)
    xx = x * x
    y = x * (1.5707903005870776 + xx * (-0.6458858977085938 + \
    xx*(0.07941798513358536 - 0.0043223880120647346 * xx)))

    if (sign != per) return -y
    return y
}

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

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

define cnt_digits(x) {
    auto i, s
    s = scale; scale = 0

    for (i = 0; x /= 10; i++){}
    scale = s; return i
}

8 комментариев

Ещё о кирпиче с клеймом «.А.»

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

В основном, казанские кирпичные клейма — это две буквы инициалов владельца завода с минимумом украшательств. Очень редко встречаются три буквы и только один раз встретилась одна — «А». Не в том смысле, что я встретил её только на одном кирпиче, а просто других одиночных букв на кирпичах Казани не попадалось.

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

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

Недавно у меня родилась новая версия, опять же, бездоказательная, но в этом направлении можно бы покопать. Я подумал, что «.А.» может быть не инициалами владельца завода, а сокращением названия заведения при котором был завод или для которого делались кирпичи.

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

6 комментариев

Doom на bc

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

Писать начал, разумеется, на одном из самых далёких от вывода графики на экран языков — bc, я ведь теперь всё на нём пишу (ха-ха). Для работы с  графикой в нём нет буквально ни-че-го! Попутно решить считать это хакатоном — дал себе сутки на реализацию. В итоге, писать начал утром, а закончил в три ночи.

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

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

Обычно мы отсылаем в терминал какие-то символы и он их отображает, а как же передать ему графику? Для этого придумали несколько несовместимых способов. Моя любимая программа для работы в терминале iTerm2 придумала собственный. Графику в этом формате можно передать в терминал специальной текстовой командой:

ESC ] 1337 ; File = [необязательные параметры] : изображение в формате base64 ^G

Хорошо, с этим разобрались. Но как нарисовать картинку именно из bc? Тут надо решить несколько очевидных проблем.

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

Во-вторых, нужно написать свою реализацию кодирования base64. Это, конечно, дело техники, но требует усилий. Тут, кстати, очень помогла обнаруженная в описании языка функция asciify(), которая переводит код символа в сам символ.

В-третьих, и самое интересное, — нужно выбрать какой-то простой бинарный формат, в котором будет формироваться графика. Тут я сразу подумал о BMP, так как в 2005-м году делал библиотеку для работы с ним на PHP.

Схема структуры файла BM: заголовок 42 4D, длина A0 04 00 00, смещение 20 00 00 00, ширина 80 00, высота 48 00, 1 бит на цвет.
Сохранившийся скриншот, где я пытаюсь аккуратно расписать для себя формат BMP Core

BMP — это, как водится во многих старых форматах, внутренне не один формат хранения графики, а несколько. В данном случае я взял самый простой и примитивный — BMP Core с индексированной палитрой из двух цветов.

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

Теперь надо было решить что же я буду писать. На самом деле к этому моменту я уже внутренне определился. В начале двухтысячных локальный фурор произвела игрушка «Wolf5k», написанная на ДжаваСкрипте. Чтобы понять, чем она крута, надо знать, что ДжаваСкрипт тогда графику выводить не умел — не существовало ни тега CANVAS, ни, тем более, WebGL или WebGPU.

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

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

Скриншот кода на JavaScript с функциями для генерации случайных чисел, обработки событий клавиатуры и отрисовки графики в браузере.
Вот и весь исходный код «Wolf5k»

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

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

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

«Wolf5k» — динамичная игра, а во всём языке bc единственная функция ввода — read(), которая требует нажатия на «Энтер» после каждого ввода. Такой себе интерактив.

В самом языке это никак не решить, так что, признаюсь, тут я немного смухлевал — написал на zsh запускающую часть, которая сама читает клавиатуру и пересылает нажатия в bc, «нажимая» на «Энтер»:

#!/bin/zsh
x=/*
while {}; do
    v=
    read -rs -k1 -t0.4 v

    case "${v:l}" in
        [wasdljkm\ ]) printf "%d\n" "'${v:l}";;
        *)    echo 0;;
    esac
done | bc -g -Ll -f "$0"
exit; */1
/* тут программа на bc */

Да, не очень честно, но какой выбор?

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

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

Результат выложил в свой репозиторий. Несмотря на то, что это порт «Wolf5k», игра называется BC-Doom, а не BC-Wolf, потому что как-то так повелось, — называть все подобные трёхмерные игрушки «Думом», а про «Вульф» уже никто и не помнит, как мне кажется.

6 комментариев

Из старых закромов

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

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

Скриншот переписки в WhatsApp с Степанищевой Мариной: обсуждение работы, отхода, встречи в 12, необходимости привезти деньги; сообщения с ошибками и эмодзи, время 10:46–10:48.

4 комментария

А что там с кафе?

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

На фото наши десерты (с розовыми ценниками) в кафе «Скуратов», уже второй день можно купить по всему городу.

Витрина с десертами: моchi с малиной-фисташкой, манго и клубникой под колпаками, сырники с вишней, семена чиа с манго, кунжутный пончик и бутылки Skuratov.

5 комментариев

Обзывалки

Вчера мы с дочкой придумывали рифмованные обзывательства к именам детей в её классе. Учитывая современные имена, это не очень-то просто, знания, полученные мной в детстве, почти не пригодились. Тем не менее, мы справились.

Началось всё с того, что дочка спросила дразнили ли меня в школе в детстве. Ну кого не дразнили? Меня тоже, о чём я честно и сказал. Дочка расстроено сказала, что её тоже дразнят, даже в школу идти не хочется. Я спросил — что она на это отвечает? Оказалось, что ничего, она не умеет придумывать дразнилки.

В общем, это одно из немногих домашних заданий, которые мы сделали вместе.

5 комментариев

Увидел икону

У массажистки, к которой иногда хожу, как-то увидел на кухне икону, как выяснилось, старинную, — пошёл на кухню воды попить, а она там стоит наверху на шкафах. Заинтересовался, оказалось икона бабушкина, откуда взялась — массажистка не знает, бабушка померла давно, пока была жива, об этом не разговаривали.

В иконах я не разбираюсь, да и не особо интересуюсь, так что не сфотографировал, меня заинтересовало кое-что другое.

В основании едва-едва разглядел золотниковую пробу, такие ставили при царизме, и год — 1859. Решил в следующий раз захватить лупу, разглядеть всё получше.

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

Год действительно 1859, над ним буквы — И. А, клеймо Артамонова Ивана Семеновича, мастера, который ставил пробу. Работал в Туле, позже был переведён в Ульяновск. Честно сказать, не знал, что у пробиреров были свои собственные клейма.

84 — это легко, золотниковая проба, в те времена мерили ещё имперскими единицами. В переводе на нашу — 875-я.

Дальше, вроде бы, Георгий Победоносец, пронзающий копьём змея, но не уверен, детализация низкая. Если это так, то икону, вероятно, делали в Москве и инициалы рядом, «АО», расшифровываются как «Алексей Осипов» — был там такой серебряных дел мастер.

Крупный план серебряного изделия с гравировкой и пробами «56», «84» и «1989» на борту, лежащего на красной ткани и светлой поверхности с узором.
Сфотографировано через лупу

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

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

Оставить комментарий

Что там нечётные числа?

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

Тогда я сократил размерность типа вдвое — стал вычислять 64-битные числа и запустил программу почти на два месяца на стационарном компьютере. Там она работала на одном ядре и намолотила 180 с гаком миллионов чисел. Это очень медленно, как по мне.

Скриншот терминала Linux: команда ps aux | grep phase показывает процесс ./phase1 с высоким использованием CPU, затем cd odds/, wc -l log (180170316 строк) и logout.

Сегодня мне надоело, я этот процесс остановил. Вывод — на одном ядре считать совершенно не вариант, надо дописывать многопоточную версию.

Я, кстати, её даже начинал писать — накидал кое-какой скелет, но по дороге решил привлечь к этому делу большие языковые модели. Хотел посмотреть настолько ли они круты, чтобы помочь мне закончить. Пробовал и ЧатГПТ, и уже появившуюся в то время рассуждающую модель DeepSeek R1, бестолку — каждая новая версия программы, написанная с их помощью, не работала так как полагается. В общении с нейросетями я провёл два вечера, а потом просто отложил эту программу в сторону.

Единственное, в чём я признателен нейросеткам, — они решили мою проблему с производительность. Моя многопоточная версия упиралась в блокировку некого разделяемого ресурса и я решил посмотреть справятся ли нейросети с этой проблемой. Справились! В остальном время было потрачено зря.

Надо бы уже показать кованным мешкам кто тут папочка и дописать код самостоятельно.

2 комментария

Быстрый корень из суммы квадратов

Я недавно писал как ускорял свой «Дум» для bc. В частности я заменял тригонометрические функции их менее точными, но более быстрыми, аналогами.

Роман Парпалак посоветовал способ ускорения вычисления квадратного корня из суммы квадратов. Аппроксимация там через формулу 0,96 × x + 0,4 × y при x ≥ y. Погрешность должна быть не более 4%.

Выглядит здорово, я замерил — производительность вырастает в восемь раз, заманчиво, но если посмотреть абсолютную погрешность там она почти 5,5 единиц. Это как будто бы очень много. Я даже нарисовал график разницы между корнем и аппроксимацией в «Днунипере».

Заменять я не буду, но знать о такой возможности полезно, спасибо, Роман!

Оставить комментарий

Улучшение в словаре на bc

За последние недели мой уровень в bc очень сильно вырос. Я стал видеть вещи в своих прежних проектах, которые можно сделать проще и изящнее. Но, кажется, мой рост остановился. Интересно, достиг ли я потолка? Или, может, стал ли я сеньором в этом? Не пора ли мне учить других? Открыть курсы, поднимать сообщество? Вопросы без ответов!

В общем, открыл сегодня, пока ехал в такси, исходник своего англо-русского словаря, написанного на bc, и пришло мне в голову очевидное — не нужно хранить слова в десятичных числах, они длинные и непонятные, надо хранить их как они есть — в виде слов, ведь у нас в bc есть 36-ричная система счисления, то есть десять цифр и 26 букв.

Код на Python с циклом while, выводом приглашения «Введите слово или Ctrl-C для выхода» и условиями if для обработки ввода: FEW, LITTLE, SPRINKLING, TABLE с русскими переводами.

Почему же я раньше-то до такой простой штуки не додумался? Всё приходит с опытом.

Добавлено: грустно — на скриншоте обнаружил ошибки в словаре, который я использую.

3 комментария

Субтитры в «шортсах»

У многих авторов «шортсов» на «Ютубе» какое-то совершенно наплевательское отношение к субтитрам, которое меня удивляет. Делают их, как я понимаю, чтобы «шортс» можно было смотреть без звука. То есть рассчитывается, что это будет кто-то читать.

Я смотрю со звуком, но не читать не могу — у меня как-то автоматически прочитывается любой текст в фокусе зрения.

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

Оставить комментарий

«Охота на роботов», 1984

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

Даже у Артемия Лебедева, когда у него была рубрика «Что за фильм?» в блоге, где люди помогали друг другу вспомнить название по описанию, спрашивал. Но и там не помогли.

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

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

Попробовал описать каждую деталь, которую я помню, китайской нейросети «ДипСик». Она великолепно справилась даже без поиска по интернету — просто сразу выдала кандидата и на сто процентов попала. Я, по мере ответа, даже начал улыбаться — быстро понял, что попадание верное.

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

Добавлено позднее: рано обрадовался. В остальном не повезло — не нашлись ни фильмы, ни книга.

6 комментариев

Ближе носа

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

Если вам не лениво, напишите в комментариях здесь или в канале «Телеграма» — можете ли вы заметить свой нос и, если да, то что вам надо для этого сделать — глаза скосить или просто сосредоточиться на нём? Или не видите вовсе, что ни делай?

Вид на Большого Сфинкса в Гизе: каменная статуя с головой человека и телом льва на фоне пустынного ландшафта и группы туристов.
Большой сфинкс уже давно не видит свой нос (фото — июнь 2024 года)

13 комментариев

Ведение сайта

Читатели как-то меня спрашивали сколько времени я трачу на ведение этого сайта и когда я пишу.

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

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

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

В общем, сайт — одна из самых малых моих активностей, но на большее нет времени и мотивации.

1 комментарий

Throttling game

В полку́ странных игр прибыло! Помните я писал игру, где надо управлять человечком, подключая и отключая зарядку «Макбука»? Вчера вечером написал небольшую игру из той же оперы.

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

Чтобы поиграть в эту игру, надо открыть рядом «Монитор ресурсов» и вывести график загрузки процессоров. Частоту обновления («Вид» → «Частота обновления») надо поставить «Очень часто».

После этого можно запустить игру и, управляя загрузкой процессора через клавишу «Касплок» («капс» включен — процессор загружен), держать загрузку между 10 и 90%. После старта у вас будет четыре секунды, чтобы подготовиться, вывести все нужные окна на передний план и нащупать кнопку.

Скриншот терминала: процессы Opera Helper, watchdogd. ЦП: 4,41% система, 3,94% пользователь, свободно 91,65%. Потоки 3791, процессы 766. График загрузки ЦП.

На идею меня навела бессмертная игра «Посадка на Луну» для калькулятора «Электроника МК-61» и код, который я делал когда-то для одного из старых проектов — у меня была идея выводить пульсацию проигрываемой мелодии в «Мониторинг ресурсов», рисуя её в окошках загрузки ядер процессора. Тогда у меня был «Макбук» с четырьмя ядрами и для каждого «Мониторинг» выводил своё окошко.

Из-за инерции, с которой рисуется загрузка процессоров, сделать это не удалось, а код лежал в архиве до вчерашнего вечера.

Код игрушки лежит в моём репозитории.

2 комментария

DeepSeek R1

Хочу поделиться. Погоняли китайскую нейросеть «ДипСик Эр1» на оборудовании «Селектела», за что ребятам, как всегда, большое спасибо. Это, конечно, чудо, что на относительно скромном оборудовании можно себе развернуть полноценную большую языковую модель.

Скриншот вывода nvidia-smi: две GPU NVIDIA A100 80GB PCIe, драйвер 570.86.15, CUDA 12.8; процесс llama-cli использует ~80 ГБ памяти на каждой GPU.

На двух nVidia A100 40 GB модель как-то ползает (мы брали квантизованную Q2_K_XL). Можно общаться, но не слишком комфортно. А вот на двух карточках по 80 гигабайт в однопользовательском режиме работает уже просто отлично. В память лезет чуть больше половины всех слоёв, больше всего грузятся ядра центрального процессора (у нас там 24 ядра на 2,4 ГГц), но общаться вполне комфортно — скорость порядка 170 токенов в минуту.

Завтра попробуем замерить сколько человек может работать с такой моделью параллельно. Но даже уже в этой конфигурации можно проверять какие-то гипотезы. Удивительно насколько доступными стали топовые языковые модели!

5 комментариев

Ускорение операций в bc

Как вы помните, я недавно устроил себе суточный хакатон, писал «Дум» на bc. Получился он тогда довольно медленным, особенно когда на экране было много объектов. Сейчас я его потихоньку оптимизирую, но так как профилирования в bc не существует, двигаюсь наугад.

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

В стандартной библиотеке bc есть много функций, написанных нативно. Их, как правило, удаётся так или иначе ускорить, поэтому я решил посмотреть что у меня из такого ещё используется. Взор пал на функцию band(), особенно в форме (band(a, b) && 1), то есть там, где всё, что меня интересует — установлен бит или нет. У меня в коде было несколько таких мест.

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

define check_bit(x, y) {
    auto result, m[]
    result = 0
    scale = 0

    while (x && y) {
        x = divmod(x, 2, m[])
        if (m[0]) {
            y = divmod(y, 2, m[])
            result += m[0]
        } else {
            y /= 2
        }
    }
    return result
}

Получилось быстрее почти в два с половиной раза. Саму операцию band() тоже удалось ускорить в 1,7 раза, в «чистом» виде она у меня в коде тоже есть. Думаю, может сделать коммит в код bc?

Добавлено: коммит сделал. Но беда — автор bc в примечании к репозиторию на «Гитхабе» написал, что с «Гитхаба» он ушёл. К сожалению, то место, куда он ушёл не работает. Так что коммит пришлось залить на «Гитхаб», больше-то некуда.

4 комментария

Тыканье

Мне казалось я об этом уже писал, но поискал и не смог найти, возможно ложная память.

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

Вместо «нажимаем», «читаем тут», «выбираем вот это» они людям, с которыми это неприемлемо, говорят «нажимаешь», «читаешь тут», «выбираешь вот это».

Думаю, авторам такого «тыкания» кажется, что это деперсонализированная речь и они так говорят, держа в голове некого пользователя, которым они как будто бы руководят. Но слушатели, уверяю, воспринимают это совершенно иначе — на свой счёт.

Если вы так делаете, подумайте — уместно ли это.

Оставить комментарий

Ненормальное программирование ★

Введение

Недавно разговорился с одним приятелем, тема разговора как-то мало-помалу сместилась в программирование. Оказалось, он давно читает мой блог и удивляется почему я, по его словам, «в последнее время увлёкся совершенно непрактичным программированием».

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

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

«Junix» (1999—2003)

Это самый старый из сохранившихся подобных проектов. И, наверное, самый монументальный. Дело было в конце 90-х, тогда ДжаваСкрипт мало кто воспринимал всерьёз. В основном его использовали для какого-нибудь простенького интерактива или, максимум, относительно несложных игр, типа «Тетриса».

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

Так у меня получилось что-то вроде эмулятора командной строки «Линукса». Это был первый такой проект в мире и о нём написали все топовые интернетные издания того времени. Я реализовал интерпретатор, похожий на tcsh, несколько утилит и аналог терминала с доступом к файловой системе.

Терминал JUnix v5.52b: вывод команд df (разделы Unix, Storage,1, Cookie,0), ls / (bin/, tmp/, dev/, usr/, etc/), cat /dev/local/storage (Storage,1) и ll /bin.

«JS-FTPd» (2001)

В то время, когда я делал этот проект, ДжаваСкрипт ещё не был монополистом в мире браузерных языков. Существовало несколько альтернативных технологий, так, например, в браузерах была технология «апплетов», позволявших писать небольшие встраиваемые в браузер приложения на языке Джава.

В то же время в браузере «Нетскейп» была нестандартная технология «LiveConnect», которая позволяла вызывать Джаву из ДжаваСкрипта, а так же запрашивать из браузера различные разрешения, например, на сетевое взаимодействие. Впервые я познакомился с этой технологией, когда писал «Junix», там я через неё работал с диском компьютера, а в этом проекте мне захотелось изучить работу с сокетами.

Используя «LiveConnect» я написал FTP-сервер — на ДжаваСкрипте, вызывая Джаву там, где ДжаваСкрипт что-то не умел. Заодно детально разобрался как устроен протокол FTP, что потом часто пригождалось.

Интерфейс JavaScript FTPD от Евгения Степанищева (2001, Казань) с логотипом Netscape, кнопками Start/Stop и инструкцией «Press "Start" to start server».

«Крестики-нолики» на HTML и CSS (2011)

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

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

Игра в крестики-нолики: три нолика в правом столбике выигрывают партию, красная линия показывает выигрышную комбинацию, под полем кнопка Restart.

«Арканоид» на bash (2011)

В рамках этой игры я хотел испытать две концепции.

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

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

Скриншот игры Space Invaders: красная пушка внизу, ряды зелёных, синих и розовых пришельцев, счёт 25, три жизни, URL bolknote.ru © 2011.

«Шахматы» на языке утилиты sed (2013)

Когда я решил написать шахматы на sed, знакомые, с которыми я поделился своей идеей, подумали, что я сошёл с ума. Ну а как иначе? sed — в их глазах не язык программирования, а текстовый редактор, который умеет менять «кота» на «собаку» в конфигах.

Но мне хотелось доказать, что даже в таком примитиве можно выжать больше, чем кажется. В итоге я провёл две недели в диалоге с регулярными выражениями: заставлял их считать, сравнивать числа в придуманном мной формате 111::11 (так в нём записывается число 302) и имитировать логику шахматного ИИ. Каждый день я порывался бросить: когда код превращался в лабиринт из меток и переходов, а функция вычитания занимала 59 строк, но упрямство перевешивало.

Как я уже сказал, большая часть логики сделана на регулярных выражениях, поверх которых я написал мета-язык, на котором уже и писал шахматы, благо в sed есть способ переиспользования кода. Было очень тяжело, но мне так нравилась идея, что я справился. Это был настолько сложный проект, что его выпуск породил волну публикаций по всему интернету. Информационный гул заметили даже «Гугле» и пригласили на собеседование, но я отказался.

Шахматная позиция: белые — король a1, ладьи d1, h1, пешки b2, f2, g4, g6; чёрные — король g8, ферзь b7, ладья a4, слон c5, пешки b4, b5, d4, f7, g7. Надпись: «Введите команду».

«Тетрис» на языке AppleScript (2017)

Встроенный в «МакОс» язык автоматизации «ЭплСкрипт», кажется, никто никогда для написания игр использовать и не пытался. По крайней мере, я таких попыток не обнаружил. И немудрено — сходу неясно чем бы он мог таким оперировать, чтобы взаимодействовать с пользователем.

Я написал «Тетрис» на нём, когда понял, что графику можно выводить, манипулируя свёрнутыми в точку окнами приложений и опрашивая клавиши регулирования громкости.

На снежном стекле нарисованы чёрными точками контур дома и несколько снежинок, на заднем плане видны ели.

«Морской бой» на клавише «Капслок» (2020)

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

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

В итоге я написал игру, где всё взаимодействие с компьютером делается через азбуку Морзе — пользуясь одной клавишей, как ключом, мы вводим координаты для игры в «Морской бой», а ответы компьютера считываем через мигание светодиода на «Капслоке». Картинка ниже — это отладочный режим, его можно включить, но по-умолчанию на экран ничего не выводится.

Таблица с эмодзи волн, взрывов и черепов, расположенных по строкам 01–10 и столбцам А–К на чёрном фоне.

«Вампус» для наручных часов в корпусе «Касио» (2024)

Я вообще очень люблю различные ретро-устройства, а так же всё, что их напоминает — постоянно читаю о ретро-консолях, подписан на каналы, где обозревают интересные устройства прошлого, и когда узнал про «The Sensor Watch», небольшую плату, превращающую классические «Касио» в программируемое устройство, влюбился в эту концепцию и добыл себе всё необходимое.

До сих пор ношу эти часы почти каждый день, они у меня сейчас самые любимые.

Но если уж я добыл себе эти часы, было бы логично что-то под них запрограммировать. Вся сложность была в том, что экран устройства остался от обычных часов «Касио», надо было хорошенько постараться, чтобы что-то на нём вывести. Я какое-то время ломал голову, а потом запрограммировал классическую игру 1972 года «Охота на Вампуса». В её поздний клон я когда-то играл в детстве.

Схема эмулятора часов Casio F-91W для игры Wumpus Hunt: экран показывает ID приложения, номер комнаты, действие и опасности (W — Вомпус, Bt — Летучая мышь, Pt — Ловушка).

«Вампус» на командах командной строки (2024)

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

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

Скриншот текстовой игры: список команд (LS, CD, RM, EXIT), вывод «I SMELL A WUMPUS, BATS NEARBY», команда «rm 12 3 2 3 4» и сообщение «AHA! YOU GOT THE WUMPUS!

«PowerShoot» игра, управляемая подключением зарядки (2024)

Игра, написанная под влиянием болезни. Я довольно тяжело болел и хотелось развлечь себя какой-нибудь прикольной идеей.

На искомую идею меня натолкнул звук, который раздаётся, когда «Макбук» подключается к зарядке. Я задумался, что можно же программно узнать — заряжается ноутбук или нет, а потом уже, от скуки, развил эту мысль до небольшой игрушки. В ней игрок выпускает в сторону врагов бомбу, когда ноутбук подключается к зарядке.

Мужчина идёт мимо двух фиолетовых инопланетных существ, справа — красный прямоугольник с цифрой 12.

«Дум» на языке калькулятора bc (2025)

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

Во мне идея сделать что-то графическое в терминале зрела много лет и, когда я стал изучать язык утилиты bc, мне пришла в голову идея суточного хакатона — сделать на этом совершенно непригодном для написания игр языке, первую игру, да не простую, а трёхмерную, с выводом графики в консоль.

Хотя первые несколько часов хакатона я был в отчаянии от своей идеи и мне казалось, что я либо ничего не сделаю, либо не уложусь в срок, у меня всё получилось — за сутки я сделал порт игры «Wolf5k» на bc и придумал как на этом языке генерировать графику. А заодно доказал, что кодить сутки с раннего утра и до трёх ночи можно и в 47 лет.

Скриншот игры: пиксельный персонаж стреляет из оружия по белым блокам на чёрном фоне; внизу видны числа 150 и 5.

«Throttling» игра, использующая для отображения мониторинг загрузки процессора (2025)

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

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

Три серых блока на чёрном фоне: «Start» с красным и двумя зелёными кругами, «Process» с секундомером и числом 000048, «Lost» со взрывом и числом 000064.

Заключение

Я отобрал всего несколько проектов из того «ненормального», что я делал. Надеюсь, вполне очевидно, что «ненормальное» программирование я ценю и люблю очень давно. Для меня это не просто странное баловство, а способ изучить какие-то привлекательные идеи и выразить свои чувства по отношению к ним.

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

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

3 комментария

← сюда туда →