Forum bat: Форум — Всё о The Bat!

Пишем тетрис в bat-файле / Хабр

В комментарии к моей предыдущей статье, «Какие задачи не решаются bat-файлами?», предположили, что на bat-файлах не получится написать Doom. Насчет Дума я пока не уверен, а вот тетрис у меня получился.

Сразу оговоримся, что код, который мы будем разбирать – это proof of concept. Он имеет недоработки, но я намеренно оставил его таким, чтобы не усложнять.

Bat-файл выложен на Яндекс-диск: ссылка

Upd. На Яндекс-диске превышен лимит скачивания. Вот тот же файл на Google Drive

Геймплей

Ввод с клавиатуры

В играх определенных жанров есть необходимость проверять, какие клавиши нажаты в данный момент, и при этом не останавливаться в ожидании нажатия. В С++ это делается всего одним вызовом GetKeyboardState(). В пошаговых играх и в играх типа тетриса может пригодиться посимвольный ввод, т.е. ожидание ввода одного символа без ожидания нажатия на Enter. В C++ это тоже один вызов – _getch(). Поэтому обидно, что в bat-файле ничего подобного сделать нельзя.

Но у нас есть choice.exe. Эта утилита ожидает ввода одного из перечисленных символов и выставляет errorlevel, равный порядковому номеру выбранного варианта. Допускаются только буквы и цифры. Есть опция таймаута. При этом требуется указать вариант по умолчанию, который выбирается по истечении таймаута.

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

choice /C "sawd" /D s /T 1 > NUL

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

И тут возникает ограничение на скорость игры. Таймаут указывается как целое количество секунд. То есть, минимальный таймаут – одна секунда. Значение 0 допустимо, но в этом случае всегда возвращается вариант по умолчанию, и никакого ввода не получается.

Кроме того, таймаут отсчитывается от запуска choice.exe. Иными словами, от предыдущего ввода, так как у нас эта команда будет в бесконечном цикле. Таким образом, если постоянно нажимать вправо-влево, то фигура вообще перестает двигаться вниз. Это первый недостаток моей реализации игры.

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

В bat-файлах нет массивов. Однако, можно использовать переменные с именами, содержащими индексы. Таким образом организуются псевдо-массивы. В нашем случае это двумерный массив field_%Y%_%X%. Y меняется от 0 до 15, причем, 0 – это верх. X – от 0 до 7. Элементы равняются либо 0 – блок свободен; либо 1 – блок занят.

Перед началом игры поле инициализируется нулями:

for /L %%a in (0,1,15) do (
  for /L %%b in (0,1,7) do set field_%%a_%%b=0
)

Рендеринг игрового поля

Псевдографика позволит изобразить по две строки поля в одной строке текста. Половина ячейки символа – один блок. Так блоки получаются более-менее квадратными. Символ с кодом 223 представляет собой закрашенную верхнюю половину ячейки, 220 – нижнюю, а 219 – полностью закрашенная ячейка.

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

Напомню, что bat-файл надо сохранять в кодировке 866. Кодировку можно изменить командой chcp, но нам это не понадобится.

Когда обе половины ячейки свободны, нужно вывести пробел. Это значит, в скрипте будет строка, оканчивающаяся пробелом. Его не видно, а он есть, и есть риск его удалить при редактировании. В кавычки его ставить нельзя. Если с командами SET и ECHO использовать кавычки, они попадают, соответственно, в переменную и на экран.

Перемещение курсора

Чтобы обновить весь экран, есть вариант его очистить командой CLS, а потом вывести всё содержимое. Но в нашем случае рендеринг идет дольше смены кадров, и изображение мигает, если очищать экран. Поэтому нужно переместить курсор в точку (1;1) и вывести новое поле поверх старого.

Для перемещения курсора нам понадобится код ANSI-терминала <ESC>[1;1H. <ESC> – это символ с кодом 27 (033 или 0x1B). Его, как и псевдографику, можно вставлять в команды как есть. Главное – найти текстовый редактор, который позволит это делать. Notepad++ подойдет. Спасибо @horror_x за подсказку.

Алгоритмы

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

Выбор фигуры

В таблице ниже представлены все фигуры тетриса

Все фигуры

Случайным образом (через переменную %RANDOM%) выбираются значения переменных figtype (от 0 до 3) и figflip (0 или 1). Для figtype от 0 до 2 изменение figflip – это зеркальное отражение относительно вертикальной оси. Фигуры с figtype 3 симметричны относительно обеих осей, поэтому для этого случая figflip выбирает саму фигуру. Это позволяет не кодировать явно все 8 фигур. Достаточно пяти. Фигуры с figtype<3 и figflip=1 получаются отражением.

Представление фигур

Функция :getfigure заполняет переменные figdefx и figdefy. В каждой из них 4 цифры. Каждая цифра – координата. figdefx – это X-координаты, а figdefy – Y. Таким образом закодированы положения 4 блоков, из которых состоит фигура. Эти переменные не меняются при повороте фигуры по ходу игры, и figflip их тоже не меняет. Вместо этого координаты преобразуются при помощи матрицы поворота и отражения.

Матричная алгебра

:getfigure инициализирует матрицу либо единичной матрицей, либо матрицей отражения в зависимости от figflip. Матрица хранится в 4 переменных: mat11, mat12, mat21 и mat22.

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

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

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

Применение фигуры

Функция :applyfigure принимает 3 параметра: колбэк и координаты. Функция рассчитывает координаты каждого блока фигуры с учетом указанного смещения и матрицы и вызывает колбэк, передавая ему эти координаты.

Используются следующие колбэки:

  • :setblock заполняет блок, т.е. присваивает значение 1 элементу псевдо-массива field_%2_%1. Таким образом, фигура рисуется на поле;

  • :clearblock очищает блок. Фигура стирается с поля;

  • :testcollision возвращает errorlevel 1 если указанный блок заполнен или находится за границами поля. Коллизия с верхним краем тоже проверяется. Она может произойти при повороте фигуры.

Если колбэк возвращает errorlevel 1, :applyfigure прерывает выполнение и тоже возвращает 1.

Жизненный цикл фигуры

На метке :nextfigure после выбора очередной фигуры эта фигура рисуется на поле в точке (3; 0). Если при этом возникает коллизия, игра заканчивается. Как вы помните, координаты блоков в определении фигуры неотрицательны, а флаг figflip отражает фигуру относительно вертикальной оси. Таким образом, коллизия с верхним краем исключена. Коллизии с правым и левым краем тоже исключены, потому что нет таких широких фигур. Таким образом, коллизия может быть только с ландшафтом.

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

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

За удаление заполненных рядов отвечает функция :removefulllines. Надеюсь, там ничего сложного.

Заключение

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

На этом примере мы показали использование команды choice для ввода с таймаутом, псевдографику и коды ANSI-терминала.

Мы продемонстрировали практическое использование псевдо-массивов, колбэков и базовых алгоритмов.

Специальная авиационная служба — Индекс

Ангар SAS

Объявления

Правила и объявления форума SAS

459 сообщений
9 тем
Последнее сообщение от SAS~CirX
в Re: Пожертвование SAS
30 октября 2022 г., 22:32:18
Гостиная

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

123105 сообщений
10436 тем
Последнее сообщение от KingTiger503
в Re: КЦ Скриншоты и Ви…
к Сегодня в 10:32:58
Дочерние доски : Фильмы и скриншоты, Доска не на английском языке, Запросы и идеи, Новый симулятор полета, Plastix, SAS Dogfight Server, Linx
Зона безопасности для новых участников

Изучите основы форума, игры и задайте потенциальные вопросы «новичка»

Модератор: SAS~tsisqua

13481 сообщений
2178 тем
Последнее сообщение от Cybersnow46
в Re: HOTAS продолжает падать
10 ноября 2022 г. , 14:41:19

Battlefield — Airborne — Tactical (BAT)

Отдельные модификации и наборы для Ил-2 1946 г.

SAS Essentials / Базовые модификации

Кнопки SAS, базовые модактиваторы, общие улучшения и стандартные исправления

3123 сообщений
26 тем
Последнее сообщение от Frankiek
в Re: UltraSpain 2019
07 октября 2022 г., 17:30:37
Детские доски : Модакт SAS
Самолет
64475 сообщений
1176 тем
Последнее сообщение от Dandolo513
в Re: Kyushu Q1W1 Tokai …
на Сегодня в 05:51:30
Дочерние доски : Самолеты, Близнецы, Тяжелые, Гидросамолеты, Немецкие_Одиночные, Япония_Одиночные, Великобритания_Одиночные, США_Одиночные, СССР_Одиночные, Итальянские_Одиночные, Польские/Чешские_Одиночные, Французские/Испанские_Одиночные, Другие_Одиночные, Вертолеты/Дирижабли, Ангар 9 Первой мировой войны, Франкенштейн
скинов, карт, миссий и кампаний
71413 Сообщений
6774 Тем
Последнее сообщение от oldschoolie
в Re: A6M2 Type 0’Saburo S. ..
на Сегодня в 11:36:49
Дочерние доски : Skinshop, Skin&Markings, Templates, SkinRequests, German Skins, Italian Skins, French, Polish & Czech Skins, USA Skins, USA Skins, UK Skins, Japanese Skins, WWI Skins, MapWorx (Common), ETO Карты, карты PTO, карты MTO, карты WWI, текстуры карт, карты WIP, миссии (общие), обсуждения миссий и запросы, кампании, MissionPro, кампании и миссии WW1
Другие моды

Все, что не подходит под категории выше

72940 Сообщений
2004 Темы
Последнее сообщение от Dandolo513
в Kyushu Nankai Q3W1 и S…
на Сегодня в 12:19:54
Дочерние доски : WIP, SlotRequest, FM Discussions, Cockpits (Common), Cockpits (New Flyables), Cockpits (ReSkins), Sounds (Common), Sounds (Speech), Sounds (Motors), Sounds (Arms) , Звуки (FX), Корабли, Транспорт + Артиллерия, Визуальные моды, 3Dfix, Эффекты, Наборы оружия, Stereo3D, ModWorx
Ultrapack Обсуждение и поддержка

Уродливая младшая сестра BAT, созданная специально для сетевой игры

5092 Сообщений
536 Тем
Последнее сообщение от KingTiger503
в Re: Отчет об ошибке Ultrapack. ..
на Сегодня в 10:42:15
Дочерние доски : Загрузки и обновления Ultrapack
4.09 База повстанцев

4.09 Только связанные вещи. Да пребудет с вами сила 4.09.

2390 сообщений
156 тем
Последнее сообщение от Epervier
в Re: Breda Ba.65 — DH-89 …
11 ноября 2022 г., 05:14:51

Фабрика SAS — техническая помощь, древние моды и т. д.

Техническая помощь (кроме BAT или IL-2 Great Battles)

Решайте свои проблемы и получайте ответы на вопросы здесь, если они не касаются BAT или IL-2 Great Battles, у которых есть свои собственные доски технической помощи.

18968 Сообщений
2894 Тем
Последнее сообщение от WxTech
в Re: Perfect Landscape Ca…
на Сегодня в 07:02:05
Дочерние доски : Техническая помощь : Использование модов, Техническая помощь : Создание модов
На память: старые пакеты модов, игровые версии и гостевые моды

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

18386 Сообщений
1852 Тем
Последнее сообщение от Sergent Pepper
в Re: VP Modpack 1. 2 Beta
от 30 октября 2022 г., 07:20:23
Дочерние доски : Обсуждение и поддержка Dark Blue World, Универсальный патч сообщества (C.U.P.), Обсуждение и поддержка HSFX, VP Modpack, Cliffs of Dover, IL-2 Great Battles

Карта сайта.

1999                                      Декабрь
2000     Январь   фев   март   Апрель   Май   Июн   июль   Август   сент.   окт.   ноябрь   Декабрь
2001     Январь   февраль   март   Апрель   Май   Июн   июль   Август   сент.   окт.   ноябрь   Декабрь
2002     Январь   февраль   март   Апрель   Май   Июн   июль   Август   сент.   окт.   ноябрь   Декабрь
2003     Январь   февраль   март   Апрель   Май   Июн   июль   Август   сент.   окт.   ноябрь   Декабрь
2004     Январь   февраль   март   Апрель   Май   Июн   июль   Август   сент.   окт.   ноябрь   Декабрь
2005     Январь   февраль   март   Апрель   Май   Июн   июль   Август   сент.   окт.   ноябрь   Декабрь
2006     Январь   февраль   март   Апрель   Май   Июн   июль   Август   сент.   окт.   ноябрь   Декабрь
2007     Январь   февраль   март   Апрель   Май   Июн   июль   Август   сент.   окт.   ноябрь   Декабрь
2008     Январь   февраль   март   Апрель   Май   Июн   июль   Август   сент.   окт.   ноябрь   Декабрь
2009     Январь   февраль   март   Апрель   Май   Июн   июль   Август   сент.   окт.   ноябрь   Декабрь
2010     Январь   февраль   март   Апрель   Май   Июн   июль   Август   сент.   окт.   ноябрь   Декабрь
2011     Январь   февраль   март   Апрель   Май   Июн   июль   Август   сент.   окт.   ноябрь   Декабрь
2012     Январь   февраль   март   Апрель   Май   Июн   июль   Август   сент.   окт.   ноябрь   Декабрь
2013     Январь   февраль   март   Апрель   Май   Июн   июль   Август   сент.   окт.   ноябрь   Декабрь
2014     Январь   февраль   март   Апрель   Май   Июн   июль   Август   сент.   окт.   ноябрь   Декабрь
2015     Январь   февраль   март   Апрель   Май   Июн   июль   Август   сент.   окт.   ноябрь   Декабрь
2016     Январь   февраль   март   Апрель   Май   Июн   июль   Август   сент.   окт.      Декабрь
2017     Январь   фев   март   Апрель   Май   Июн   июль   Август   сент.      ноябрь   Декабрь
2018     Январь   9 февраля0311   март   Апрель   Май   Июн   июль   Август   сент.      ноябрь   Декабрь
2019     Январь   фев.   март   Апрель   Май   Июн   июль   Август   сент.   окт.      Декабрь
2020     Январь   Февраль   март   Апрель   Май   Июн   июль   Август   сент.   окт.   ноябрь   Декабрь
2021     Январь   Февраль   март   Апрель   Май   Июн   июль   Август   сент.

Imacros | Все права защищены © 2021