Пользователь
0,0
рейтинг
14 июня 2009 в 18:52

Разработка → Мандельброт на .bat «for fun»

Вот эта картинка создана .bat файлом:



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

Например, как сделать паузу на заданное количество секунд? Команда pause тут бессильна. В место неё паузу удобно организовать через ping.
Пауза на 5 секунд будет выглядеть вот так:
ping 127.0.0.1 -n 6 -w 1000 > nul

Вот как узнать, содержит ли строка подстроку? Опять же, на первый взгляд ничего подходящего нет. На помощь приходит замена подстроки в строке:
set string=SOME TEXT
if not "%string%"=="%string:TEXT=%" echo YES

Ещё на .bat можно организовать вычисления с плавающей точкой (изначально плавающая точка не поддерживается), распараллеленные вычисления, синхронизацию между «процессами», распараллеленное вычисление на нескольких компьютерах и т.п. Я как-то раз видел исходники полиморфного(!) вируса, который полностью написан на bat-файле :)

В общем, время от времени я пишу что-нибудь на .bat, не могу пройти мимо такого вызова :)
Cейчас выкладываю одну из своих работ: батник, который рендерит множество Мандельброта в bmp.

@echo off
set /a xPixels = 180
set /a yPixels = 120
set /a xStart = -22000
set /a yStart = -10000
set /a xSize = 32000
set /a ySize = 20000
set /a maxIter = 32
call ::make_bmp_header
 
set /a xStep = xSize/xPixels
set /a yStep = ySize/yPixels
 
set /a iy = 0
:iyLoop
 
  set /a ix = 0
  :ixLoop
 
    set /a x = xStart + ix * xStep
    set /a y = yStart + iy * yStep
    set /a x0 = x
    set /a y0 = y
 
    set /a iteration = 0
   
    :formula
      set /a xtemp = x*x/10000 - y*y/10000 + x0
      set /a y = 2*x*y/10000 + y0
      set /a x = xtemp
      set /a iteration+=1
 
      set /a dist = x*x/10000 + y*y/10000
      if [%iteration%]==[%maxIter%] goto breakFormula
    if /I %dist% LEQ 40000 goto :formula
    :breakFormula
   
    if [%iteration%]==[%maxIter%] (call :plot_black) else (call :plot_color %iteration%)
 
  set /a ix += 1
  if not [%ix%]==[%xPixels%] goto ixLoop
 
  set /a progress = yPixels - iy
  echo.%progress%
 
set /a iy += 1
if not [%iy%]==[%yPixels%] goto iyLoop
 
call ::make_bin
ren file$ result.bmp
mspaint result.bmp
exit/b
 
 
:plot_black
call :write_byte 0
call :write_byte 0
call :write_byte 0
exit/b
 
:plot_color
set /a rc=%1*5 + 32
set /a gc=%1*7 + 6
set /a bc=128 - (%1*3 + 4)
call :write_byte %rc%
call :write_byte %gc%
call :write_byte %bc%
exit/b
 
 
:make_bmp_header

set /a dataSize = xPixels * yPixels * 3 + 54
set /a dataSize0 = dataSize%%256
set /a dataSize1 = (dataSize/256)%%256
set /a dataSize2 = (dataSize/(256*256))%%256
set /a dataSize3 = (dataSize/(256*256*256))%%256
 
call :init_bin
 
call :write_byte 66
call :write_byte 77
 
call :write_byte 118
call :write_byte 56
call :write_byte 0
call :write_byte 0
call :write_byte 0
call :write_byte 0
call :write_byte 0
call :write_byte 0
call :write_byte 54
call :write_byte 0
call :write_byte 0
call :write_byte 0
call :write_byte 40
call :write_byte 0
call :write_byte 0
call :write_byte 0
call :write_byte %xPixels%
call :write_byte 0
call :write_byte 0
call :write_byte 0
call :write_byte %yPixels%
call :write_byte 0
call :write_byte 0
call :write_byte 0
call :write_byte 1
call :write_byte 0
call :write_byte 24
call :write_byte 0
call :write_byte 0
call :write_byte 0
call :write_byte 0
call :write_byte 0
call :write_byte %dataSize0%
call :write_byte %dataSize1%
call :write_byte %dataSize2%
call :write_byte %dataSize3%
call :write_byte 0
call :write_byte 0
call :write_byte 0
call :write_byte 0
call :write_byte 0
call :write_byte 0
call :write_byte 0
call :write_byte 0
call :write_byte 0
call :write_byte 0
call :write_byte 0
call :write_byte 0
call :write_byte 0
call :write_byte 0
call :write_byte 0
call :write_byte 0
 
exit /b
 
 
:init_bin
echo.n file$>bin$
set /a addr=0x0100
call set "hstr=e "
call :write_word %addr%
set mustflush=0
exit /b
 
:write_byte
set /a a=%1
set hexs=0123456789ABCDEF
set /a a0=a/16
set /a a1=a%%16
call set res= %%hexs:~%a0%,1%%%%hexs:~%a1%,1%%
set hstr=%hstr%%res%
set /a addr+=1
set /a mod16=addr%%16
set mustflush=1
if not %mod16%==0 exit /b
echo.%hstr%>>bin$
call set "hstr=e "
call :write_word %addr%
set mustflush=0
exit /b
 
:write_word
set /a a=%1
set hexs=0123456789ABCDEF
set /a a0=a/4096
set /a a1=a/256%%16
set /a a2=a/16%%16
set /a a3=a%%16
call set res=%%hexs:~%a0%,1%%%%hexs:~%a1%,1%%%%hexs:~%a2%,1%%%%hexs:~%a3%,1%%
set hstr=%hstr%%res%
exit /b
 
:make_bin
if "%mustflush%"=="1" echo.%hstr%>>bin$
set /a filesz=addr-0x0100
echo.r cx>>bin$
set hstr=
call :write_word %filesz%
echo %hstr%>>bin$
echo.w>>bin$
echo.q>>bin$
debug<bin$
del bin$
exit /b

Алексей Борисов @Imp5
карма
135,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (102)

  • +19
    Например, как сделать паузу на заданное количество секунд? Команда pause тут бессильна. В место неё паузу удобно организовать через ping.
    Пауза на 5 секунд будет выглядеть вот так:
    ping 127.0.0.1 -n 6 -w 1000 > nul

    Вот как узнать, содержит ли строка подстроку? Опять же, на первый взгляд ничего подходящего нет. На помощь приходит замена подстроки в строке:
    set string=SOME TEXT
    if not "%string%"=="%string:TEXT=%" echo YES


    да уж… прям через одно место это делается… но радует что есть люди которые умеют выйти из ситуации :)
    • +5
      Особенно интересно делается интерактивность =)
      Когда делал игру «сокобан», приходилось учитывать разные версии командной строки.
      • +3
        переходите на bash :)
        • +8
          а там нужно трудности преодолевать? =)
          • +25
            трудности — да, но не через одно место :)
        • 0
          сам по себе он не столько рулит (хотя конечно несравним с cmd), а вот вместе со стандартным набором консольных утилит… sed+awk это уже очень много.
          • 0
            sed, awk, grep, find… Этот список можно долго продолжать :)
    • 0
      таких людей зовут програмисты!=)
      • +1
        программисты
  • +32
    Код сходу непонятен, но чувствую, что круто! +
    • НЛО прилетело и опубликовало эту надпись здесь
  • +1
    Больше всего понравилось: текст habracut`a
    (=
    • +61
      Я что-то писал?
  • 0
    Гениально!!!
  • +14
    плюс вам, тов. Маньяк
  • +1
    Вы это сами всё? Тогда вы большой молодец. Плюс вам.
    • +3
      сам =)
      но время от времени заглядывал на разные сайты с tips and tricks
      например, malektips.com/windows_xp_and_dos_help_and_tips.html
      • 0
        Спасибо за ссылку. Очень познавательно
  • +2
    Черепашка тож много чего нарисовать может…
    • НЛО прилетело и опубликовало эту надпись здесь
      • 0
        «logo — это lisp без скобок», прочитал я в ZX-Review.
    • 0
      я еще и крестиком вышивать умею!
  • +1
    Это, конечно, не тетрис на sed, но всё равно круто.
    Никогда бы не подумал, что это возможно в принципе.
  • +12
    >паузу удобно организовать через ping

    Майкросовский подход :)
  • +24
    Мсье знает толк в извращениях…
  • +1
    я программировать начал с bat в досе на 286 в 96 году)) правда недолго) что-то делал интерактивное, но что б такое… я поражен. правда, похоже, за это время функциональность командного процессора несколько возросла.
    • +1
      а еще из извращений вспоминаются конфиги с навороченной логикой (менюшки там всякие, арт) для Quake 1 и 2 с их bind'ами и alias'ами :)
      • +2
        Ну не такие уж это и извращения. Часто батники как раз использовали для подобных вещей. Чтобы сделать некое подобие «интерфейса для секретарши».
  • 0
    А как такой код дебажить? Отладочными принтами, или есть возможность сделать это поудобнее?
    И как юзать плавающую точку?
    Да, это пожалуй самое оригинальное извращение из всех о которых я слышал =)
    • +2
      >А как такой код дебажить? Отладочными принтами, или есть возможность сделать это поудобнее?
      Да, отладочными echo.
      А ещё, если не делать @echo off, то можно видеть какие команды исполняются и с какими параметрами. Для удобства, этот вывод можно перенаправить в файл для дальнейшего изучения.

      >И как юзать плавающую точку?
      Надо написать функции для работы с плавающей точкой =)
      В этой програме я использовал фиксированную точку, 4 десятичных разряда для дробной части.
  • +1
    Когда программистам делать нечего :)
  • +4
    А вы не директор по ведущим разработкам Мелкософта? =)
  • +2
    мандельброт в 61 байт:
    tinyurl.com/llkbsd
    • НЛО прилетело и опубликовало эту надпись здесь
  • +2
    Я как-то раз видел исходники полиморфного(!) вируса, который полностью написан на bat-файле

    Это не новость для посвящённых. В славные 90-е вирмейкеры куда больше изощрялись, чем сейчас. :)
    Интересующиеся могут полистать старые e-zines вирсцены.
    • +2
      Из российских я там заметил Chaos AD, Infected Voice, MoonBug.
      • +2
        О да! Infected Voice — помню, помню =)
        • 0
          еще Infected Moscow помню был один выпуск, а второго вроде бы так и не дождались…
          во были времена, когда натыкался на эти выпуски, приятно вспомнить.
  • 0
    О да! Infected Voice — помню, помню =)
    • +3
      Не туда ответил %|
  • +2
    С gamedev.ru

    Растеризация треугольника в консоли:
    www.everfall.com/paste/id.php?t5ht4mw6kvls

    Консольный сокобан:
    www.everfall.com/paste/id.php?szlzpnwtsftu
    • +2
      Это один и тот же автор.
    • +5
      «Pasted by Imp5»

      это автор топика видимо запостил)
      • +4
        да, это был я
      • 0
        Хех, вечером по запарке не заметил))
  • 0
    Под дос был криптор исполняемых файлов написанный на .bat Trap авторства Christoph Gabler, последние версии правда уже полностью на asm вроде перевел.
  • 0
    круто у Вас на работе. есть чем заняться ;)
    • +3
      это в свободное время.
      «programming for fun»
  • +17
    Ваша шайтан-программа грузит сеть весьма странным образом %)



    Батник был запущен с сетевой расшарки на другом компе. Временных файлов на расшарке я не увидел :)
    • +3
      кстати графики сетевой активности тоже можно попорбывать батниками рисовать. должно быть даже проще, но не так эффектно, конечно)
      • 0
        )))
    • +1
      Учитывая, что автор интересовался Infected Voice, стоит прогнать машина антивирусом :))
      • 0
        *машину
    • 0
      дык это ж из-за ping-задержки наверное?
      • +1
        компы в пределах одного роутера, второй комп под линуксом. Обычно задержка очень маленькая. Скорее, дело действительно в механизме исполнения батника. Кстати, батник сразу предупредил, что будет использовать не текущий путь (в расшарке), а c:\windows\.
    • 0
      Вообще этот батник создаёт временные файлы в текущей папке.
      Ещё дело может быть в том, как cmd исполняет батники. Он их читает по командам (из-за этого батники можно менять в процессе исполнения)
    • 0
      временный файл создается, проверил (имя bin$)
  • +10
    Леша — ты опять забыл принять лекарство! =))
    • 0
      Изображение в посте напоминает как раз картику, которую психиатр показывает пациенту и спрашивает что вы на ней видите =)
      Мне напоминает повернутые пики или раздутые трефы
      • +1
        Это не картинка психиатра, там просто маленькая ящерка с выпотрошенными кишочками, которую ест ее мама
    • –2
      :)))))!
  • 0
    У меня эта хрень минут 5 гудела, может потому что виртуалка, но вряд ли. Так что батник для таких вещей — не самый лучший выбор))
    • 0
      у меня уже минут 20
      что я делаю не так?
      • +2
        Freeman85 не жалуется, он хвастается =)
        у меня на ноутбуке тоже где-то 20 минут работает.
        • 0
          Может и 20 минут, я как-то не засекал :) Просто говорю, что долго.
        • 0
          у меня работает 8 минут, идут цифры от 120 до нуля, потом выдает ошибку что файл с картинкой не найден, что я делаю не так? 0_о
          Батник в любой папке лежать может?
          • 0
            Батник должен быть в папке, которая свободна для записи.

            Посмотри, чтобы там уже не было result.bmp

            В строках
            set /a xPixels = 180
            set /a yPixels = 120
            замени разрешение на меньшее, например 8 на 8, чтобы не ждать результата долго.

            Есть ли у тебя mspaint.exe?

            Есть ли у тебя команда debug?
            • 0
              команды debug нету
              • 0
                А какая версия Windows?
                • +1
                  Vista SP1 x64
  • +4
    Когда я читаю вот такие стать, как ваша, я вдохновляюсь. Очень приятно читать настоящего хакера.

    Заметьте, ни одного заминусованного коммента к статье.
    • +2
      Ваш минусовать начали :D, поднял обратно до нуля.
      • +1
        Я предвидел — меня это не оскорбляет. Спасибо вам, но право не стоило.
  • 0
    Может кто в курсе, есть ли способ прервать выполнение батника для ввода данных и записи в переменную? Не считая сторонних программ которые записывают введенное значение в errolevel?
    • 0
      rem SETLOCAL ENABLEEXTENSIONS
      set /p var=Как Вас зовут?:
      echo Hello, %var%

      если не заработает, раскомментировать первую строчку
      • 0
        То что надо, спасибо :)
    • 0
      Если вам надо в определённом месте спросить что-то у пользователя, то вариант от kentaskis должен подойти.
      Если это нужно сделать в произвольный момент, то к сожалению, я не знаю простых способов.
  • 0
    Для пауз есть waitfor
    Ждем Doom на cmd скриптах :)
    • 0
      Да, начиная с Vista или 2003, waitfor есть в штатной комплектации.
  • –8
    А был ли мальчик? Короче, устал ждать счастья — убил выполнение. Используйте bash, удаляйте cmd.
    • +2
      Напишите Мандельброт на bash.
  • 0
    А мне вспомнился спектрум, как это не банально. И хоть мое счастливое детство прошло без детища синклера, но позже этот прекрасный компьютер чрезвычайно увлек меня в своем виртуальном (эмулируемом) воплощении. Многое тоже приходилось делать руками, а иногда и особым образом «удалять гланды». Как первому (операции с плавающей точкой, тригонометрия через ряды, умножение с делением, которые Z80 не поддерживал), так и второму (нестандартные видеорежимы, вывод на экран блоками по 8х8, внутри которых можно использовать лишь 2 различных цвета, 3d на такой простенькой машинке) можно было обучиться, читая ZX-прессу, дискмаги и газеты. Среди прочих равных выделялся журнал ZX Format. В нем всегда можно было найти статейку-другую о программировании для speccy. Эх…
    • +2
      … и тут все должны прослезиться?
  • +1
    Такими темпами скоро варкрафт на бат перепишут )))
  • 0
    20 минут и файл размером 180x120px :) Хорошо повеселили
  • 0
    пару секунд и



    Правда в Linux и с помощью специализированной программы Fraqtive.

    С помощью пинга локалхоста задержки делать + (не могу пока).
  • 0
    В универе в курсе Синергетики такие изображения назывались Фракталы. Есть также спец. программы, которые их строят.
  • 0
    Например, как сделать паузу на заданное количество секунд?
    В Windows7, не знаю как в Vista наконецто добавили
  • +1
    Извиняюсь за отрывок, случайно отправил
    Examples:
    TIMEOUT /?
    TIMEOUT /T 10
    TIMEOUT /T 300 /NOBREAK
    TIMEOUT /T -1

    Parameter List:
    /T timeout Specifies the number of seconds to wait.
    Valid range is -1 to 99999 seconds.

    /NOBREAK Ignore key presses and wait specified time.

    /? Displays this help message.

    NOTE: A timeout value of -1 means to wait indefinitely for a key press.
  • 0
    а я уж думал, что щас картинка 20 на 20 тыс. px вылезет…
  • 0
    Теперь осталось написать на .bat-файлах веб-сервер
  • +1
    Люди знают толк в извращениях
  • 0
    класс :)
    вспоминаю молодость :)

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