Comments 41
Для перемещения курсора нам понадобится код ANSI-терминала <ESC>[1;1H. <ESC> – это символ с кодом 27 (033 или 0x1B).
Не сработало на Win7 Eng Pro в cmd.exe. Стакан не перерисовывается. Вместо этого рисуются новые стаканы с этим вот кодом между ними.
В Win10 выходило обновление, добавляющее поддержку ESC ANSI Sequences. Потому в более ранних осях это не работает.
Для получения ESC (а также BACKSPACE) не обязательно печатать спецсимвол напрямую. Можно получить их с помощью разбора prompt, см: https://www.cyberforum.ru/post4375870.html
Не уверен, что в чистом досе и его command.com поддерживаются другие фичи, которые я тут использую
В win10 в этом необходимости уже нет.
for /f %e in ( '"prompt $E & for %e in (1) do rem"' ) do @echo:%e[91m%e[107mbright red on white%e[0m
Для таймаутов <1s можно использовать ping localhost ;)
Посмотрите здесь: https://www.dostips.com/forum/viewtopic.php?f=3&t=6812
Там используются сантисекундные задержки и ввод производится с помощью set /p
и одного хитрого трюка (сам еще не до конца понял его) "%~F0" Input >> pipeFile.txt | "%~F0" Main < pipeFile.txt
.
Я понял, что там у них сделано.
Для ввода используется xcopy /W. Опция /W означает ждать нажатия. При этом введенный символ выводится на stdout, а сообщение "Нажмите..." - на stderr. Важно передать в качестве источника и цели для копирования существующие файлы. Иначе xcopy спросит, файл или каталог указан как цель. В данном случае bat-файл копирует сам себя в себя же. Если вы до сих под четко знали азбучную истину о том, что нельзя копировать файл в себя, забудьте. xcopy так может.
Для задержек используется цикл с проверкой, не достигла ли переменная %TIME% нужного значения. Из этой переменной берутся последние два символа - доли секунды. Перед ними добавляется единица, и действия производятся с числами от 100 до 199. Если единицу не добавлять, будет проблема с тем, что последовательность цифр, начинающаяся с нуля, означает число в 8-ричной системе. Т.е. 08 и 09 - это синтаксическая ошибка.
А трюк для ввода без задержек заключается в том, что set /P в случае, когда ввод перенаправлен от другого процесса, не ждет ввода, как это обычно происходит. Если на вводе что-то есть, оно читается. Если ничего нет, переменная не устанавливается, но выполнение скрипта продолжается без задержек. Запускаются два процесса - %0 Input и %0 Main. Input с помощью xcopy ждет ввода, интерпретирует его и выводит код действия. Main использует set /P.
Я, когда работал над статьей, рассматривал вариант с запуском процесса, который будет убивать choice.exe командой taskkill. Процесс, убитый таким образом, возвращает errorlevel 1. Надо сделать "s", т.е. движение вниз, не только вариантом по умолчанию, но еще и первым в списке и, казалось бы, всё.
Но выяснилось, что много времени уходит на перерисовку поля и, возможно, на что-то еще. taskkill часто выдавал сообщение, что процесс не найден, и фигура опускалась не очень быстро, сколько бы я ни уменьшал задержку. Кроме того, надо как-то учесть, что в системе могут в это же время работать чужие экземпляры choice.exe, которые не надо трогать. Всё это заставило меня выложить статью без этого.
Раз уж всё равно используются внешние программы, то почему бы не попробовать использовать другой интерпретируемый язык, который позволяет сделать меньшие задержки? Например, можно в батник воткнуть кусок кода для powershell, и вызвать сам powershell, передав ему этот же батник (да, хитро можно разделить выполнение), а в powershell есть например start-sleep -m. Можно в цикле проверять нажатие клавиши и возвращать определённый код возврата. Хотя... тогда будет сильно проще и вовсе всё на powershell переписать, там возможностей больше.
> Для ввода используется xcopy /W
Теперь все понятно. Я видел эту команду, но потом забыл о ней и все не мог понять как set /p принимает ввод клавиш без ожидания.
ps: ждём змейку
Вот и змейка: https://www.dostips.com/forum/viewtopic.php?t=4741
"на bat-файлах не получится написать Doom". Легко :)
cd Doom
Doom.exe
Если кому интересно могу кинуть ссылку на свой js тетрис. там же собственно и код. что то порядка 150-200 строк
JS - это в браузере? Или Node JS? Или, может, cscript/wscript?
А тут ещё и на чистом CMD (я лично давно плюнул и стал юзать греп, сторонние парсеры и самописные утилиты, иначе боль).
В wt проблемы с кодировкой
Hidden text

Ещё можно попробовать скрыть курсор - чуть более гладкий вывод получим.
<ESC>[?25l
Отличная статья и реализация Тетриса в BAT-файле, спасибо!
Я бы так вряд ли бы смог. Но от небольшой критики не могу удержаться... :)
Я обычно использую кавычки в SET, чтобы включить или исключить пробелы в переменной.
:: в переменную LINE не попадёт случайный пробел:
set "LINE=║"
:: в переменную LINE попадёт обязательный пробел:
set "LINE=!LINE! "
Дело вкуса, но я бы использовал для выхода из процедур/функций единый стиль: "exit /b [значение]" (вместо "goto :eof" и "exit /b <значение>").
Круто. Не хватает только подсчёта очков (и увеличения уровня влияющего на скорость падения фигур при достижении определённых значений) и отображения где-нибудь сбоку какая фигура выпадет следующей. Думаю это всё несложно реализовать.
Ах да, ещё стакан вроде бы маловат, где-то 2-3 клетки по ширине и столько же по высоте не хватает (или мне кажется?).
А что насчёт цветных фигур, слишком сложно будет это сделать?
Всё это вполне реализуемо. Для цветных фигур надо хранить для каждой клеточки не 0 или 1, а цвет. Чтобы это рендерить, нужно будет вместо того, чтобы выводить разные символы, использовать только один символ с закрашенной половинкой и менять только цвет. Цвет меняется кодами ANSI-терминала. Т.е. тут уже только Windows 10. На семерке ни в каком виде не получится.
Пишем тетрис в bat-файле