Вот так, с помощью нехитрых приспособлений
…можно в 2022 году написать игру на калькуляторе Электроника МК-61.
В прошлом году за 1 000 рублей мне достался программируемый калькулятор Электроника МК-61 1990 года выпуска. Вообще этот калькулятор выпускался аж с 1984 года и имел колоссальный успех у советских граждан. Персональные компьютеры были доступны не каждому. Я бы даже сказал — практически никому, а калькулятор, в свою очередь, стоил 85 рублей (быстрый поиск в интернете показал, что средняя зарплата в те времена составляла 190 рублей), что не слишком дешево, но вполне доступно. Кроме того, МК-61 имел намного больше возможностей, чем предыдущие модели (например, Электроника Б3-34 или Электроника МК-54). В дальнейшем МК-61 эволюционировал в Электронику МК-52, который с помощью ПЗУ позволял запоминать программы после выключения питания.
За счет того, что в МК-61 был встроен дополнительный процессор, в нем появились новые функции: генератор случайных чисел, возврат целой или дробной части числа, модуль, определение знака и так далее. Увеличилось и количество доступных программных шагов (105 вместо 98-и в Электронике МК-54) и регистров памяти (15 вместо доступных в ранних моделях 14-ти).
Мне калькулятор достался в состоянии, близком к идеальному. В комплекте шел оригинальный чехол, блок питания и относительно потрепанная жизнью инструкция. Калькулятор может питаться как от сети, так и от трех АА батареек.
На этом закончим с техническими моментами и историей, тем более я сам мало что понимаю в устройстве подобных калькуляторов.
Сейчас я вкратце расскажу об основных принципах проведения расчетов на этом калькуляторе, а потом постараюсь написать простенькую игрушку, хотя это будет ох как непросто.
Для удобства я буду пользоваться эмулятором, который позволяет отслеживать состояние регистров памяти в реальном времени и даже вводить код в текстовом режиме.
Порядок расчетов
Первым делом, когда неподготовленный человек старается совершить на МК-61 простейшее арифметическое действие, возникает проблема: «А где здесь сука **** *** клавиша равно?»
Дело в том, что на клавиатуре калькулятора действительно нет знака равно («=»). Зато над клавишей сброса значения (Сх) затаилась непонятная клавиша (В↑). Это кнопка ввода числа в память (т. е. в регистр Y).
МК-61 использует для расчетов так называемую обратную польскую запись. Помимо видимого на экране значения (т. н. регистра Х), в калькуляторе есть еще три участвующих в расчетах регистра (Y, Z, T).
Для того, чтобы сложить два числа, например 5 и 2, надо последовательно нажать 4 клавиши: первое число (5); B↑; второе число (2); клавишу сложения («+»). На экране отобразится сумма (7). Вот, что происходит с памятью:
Клавиша В↑ помещает значение из регистра X в регистр Y, из регистра Y в регистр Z, а из Z в T. При этом значение в последнем регистре T стирается. Если нажать на клавишу «+», то значение в регистре Y сложится со значением в регистре X, а прочие регистры сместятся на 1 ячейку назад. Аналогично производятся и другие арифметические действия. При вычитании из регистра Y вычитается регистр X, а при делении регистр Y выступает делимым, а регистр X — делителем.
Перейдем к более сложным действиям. Допустим, нам надо совершить два действия: вычитание и умножение, при этом вычитание производится первым.
Например: (2-6)*10.
Можно пойти простым путем: вводим 2, отправляем в регистр Y; вводим 6, вычитаем; вводим 10, умножаем, получаем значение (-40). После совершения первого действия мы получили (-4). Если при этом ввести число 10, то (-4) автоматически отправится в регистр Y.
Можно поступить иначе: ввести 10, отправить в регистр Y; ввести 2, отправить в регистр Y, при этом 10 переместится в регистр Z; ввести 6, вычесть; умножить. На одно действие больше, но результат один и тот же.
В общем-то, это все, что нужно знать про вычисления на МК-61 (как и на предыдущих моделях калькуляторов). Непривычно и требует время для изучения.
Однако, нас интересует совсем другое. А именно…
Режим программирования
Сложилось так, что получив в распоряжение устройство, предназначенное для написания программ, первым делом я пытаюсь накодить какую-нибудь игру, ведь учиться чему-то новому проще всего в игровой форме.
Так сложилось и с Электроникой. Изучив тему, я понял, что люди в свое время извращались как могли. На экране, который показывает только 8 цифр (не считая индикатора отрицательного значения и экспоненты), можно поиграть в морской бой, пройти трехэтажный лабиринт или даже запустить симулятор космических баталий.
Представьте, что у вас есть трехэтажный лабиринт, в котором каждый этаж представляет собой сетку 7*4. В ячейках этой сетки есть стены, которые можно взорвать (при этом запас динамита ограничен), и различные припасы (количество уменьшается каждый ход). Позиция игрока отображается на экране в формате F.XXXXXY, где F — это номер этажа, количество чисел после запятой — положение по X, а последнее число — положение по Y. Цель игры — найти выход из лабиринта.
И все это на калькуляторе со 105-ю возможными командами и 16 регистрами памяти!
Пора бы написать собственную игру.
В моем случае мы будем угадывать число, которое загадал калькулятор (стандартная задача для обучающих курсов, но на большее на текущий момент меня не хватит. Изначально я хотел написать подобие BlackJack или игры «Очко», но понял, что это слишком сложно).
В начале статьи я говорил, что МК-61 умеет генерировать случайные числа. Для того, чтобы сгенерировать случайное число, нужно последовательно нажать клавиши К и В↑ (СЧ). Проблема заключается в том, что при использовании функциональных клавиш (с использованием клавиши F) генератор случайных чисел (ГСПЧ) может сломаться и, например, начать выдавать одно и тоже число раз за разом. Это общеизвестная проблема, решить которую не успели, так как Советский союз немного закончился.
Но для нашей игры обязательно нужен рабочий генератор случайных чисел, ведь угадывать одно и тоже число раз за разом не очень интересно. Сразу скажу, что особо не вникал в недокументированные особенности МК-61, из которых возникла целая религия «ЕГГОГОлогия» (в честь фразы «ЕГГОГ», которая появлялась на экране калькулятора при возникновении ошибки в вычислениях), поэтому буду действовать, что называется, в лоб.
Переключаемся в режим программирования последовательным нажатием клавиш F и ВП (ПРГ).
Каждое нажатие клавиши вводит определенную команду, которая кодируется двухзначным символом. Три символа слева — это наш код, а в правой части экрана отображается счетчик команд (т. е. позиция последней команды в программной памяти).
Сперва надо сформировать алгоритм игры. МК-61 загадывает случайное число от 1 до 100. Игрок вводит число. Если введенное число больше загаданного, то калькулятор выдает «1», если меньше, то «-1». Если число угадано, то на экране появляется «ЕГГОГ». Количество попыток неограниченно.
Сперва напишем код «игры» на Python для сравнения:
15 строчек чистого говнокода.
Теперь определимся с алгоритмом ГСПЧ. Я решил использовать самый простой линейный конгруэнтный метод, при котором следующее «случайное» значение напрямую зависит от предыдущего.
Формула:
seed = (seed * A) + C Mod M, где:
seed — первоначальное значение, от которого высчитываются последующие «случайные» числа, при этом переменная seed меняется с каждой следующей итерацей.
A, C, M — параметры, заложенные в алгоритм. Эти параметры нужно подбирать тщательно, но в сети есть множество подходящих вариантов.
Алгоритм построен таким образом, что «случайное» значение — это остаток от деления левой части выражения на константу M.
Итак, за первоначальные значения принимаем следующее: A = 106; C = 1283; M = 6075.
Сперва нужно ввести эти значения в память калькулятора. Для этого используется клавиша X⟷П (ввод числа в регистр). Вводим число 106, нажимаем X⟷П и нажимаем клавишу регистра (предлагаю использовать регистр A). Вводим: 106 >>> X⟷П >>> . (a).
Аналогично поступаем с другими числами. 1283 помещаем в регистр B, 6075 в регистр C. Первоначальное значение (seed) помещаем в регистр E. Seed вы придумываете сами, но при этом надо учитывать, что при вводе одного и того-же seed, случайные числа с каждым новым запуском программы будут повторяться.
В итоге должно получится следующее:
Оговорюсь, что все эти значения нужно вводить в режиме автоматических расчетов (т. е. в режиме обычного калькулятора). Для перехода в этот режим нужно последовательно нажать F и /-/ (АВТ).
В режиме программирования последовательно вводим следующие команды (каждая команда разделяется пробелом):
Мы посчитали первую часть выражения. По порядку: достаем из регистра E значение 5 691 (переменная seed отправляется в регистр X); достаем из регистра A значение 106 (константа A отправляется в регистр X, переменная seed отправляется в регистр Y); умножаем; достаем из регистра B значение 1 283 (константа C отправляется в регистр X, предыдущее вычисленное значение отправляется в регистр Y); умножаем.
С/П отвечает за точку остановки. Когда программа доходит до этой команды, она приостанавливает работу и позволяет ввести дополнительные значения в память, если это требуется.
По итогам вычислений мы получим 604 529, но это не то число, что нам нужно. Теперь надо посчитать остаток от деления 604 529 на 6 075 (регистр C).
Остаток от деления считается по следующей формуле:
r = x — (m * y), где:
r — остаток от деления;
x — делимое, то есть в нашем случае 604 529;
m — делитель, то есть 6 075;
y — неполное частное, то есть результат деления 604 529 на 6 075 без части после запятой.
Модифицируем код:
Погнали. Первая часть кода остается такой же, за исключением того, что финальное значение мы помещаем в регистр 9 для последующих вычислений. Далее мы вытаскиваем из регистра С наш делитель, делим 604 529 на 6 075. Получается значение с точкой. Убираем дробную часть с помощью команды К >>> 7 [X]. Снова достаем из регистра С значение 6 075 и умножаем на полученное. Из регистра 9 достаем 604 529, тут же вычитаем его и убираем минус. Новый seed помещаем в регистр E.
Для запуска программы надо перейти в режим обычных расчетов (F >>> /-/ (АВТ)) и нажать В/О (возврат к нулевому индексу программы) и С/П (Старт/пауза).
Случайное число готово. Проверка в Excel подтвердила, что алгоритм работает верно. Даже можно полюбоваться на график из 3 000 «случайных» чисел.
Проблема заключается в том, что в данный момент наш ГСПЧ выдает случайное значение от 0 до 6 075. А нам нужно число от 1 до 100. Для этого нужно взять остаток от деления полученного числа на 100 и прибавить 1.
Повторяем тот же алгоритм еще раз. Здесь можно было бы создать подпрограмму, чтобы не повторяться, но по моим подсчетам, это займет больше ячеек программного кода (или я чего-то не понял).
Сперва надо ввести в регистр D константу 100, от которой мы будем высчитывать второй остаток.
Потом набираем следующий код:
Или, как отображает этот код интерпретатор в эмуляторе (возможно, более удобно):
Я использовал уже 28 из 105 доступных команд. Будем надеяться, что на остаток кода памяти хватит.
В ячейках с 00 по 14 код не менялся. Ячейки с 15 по 22 повторяют аналогичную ячейкам с 06 по 13 последовательность (возврат остатка). В 23 ячейке мы вводим единицу, прибавляем к ней полученный результат (ячейка 24), отправляем сумму в регистр 9 (ячейка 25), стираем регистр X (то, что отображается на экране — ячейка 26) и ставим точку остановки (ячейка 27).
Проверяем. Все работает.
Осталось прописать условия. Игрок вводит значение от 0 до 100 в регистр X, а программа проверяет три условия: X == 0, X < 0, X>=0 (так как условия X>0 МК-61 не предусматривает).
Начинаем с 28 ячейки памяти. Вытаскиваем из регистра 9 наше случайное значение и вычитаем (ячейки 28-29). В регистр X записывается разница.
В 30 ячейке прописываем первое условие (если Х == 0). Здесь хочу обратить внимание на то, что условные операторы в МК-61 работают не так, как в обычных языках программирования, а наоборот. То есть фактически оператор X == 0 означает X != 0. Если разница между введенным числом и загаданным не равна нулю, то в ячейке 31 осуществляется условный переход в ячейку 40. Иначе выполняется код в ячейках 32 — 35:
В ячейке 32 вводим единицу, в ячейке 33 делаем ее отрицательной, а в ячейке 34 берем натуральный логарифм от отрицательного числа, из-за чего калькулятор выдает ошибку (т. е. для игрока это означает победу).
Если игрок не угадал число, то осуществляется переход в ячейку 40, где проверяется условие X < 0. Если игрок ввел число меньшее, чем задумал калькулятор, то выполняется код в ячейках 42-44, т. е. мы вводим единицу, делаем ее отрицательной, а потом осуществляем безусловный переход в ячейку 27, где игроку снова предлагают ввести число.
Если игрок ввел число большее, чем задуманное, то из ячейки 41 осуществляется условный переход в ячейку 50, где калькулятор проверяет условие X >= 0. В ячейке 51 оставляем условный переход в ячейку 00 (потому что других условий не существует), а потом вводим единицу и перемещаемся в ячейку 27 для ввода нового числа.
Программа готова. Но…
Я понял, что можно ее сократить на 8 команд. Для этого нам необязательно проверять два лишних условия (X < 0 и X >= 0). Достаточно просто взять знак числа (т.е. единицу или минус единицу).
В ячейках 00 — 35 ничего не изменилось. При переходе в ячейку 40 программа возвращает знак числа (1 или (-1)) и отправляется в ячейку 27 для ввода нового значения.
Как играть
При запуске калькулятора вводим (с помощью клавиши X-П) в регистры памяти A — D последовательно значения: 106, 1283, 6075, 100. В регистр E вводим любое случайное число, которое придет вам в голову (не отрицательное). От этого числа будет зависеть последовательность генерации случайных чисел. Конечно, если жульничать, то можно всегда вводить одно и тоже значение, но это не так интересно.
Переходим в режим программирования (F >>> ВП (ПРГ)) и набираем указанный выше код. Чтобы переместиться из ячейки 35 в ячейку 40, надо использовать клавишу ШГ→.
Переходим обратно в режим расчетов (F >>> /-/ (АВТ)) и нажимаем последовательно В/О и С/П. МК-61 начинает высчитывать случайное число.
Когда на экране появляется цифра 0, вводим число, которое, предположительно, загадал калькулятор. Если вы угадали, то на экране появится заветная фраза «ЕГГОГ», после чего можно нажать В/О >>> С/П, чтобы начать играть заново c текущим seed, либо можно ввести новый seed в регистр E.
Если вы ввели число меньшее или большее, чем загадал калькулятор, то на экране появится (-1) или 1, соответственно. После этого нужно ввести новое число и нажать исключительно С/П, чтобы программа продолжила работать с той же точки, на которой остановилась.
Конечно, МК-61 позволяет жульничать, ведь в режиме мерцания отображаются все действия, которые он производит, поэтому практически все игры для этого калькулятора предназначены только для честных людей (за исключением скролл-шутера, в котором вся суть игры завязана на режиме мерцания). Кроме того можно вывести задуманное калькулятором значение из регистра 9.
Вот такой краткий получился экскурс в программирование на Электронике МК-61. Помимо МК-61 у меня есть еще Casio PRO fx-1 1978 года выпуска. Тоже программируемый калькулятор, но, к сожалению, встроенный в него язык программирования не позволяет написать что-то игровое, разве что выполнять в автоматическом режиме некоторые математические расчеты (как раз за счет отсутствия дополнительных функций). Но зато он позволяет записывать программы на магнитные карты (которые сейчас нигде не найдешь, хотя в интернете есть гайды, как создать такие карты самостоятельно).