Игра Охота на лис (логическая игра).
Найти всех лис.
На поле 10 на 10 случайным образом расположены лисы, количество которых (N) задаётся через регистр Re. Все в разных клетках. Вы задаёте своё положение, указав координаты клетки (координаты охотника). В ответ ПМК выдаёт количество лис, пеленгуемых из указанной клетки. Это число указывает, сколько лис расположено в одной вертикали, горизонтали и диагоналях с указанной клеткой.
Если координаты клетки совпадают с положением одной из лис, то она считается найденной, но НЕ исключается из дальнейшей пеленгации. В этом случае ПМК отображает в дополнении к целому числу найденных дробную часть .01, чтобы показать, что в указанных координатах находится одна лиса.
Перед запуском укажите случайное число от 0 до 1. Оно будет использовано для генерации положений лис, затем В/О С/П.
ПМК расставит лис случайным образом и по окончании выдаст −N, как бы сообщая, что осталось N лис. В регистре Y будет ноль (количество ходов за игру).
Вы задаёте координаты клетки, из которой хотите провести пеленгацию, числом в виде пары цифр, разделённых десятичной точкой. Обычно целая часть – вертикальная координата, а дробная – горизонтальная. Впрочем, можете считать наоборот, для игры это не важно – поле-то квадратное! После С/П ПМК выдаст результат на экран. Вот возможные результаты:
Число | Значение |
---|---|
0…N | Количество лис, запеленгованных из заданной координаты. Сами координаты (ход) находятся в регистре Y. Для вас, конечно, идеальный ответ это ноль. В этом случае сразу столько клеток поля исключаются из рассмотрения. |
(1…N).01 | То же, что выше, но в текущей клетке есть лиса. Она входит в общий подсчёт количества. |
−N…−1 | Вы указали неверную координату. Выводится, сколько лис осталось найти. В RY будет сделанное вами количество ходов за всю игру. Ходы с неверной координатой не учитываются, поэтому можно специально указать, например отрицатеьное число, чтобы получить эту информацию. |
Если вы нашли всех лис, то на экран выдаётся -99999999. , как признак окончания игры. В регистре Y указано количество ходов, которые вы сделали за игру.
Предупреждение: если вы случайно повторите координаты с найденной
ранее лисой, то счётчик оставшихся лис собъется и игра завершится
раньше. Если что, скорректировать счётчик можно в регистре R0.
Для начала новой игры введите случайное число от 0 до 1 и нажмите С/П (или В/0 С/П).
Дело в том, что это максимальное количество лис, которые можно разместить. Получено импирическим путём. Автор предполагал любое число от 1 до 100. Но испытания показали, что при указании бо́льшего количества лис ПМК зацикливается на этапе расстановки. Поэтому задавайте в Re число от 1 до 38 (включительно).
И да, расстановка при большом количестве лис дело долгое, поэтому если используете эмулятор с ускорением – ускорьте.
Программа делится на две части. Первая – расстановка лис на основе случайного числа, ведённого игроком. Вторая – цикл поиска лис.
R0 | В первой части это координата очередной лисы, во второй счётчик оставшихся лис. |
---|---|
R1 | В первой части счётчик для цикла проверки по ранее рассаженным лисам, чтобы исключить двух лис в одной клетке. Во второй части – ход игрока. |
R2 | Счётчик для пробега по всем лисам. В первой части чтобы всех расставить, во второй чтобы сравнить с координатами охотника. |
R3 | В первой хранит базовое случайное число внешнего цикла. Во второй – признак найденной лисы. |
R4 | В первой части это максимум для внутреннего цикла расстановки. Во второй – количество найденных лис в процессе хода. |
R5 | Число ходов за игру. |
R6 | Базовое число для всей псевдослучайной последовательности лис. |
R6 | Текущее случайное число. |
R8 | Не используется. |
R9 | Константа -9.9999992 × 10-11 (-9.9999992-11). Хвостик (92) – это адрес генератора случайного числа. Само значение (необычное) используется для получения .01, когда найдена лиса. |
Ra | 10. |
Rb | Не используется. |
Rc | 25. Адрес начала основного цикла программы. |
Rd | 51. Адрес кода, где увеличивается счётчик найденных лис. |
Re | Общее количество лис. Должно задаваться до начала игры. |
# | | 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 |
---|---|---|---|---|---|---|---|---|---|---|
00 | | В/О | x→П6 | x→П7 | П→xe | x→П2 | 0 | x→П4 | x→П5 | КПП9 | x→П0 |
10 | | П→x7 | x→П3 | П→x6 | x→П7 | КП→x4 | П→x4 | x→П1 | FL1 | 29 | П→x3 |
20 | | x→П7 | FL2 | 08 | П→xe | x→П0 | П→x5 | П→x0 | /-/ | БП | 60 |
30 | | КПП9 | − | Fx=0 | 17 | П→x7 | В/О | FВx | К{x} | П→x1 | К{x} |
40 | | − | Кx≠0d | + | Кx≠0d | FВx | ÷ | К∣x∣ | П→xa | − | Fx=0 |
50 | | 52 | КП→x4 | FL2 | 74 | П→x1 | П→x3 | П→x9 | × | П→x4 | + |
60 | | С/П | П→xa | ПП | A1 | x→П1 | Кx≥0c | П→xa | − | Кx<0c | КП→x5 |
70 | | П→x6 | ПП | A7 | x→П3 | П→x1 | КПП9 | − | Fx=0 | 36 | П→x5 |
80 | | КП→x3 | FL0 | 51 | С/П | В/О | 0 | 0 | 0 | 0 | 0 |
90 | | 0 | 0 | П→x7 | 7 | × | Fπ | + | К{x} | x→П7 | 2 |
A0 | | F10x | × | К[x] | П→xa | ÷ |
Программа состоит из двух частей. Расстановка лис и основной цикл взаимодействия
с игроком. Для начала общая идея. Координаты лис не хранятся. Используя программный генератор
псевдослучайных чисел, подбирается такое базовое случайное число, чтобы
генератор выдал N разных (по модулю 100) случайных чисел. Потом в цикле программы базовое
число восстанавливается, чтобы пробежать
по тем же лисам.
Генератор сформирует те же самые числа, он же программный!
Расстановка самая долгая. Сначала используется как базовое случайное число, указанное пользователем. Но если с его помощью не удаётся получить N разных координат, то вычисляется другое (берётся последнее).
Для начала рассмотрим генератор случайных чисел. Он начинается с
адреса 92 (R9).
Кстати, нули с адреса 86 по 91 это просто резерв на возможное расширение
генератора или лучшее оформления завершения игры (адреса 83, 84). Никак не
используются, можно поставить ККНОП.
Генератор работает по формуле Ni+1 = {Ni × 7 + π}.
Хвост процедуры с адреса 99 просто преобразует случайное число в координату.
Используется известный трюк, когда команду В/0 переносят в начало
программы и идёт автоматический заворот
на начало.
В/0 в начале нам пригодится в другом фрагменте.
Адреса 01..06. Инициализация. Базовое число для генератора сохраняется в R6 и в текущем R7. Количество лис заносится в R2 для внешего цикла. Обнуляются верхняя граница внутреннего цикла (R4) и количество ходов игрока (R5).
Поясним, как осуществляется расстановка. Внешний цикл (по R2), просто генерит очередную координату лисы, чтобы её проверил на уникальность внутренний цикл (по R1). Внутренний цикл сначала сохраняет текущее случайное число (R7) в R3, затем устанавливает базовое (R6) в текущее и проверяет заново, сравниваю очередные координаты при генерации с текущими в R0. Если совпадений нет, то внутренний цикл завершается, восстанавливая из R3 в R7 текущее значение случайного числа. Если есть совпадение, то происходит возврат на начало программы (прерывая все циклы), но используя уже текущее случайное число из R7 как базовое.
Адреса 08..09. Получение очередной координаты. Сохраняем её в R0. Это начало внешнего цикла расстановки.
Адреса 10..16. Подготовка внутреннего цикла. Сначала сохраняется R7 в R3 и последовательность восстанавливается на базовое из R6. Затем верхний предел для внутреннего цикла (R4) увеличивается и сохраняется в R1.
Адреса 17..18, 29..33. Внутренний цикл. По адресу 29 на самом деле код команды П→x0. Т. е. извлекаются координаты проверяемой лисы, затем генерируется очередная и сравниваются простым вычитанием. Если нет совпадений, то возврат на начало цикла (адрес 17). Несколько необычно, что цикл начинается с FL1, а не заканчивается им. Просто при первом проходе значение в R4 (верхняя граница внутреннего цикла) равно единице и мы должны сразу это учесть.
Адреса 34..35. Найдено совпадение. Перегенерация. Нам нужно другое базовое число. Берём последнее и возвращаемся на начало программы (на адрес 01, если кто забыл, куда приведёт В/0 без предварительного ПП).
Адреса 19..22. Окончание внутреннего цикла. Просто восстанавливаем из R3 ранее сохранённое случайное число и продолжаем внешний цикл.
Адреса 23..24. Окончания внешего цикла.
Окончание первой части программы (расстановки).
Инициализируем счётчик оставшихся лис (R1). Далее с адреса 25 (Rc) идёт основной цикл программы:
ввести ход пользователя, проверить координаты, пробежаться
по всем лисам
с подсчётом, вывести результат.
Тут есть один интересный момент. В цикле расстановки мы R0 использовали для сохранения
координат очередной лисы, а R1 для цикла. В основной части наоборот, R1 будем использовать для
сохранения хода пользователя, а R0 для цикла по оставшимся лисам. Это сделано, что
спрятать
от игрока (перетереть) координаты последней лисы после расстановки.
Адреса 25..29, 60 (Rc). Заталкивание
количества сделанных ходов (R5) в стек,
вывод количества оставшихся лис со знаком минус и переход на остановку.
О том, что адрес команды перехода (60) совпадает с командой
П→x0 упомянул ранее.
Этот трюк используется для сокращения длины программы.
Адреса 61..68. Проверка и корректировка хода игрока (координаты охотника). Сначала с помощью хвостика генератора (адрес A1) отсекаем лишние дробные знаки. Сохраняем в R1. И проверяем на ≥0, и что при сложении с −10 уже будет отрицательным. При неудачной проверке переход на начало цикла (Rc).
Адреса 69..73. Подготовка к циклу проверки всех лис с координатой охотника. Сначала (адрес 69) просто увеличиваем счётчик ходов. А затем используем особенности адресации ПМК. Дело в том, что у ПМК после адреса A4 идёт возврат на начало, но хитро. Сначала малый цикл с 00 по 06 (адреса A5..B1), а потом большой, но снова с 00 (B2). В начале нашей программы (с адреса 02) идёт установка текущего числа для генератора, инициализация счетчика цикла по количеству лис и обнуление R4. А нам именно это и нужно для подготовки. Поэтому мы извлекаем базовое число из R6 и вызываем эти команды как подпрограмму с адреса A7 (02). А В/0 по нулевому адресу (фактически B2) вернёт нас назад. Нулём после этой подпрограммы мы инициализируем признак найденной лисы (R3).
Адреса 74..84. Проверка, что лиса найдена.
Получение координат очередной лисы и сравнение с координатами охотника.
Если нет, то переход на другие сравнения (адрес 36). Если есть, то
предварительно заталкиваем
счётчик ходов (R5) в стек, для возможного
окончания игры (83, 84). Затем корректируем признак найденной лисы (R3). После
КП→x3
там получится число -99999999. .
Причем оно же попадет в RX, потому что 99 – это адрес регистра R3.
И если все лисы найдены (цикл по R0), то оно же станет признаком окончания.
Адреса 36..53. Продолжение цикла или сравнения координат лисы и
координат охотника. Для объяснения дальнейших проверок удобнее ввести формулы.
Обозначим координаты лисы как F.f (число), а координаты охотника (в R1), как H.h.
Если перейти к дробям, то (F + f/10) и (H + h/10) соответственно.
Тогда разность (которая сейчас в RX) будет (H + h/10) − (F + f/10).
А разность дробных частей получится (f/10 − h/10).
Для получения это разницы восстанавливаем координаты лисы из X1
(адрес 36) и далее по адресам 37..40 просто её находим.
Если дробные части совпали (адрес 41), то переход на
конец цикла с приращением сумматора: на адрес 51 (Rd). Если нет, то
мы просто складываем (H + h/10) − (F + f/10) + (f/10 − h/10) по адресу 42.
В результате получим (H − F). И если целые части совпали (адрес 43),
то снова в конец с приращением. Иначе делим (H − F) /
(f/10 − h/10) по адресу 45. Делитель точно не ноль, это уже проверили.
Если клетки расположены на одной диагонали, то разница между вертикальными и
горизонтальными координатами должна совпадать. С учётом того, что целая часть в 10 раз
больше дробной, разница совпадает, если результат деления равен ровно 10 (или −10).
Именно эту проверку мы делаем по адресам 46..50. При неудаче мы перепрыгиваем
команду приращения счетчика лис по адресу 51. И цикл по R2 на проверку
очередной лисы (адрес 74).
Адреса 54..59. Вывод результата. Если с R1 в стеке (координаты охотника) всё понятно, то как получается +0.01 у счётчика в R4 требует пояснения. Если лиса не найдена, то в R3 остаётся ноль, и умножение на R9 ничего не изменит – этот ноль прибавится к R4 не меняя его. А вот если лиса найдена, то в R3 будет -99999999. , и умноженное на R9 (-9.9999992-11) даст 9.9999991-03, что при сложение с целым числом округляется до 0.01. Здесь становится понятно зачем в R9 такая странная константа. С одной стороны порядок -11 позволяет не менятся регистру при косвенной адресации. С другой – нивелирует большое число в R3.
Вот собственно и все. Мы вернулись на начало основного цикла программы.