Лазая по просторам App Store ища очередную игрушку для своего айпада, наткнулся на старинную игрушку “Братья Пилоты”. Сразу купил, поставил и прошёл на одном дыхании (уже наверное в 3 раз). Но более всего задержался на эпизоде с холодильником. Уж больно меня прёт эта головоломка.
И внезапно вспомнил, что ещё в школьные годы, после прохождения холодильника, головоломка меня так накрыла, что я написал на паскале свою собственную игрушку — эмулятор головоломки. Но не просто повторяла исходную игру, а позволяла выбирать размер поля, имела хелп, возможность сохранения и продолжения игры с прошлого места после выхода.
Подняв старые бекапы я нашёл исходную игру. Запустил её в dosbox и пропал для внешнего мира на пару часов.
Исходная головоломка, обратите внимание на открытый левый столбец и положение вентилей
В чём же суть?
Суть головоломки достаточно проста. Имеется поле вентилей 4 на 4 штуки, необходимо все вентили на холодильнике поставить в горизонтальное положение. “Но есть нюанс”(с): когда вы поворачиваете вентиль, то вместе с ним поворачиваются все вентили в столбце и строке, в которой находится данный вентиль. И тут начинается самое интересное!
Когда я впервые сел за эту головоломку в исходном квесте, играя ещё в школе, то проходил её, наверное минут 40, не меньше. Но она до того мне понравилась, что я играл в неё играл и играл, и играл…
Но хотелось большего: возможность сохранять игровой процесс, генерировать разные уровни и менять размер поля, чтобы понять алгоритм игры.
Тогда я понял, что если мне головоломка нравится, и хочется попробовать разные масштабы игрового поля, то не стоит ждать у моря погоды. Есть только один выход — реализовать эту игру самостоятельно.
Ну’c, приступим!
Я не смогу точно определить дату создания игры, но это точно конец школы, начало института. В те годы я прекрасно владел паскалем. В институте решал на нём задачки за деньги, помогал писать курсачи и вообще — это был прекрасный логичный язык. Поэтому игрушку было решено писать на нём.
Не смотря на то, что я знал как реализовывать графику в ДОСе, я решил не делать графическое приложение. Это связанно с тем это бы страшно глючило и тормозило что, во первых, мне хотелось как можно быстрее реализовать данное приложение, а реализация графики отняла бы много времени; а во вторых, текстовый вид мне нравится больше. Хотя оглядываясь назад, мне кажется лучше бы я сделал графику и ещё добавил поддержку мыши.
Задача была простая: сделать простую изящную игру, которую не стыдно было бы показать. Из возможностей: помощь, возможность сохранения и после запуска продолжение игры с момента остановки, возможность изменять размер игрового поля. Плюс немного красок и изящества.
Реализация
Я не буду целиком разбирать исходники и логику работы всей программы, ибо они очевидны, а что не очевидно ясно из кода. Но более подробно остановлюсь на паре моментов.
Основу игры составляет текстовый массив NxN элементов, где N может быть равно 2, 4, 8 и 16. Массив заполнен всего двумя символами X и Y. Позиция курсора, это позиция текущего элемента массива i и j. При инвертировании элемента массива происходит замена X на Y и Y на X с столбце и строке массива. Ну и плюс есть горячие клавиши (F1-F4, F10), которые позволяют вызвать Помощь, Сохранить/загрузить, создать и выйти. Здесь всё ясно, и как реализовать просто и останавливаться мы на этом подробно не будем.
Наибольший интерес, с познавательной точки зрения, представляет процедура WRIFT.*
Поскольку я решил использовать текстовый режим для игры, то мне понадобилась буква, которая бы заменила бы вентиль. При чём такая буква, которая бы показывала вентиль в вертикальном и горизонтальном положении. Единственные кандидаты, которые подходят для этих целей — это латинские буквы “N” и “Z”. Буква “Z” напоминает положенную на бок букву N, только растянутую.
Я попробовал этот вариант, и остался им не доволен. И понял, что требуется сделать что-то своё, какое-то альтернативное решение. Уже было я задумался написать графическую версию, как наткнулся на паскалевскую программу “Матрица” от автора Абрарова А.М. . Программа начинается так же, как первая “Матрица” — вывода на экран строки, поиск кода. А затем начинаются сыпаться символы-иероглифы. При чём это реализовано только в текстовом режиме.
Правда, сейчас чтобы заставить программу нормально работать, даже в dosbox, надо уменьшить все задержки раз в 10 (delay), иначе конца работы дождутся ваши внуки. Поскольку переделывать программу мне лень, то она представляет чисто академический интерес. Или быть может кто её переделает и покажет миру, софтинка-то красивая (тем более я даю ссылку на сорцы). А если вдруг её автор читает сей пост, то передаю ему мои слова благодарности.
Самое главное, в той программе, для “кракозябр” реализован свой шрифт! И производится его загрузка. Вот эту процедуру загрузки я и позаимствовал, разумеется немного изменив её.
Пара слов о работе со шрифтами.
В MS-DOS средствами BIOS поддерживается работа с растровыми шрифтами. Функции BIOS позволяют получать и устанавливать пользовательские шрифты, а также получать шрифты из знакогенератора видеоадаптера. Все устанавливаемые шрифты имеют одинаковую ширину 8 точек, а высота может иметь три фиксированных значения — 8, 14 или 16 точек. Конкретное значение высоты шрифта определяется видеорежимом, для которого загружается шрифт. Высота шрифта 8 точек соответствует видеорежиму с 50/43 строками, высота 14 точек — видеорежиму с 25 строками для EGA, а высота 16 точек — видеорежиму VGA с 25 строками.
Взято отсюда
Мы будем использовать видеорежим 16 цветов 40х25 символов. В таком видеорежиме, каждый символ представляет собой массив точек 8х16. Говоря просто, каждый символ представляет собой 16 байт, где в байте бит выставленный в единицу означает то, что он окрашивается в чёрный цвет. Если у вас сейчас каша в голове, не пугайтесь — дальше станет понятнее.
Для обозначения закрытого (вертикального) вентиля была выбрана буква “X” (латинская заглавная буква “Икс”) и для открытого горизонтального, буква “Y” (латинская заглавная буква “Игрек”). Выбор был сделан на эти буквы по нескольким причинам. Во первых они знакомы из школьной программы и на слуху. Во вторых, и это важнее, они в таблице ASCII символов стоят подряд (88d и 89d позиция соответственно), что упрощает их замену. А латинские выбраны для того, чтобы можно было сделать меню на русском, без перезалива шрифта.
Итак, с символами мы определились, теперь перейдём к их одежде, ака шрифту. Берём лист бумаги в клетку, и делаем на нём поле 8х16 и приступаем к рисованию символа горизонтального, а затем вертикального вентиля. Поскольку вентиль должен быть одинаковым, как в вертикальном, так и горизонтальном состоянии, то мы будем использовать только первые 8 строк, чтобы получить квадрат. И далее рисуем в этом поле два вентиля, вертикально и горизонтально. Должно получится как-то так
Шрифт двух вентилей
Далее, чёрный квадратик обозначаем единичкой, белый нулём. И формируем 8 байт. После чего их переводим в десятичный формат и формируем массив. Сначала 8 байт символа, потом 8 байт нулей (подвал же мы оставили пустым), повторяем эту процедуру для второго символа.
Таблица двоичных кодов, и переведённые в десятичный формат
В результате получаем такую шапку процедуры:
procedure WRIFT; {Zagruzka shrifta ("pesochnye chasy")} Const Font:array [1..32] of Byte=(129,195,231,153,153,231,195,129,0,0,0,0,0,0,0,0, 255,102,36,24,24,36,102,255,0,0,0,0,0,0,0,0); Var SegScr:Word; OfsScr:Word; screen1:Array [0..512] of Byte absolute Font;
Font — это массив двух символов вентилей (каждый символ на своей строчке). Самая интересная переменная — это массив screen1 — массив, который располагается по абсолютному адресу переменной Font (директива absolute). Далее наступает самое интересное.
begin ofsscr:=ofs(screen1); segscr:=seg(screen1); Asm push bp mov ax,segscr mov es,ax mov bp,ofsscr mov bx,1000h mov dx,88 {s kakogo simvola na4at' zapis' 88d-X,89d-Y} mov cx,2 {koli4estvo simvolov} mov ax,1100h int 10h pop bp mov ah,1 {ustanovit videorezhim txt, tsvetnoj (16 cvetov) 40x25 } mov cx,1000h int 10h End; end;{WRIFT}
Как понятно из строк выше мы загружаем в регистр ES — сегмент, а в регистр BP — смещение адреса расположение нашего шрифта. Командой mov bx,1000h мы говорим, что в шрифте у нас 16 строк (число 10h=16d загружаем в BH, а BL=0).Далее в регистр DX мы загружаем номер символа, с которого мы начинаем менять шрифт. А в CX — количество заменяемых символов. Загружаем в регистр AX — номер функции BIOS для смены шрифта, и вызываем прерывание BIOS. Далее восстанавливаем регистр BP и аналогичным образом выставляем режим видеоадаптера. Подробнее описано тут: shackmaster.narod.ru/fonts.htm. Для лучшего понимания о структуре шрифтов, лучше будет почитать этот сайт.
Таким вот нехитрым образом, можно сменить весь шрифт в ДОСе на свой собственный. Для того, чтобы выгрузить шрифт, используется процедура Restore:
Procedure Restore; {Sbros shrifta} Begin asm mov ax,3 int 10h End; End;{Restore}
Которая выполняется при выводе меню и выходе из программы.
Кстати, для справки, аналогичным образом в ДОСе работали, так называемые “русификаторы”. Они просто заменяли текущий шрифт, на шрифт с русскими буквами.
Такую бы программулинку запустить на информатике, то-то училка бы порадовалась.
Модификации сегодня
На самом деле, игру я даю не в том виде, в котором она была написана много лет назад. В ней обнаружились весьма неприятные косяки:
1. Программа просто вылетала, если не был обнаружен файл GAME.SAV;
2. Генератор случайных чисел не был инициализирован, поэтому генерировал постоянно один и тот же уровень.
Плюс, из-за проблем с кодировками, я создал вторую версию игры, полностью на английском языке. И если вы будете читать исходный код не в ДОС-совместимом редакторе, рекомендую использовать её исходники — там не будет проблем с кодировкой.
Так отрадно, что ДОСбокс есть везде, лично я редактировал большую часть программы на iPAD в метро. Представляете, как забавно выглядит перец с айпадом, и открытым на нём Борланд Паскалем?
Старый добрый Borland Pascal на iPAD
Так что косяки оперативно исправлены.
Несколько скриншотов программы, с кратким описанием
Для тех у кого нет возможности или желания поиграть в игру, приведу несколько ключевых скриншотов игры.
После запуска, у нас открывается игровое поле с последней сохранённой игрой
Старт
Курсор подсвечен, и мигает.
Если нажать F1, то можно получить вот такой нехитрый хелп
Хелп
Для генерации уровня жмём F4 и попадаем вот в такое меню
Меню генерации уровней
Ну и после победы игра вас поздравит
Поздравление с победой
И будет ждать нажатия любой клавиши. В этом случае прогресс игры не сохраняется.
Как установить и играть
В силу особенностей и применения загрузки шрифта, игруха работает только в чистом ламповом ДОСе. По этому, для её работы необходимо использовать dosbox или аналогичную программу.
Установка тривиальна. Качаете архив с программой. Устанавлиаете dosbox. И, если есть желание, русифицируете его, методика для linux вот: old-game.org/?p=1717.
В принципе все эти файлы можно использовать и для винды: Для этого файл russian.txt кладётся в папке с программой и конфигом, и редактируется ярлык для досбокса. В пути ярлыка должно быть что-то типа: “«C:\Program Files\DOSBox-0.74\DOSBox.exe» -userconf” Убираем “-userconf” и будет работать ваш конфиг.
В Ubuntu я просто щёлкаю правой кнопкой мыши по программе и выбираю запустить её в dosbox, как в винде я не знаю, ибо её нет ни на одной из машин. Ну в крайнем случае монтируется путь до игры, командой mount путь.
На выбор вам русская и английская версия. Можно не морочиться с русификацией и геморроем с конфигами, а просто пулять в английскую. Разницы между ними практически нет. Хотя, лично я, как автор, предпочитаю русскую версию.
Управление производится стрелками клавиатуры, выбор и инвертация клавишей insert или двойным нажатием на пробел (да, тут косяк). Если вдруг заест позиция, нажмите один раз на пробел.
Помните, что каждый раз загружается последняя сохранённая игра. Для генерации новой, нажмите F4. Рекомендую начать с поля 4х4. Я сейчас играю 8х8, и пока боюсь переходить на 16х16. Ибо 4х4 я прохожу менее, чем за минуту, 8х8 минут за 7-10, а 16х16 боюсь даже представить.
Помните, что загрузочное поле с надписью HABR и моим ником (картинка в заходнике статьи), пропадёт после сохранения или легального выхода. Она хранится в файле GAME.SAV. Если хочется восстановить, то замените этот файл, на файл из архива.
Формат файла сохранения прост: начала идёт размер поля, например цифра 16, перевод каретки, потом 256 (для поля 16х16) символов X и Y, составляющие рисунок поля, а в конце количество Y в поле (этакая контрольная сумма).
Для этого в OF Calc я сформировал такое поле, цветом сделал надпись в клетках. А затем проставил соотсветственно буквы X и Y.
Заготовка для поля.
После чего сохранил его в CSV. Удалил все разделители. Посчитал количество Y (очень просто, делаешь во OF Writer поиск, заменить на и заменяешь Y на что-нить, он говорит количество замен — вот искомое число). Поставил сначала число 16, перевод каретки и в конце количество игреков. Результат вы можете оценить сами :).
Недостатки текущей версии программы.
Я написал текущей версии… Маловероятно, что я буду переписывать программу и совершенствовать её, ибо она уже страшно устарела. Но с другой стороны, сейчас dosbox можно поставить чуть ли не на фонарик, по этому она может обрести новую жизнь, и быть может имеет смысл переписать и исправить основные недостатки.
Итак:
1. Первый, и самый неприятный недостаток — это убогое управление. Во первых инвертация идёт клавишей Insert, или двойным пробелом. При чём, если пробел нажать нечётное количество раз, то программа “заедает”, пока не сделаешь чётное количество нажатий. Это раздражает.
2. Второй существенный недостаток — это отрисовка всей игры с помощью функций write/writeln. При каждом событии экран перерисовывается заново. При игре на поле 16х16 уже заметны тормоза и вспышки отрисовки. Плюс такой подход усложнил логику программы, и теперь её поправить громадная проблема.
Надо было реализовывать отрисовку с помощью функции goto(x;y); Тогда можно было бы менять отдельный символ, не перерисовывая весь экран.
3. Игра просто просит поддержку мыши. Опять же поддержку мыши нужно реализовывать на пару с п. 2, чтобы можно было точно “ловить” координаты.
4. Мелкий баг, который следует из п.2 — когда спускаешься в правый нижний угол, за рамку убегает один символ. Пытался исправить, и понял что проще вообще переписать это место отрисовки, чем разобраться как оно работает.
Что хотелось бы сделать
Конечно, хотелось бы такое приложение под ведройд или iPad. Чтобы можно было в него играть пальцем. Или уж, если не приложение, то браузерную игрушку (но такую, чтобы работала под Android и iOS). Чтобы там было красивое меню и удобная навигация. Была таблица рекордов. Был счётчик времени, которым можно было бравировать с друзьями. Так же была статистика, чтобы можно было оценить среднее время и скорость навыка.
В общем громадный полёт для творчества, при полном отсутствии свободного времени на изучение программирования под эти устройства. С другой стороны, dosbox есть везде, и наверное более универсальной переносимости добиться будет сложно, и может имеет смысл допилить таки эту программу? Как вы думаете?
Итоги…
Цель статьи, не показать какой я молодец, а просто вспомнить как было. Наверняка практически каждый из нас писал что-то такое в детстве. Это не ах какая сложная программа, и её может написать каждый школьник, при достаточной усидчивости. Здесь скорее пост воспоминание.
Раньше я в программах много использовал ассемблер. Мне нравилось “говорить” с железом напрямую, без посредников. Я лучше чувствовал машину. И даже потом, для AVR я писал исключительно на ассемблере. А сейчас я не понимаю, как функционирует ЭВМ. Конечно, я представляю базовые блоки и т.п., но детальную картину я не знаю, и самое забавное, что её не знает никто!
А сейчас… Языки высокого и сверх высокого уровня абстракции вообще заставляют нас не думать, как и где исполняется код. Это без сомнения хорошо, ибо позволяют сосредоточиться непосредственно на задаче, но с другой стороны уходит тот тёплый ламповый шарм работы с железом…
Список литературы и ссылок:
1. Описание, как загрузить шрифт под ДОС shackmaster.narod.ru/fonts.htm
2. Отличный справочник по ассемблеру, который мне дал понимание, как работать с функциями BIOS, да и вообще с комповым железом: “Программирование на аппаратном уровне: специальный справочник.” Кулаков
3. Эмулятор ДОСа dosbox www.dosbox.com/download.php?main=1
4. Программа и исходники narod.ru/disk/65499856001.6f143511c7c3c2ad7866f07008d8db29/INVERTOR.zip.html
5. Исходники программы “Матрица” narod.ru/disk/65499898001.a6c953f20e2ee023bd00e3518e22fea8/Matrix.pas.html
P.S. Фух, я наверное пару дней вспоминал и гуглил, как же я делал этот шрифт. Код есть, он работает, а как я не помню и не понимаю.
P.P.S. Если народу будет интересно, то я добавлю видео, как я прохожу поле 4х4 менее, чем за минуту (на примере холодильника “Братьев Пилотов”).
P.P.P.S. Буду признателен за все замечания по орфографии и пунктуации, отправленные личным сообщением!
ссылка на оригинал статьи http://habrahabr.ru/post/166057/
Добавить комментарий