Что можно сделать с компьютером на электромагнитных реле у которого нет никаких устройств ввода, а из устройств вывода — только дамп восьми регистров?
Поиграть в игры, конечно! Играли же древние люди на калькуляторах МК-61/52, которые лишь немногим нагляднее.
Угадай число
Начал я с игры, где компьютер с помощью половинного деления должен найти загаданное игроком целое число от 0 до 100.
Свою догадку компьютер записывает в регистр A, а затем останавливается.
Значения всех регистров можно увидеть благодаря светодиодам, встроенным в реле:
Теперь игрок должен изменить код программы в ПЗУ, заменив константу, загружаемую в регистр D. Если там не 0, это значит, что предположение больше загаданного числа. Иначе — меньше. После этого нужно нажать кнопку «продолжить работу». Проверив регистр D, компьютер использует прежнее предположение как верхний или нижний предел в следующей попытке.
MOVI B, 1 ; 00: 10000001 00000001
MOVI C, 101 ; 01: 10000010 01100101
Loop:
ADD A, B, C ; 02: 01001000 00011010
SHR A, A ; 03: 01111000 00001100
HALT ; 04: 00010000 00000000
MOVI D, guess ; 05: 10000011 iiiiiiii
OR F, D, D ; 06: 01101000 00110011
JMP NZ, Greater ; 07: 11100111 00001010
MOV B, A ; 08: 00011001 00000000
JMP Loop ; 09: 10000111 00000010
Greater:
MOV C, A ; 0a: 00011010 00000000
JMP Loop ; 0b: 10000111 00000010
Недостаток первой программы в том, что ей неудобно пользоваться. Это можно понять, посмотрев на фотографию ПЗУ — не очень-то легко переключать такие маленькие тумблеры, играя в игру (а ведь при этом надо ещё и следить, чтобы программу случайно не испортить).
Поэтому я придумал другой вариант ввода. Для отладки рядом с каждым регистром предусмотрен тумблер для сброса его значения. Его переключать намного удобнее, чем менять ПЗУ.
Теперь компьютер заранее заносит единицу в регистр D, а игрок либо сбрасывает его (если догадка меньше, чем задуманное число), либо оставляет как есть (если догадка больше).
MOVI B, 1 ; 00: 10000001 00000001
MOVI C, 101 ; 01: 10000010 01100101
Loop:
ADD A, B, C ; 02: 01001000 00011010
SHR A, A ; 03: 01111000 00001100
MOVI D, 1 ; 04: 10000011 00000001
HALT ; 05: 00010000 00000000
OR F, D, D ; 06: 01101000 00110011
JMP NZ, Greater ; 07: 11100111 00001010
MOV B, A ; 08: 00011001 00000000
JMP Loop ; 09: 10000111 00000010
Greater:
MOV C, A ; 0a: 00011010 00000000
JMP Loop ; 0b: 10000111 00000010
Игра вычитания (игра Баше)
Другая классическая игра, которую часто реализуют начинающие программисты — игра Баше.
В ней два игрока из кучки, содержащей первоначально N предметов, по очереди берут не менее одного и не более М предметов. Проигравшим считается тот, кому нечего брать.
В моём варианте игра идёт с компьютером. Изначально в кучке 21 предмет (например, 21 спичка). Игроки берут от 1 до 3 спичек в свой ход, а выигрывает тот, кто берёт последнюю спичку.
В игре есть выигрышная стратегия для первого игрока — всегда оставлять число спичек, которое кратно четырём. Так как 0 тоже кратно четырём, то второй игрок привести игру в эту позицию не сможет, а значит проиграет.
Компьютер ходит вторым, оставляя шанс человекам, но ошибок он не делает. И если игрок не будет следовать выигрышной стратегии, то это сделает компьютер.
MOVI A, 21 ; 00: 10000000 00001101
Loop:
HALT ; 01: 00010000 00000000
MOVI B, move ; 02: 10000001 000000mm
SUB A, A, B ; 03: 01011000 00001001
AND C, A, 3 ; 04: 01100010 10001011
MOVI Z, C, 1 ; 05: 10010010 00000001
SUB A, A, C ; 06: 01011000 00001010
JMP Loop ; 07: 10000111 00000001
В первой версии использовался тот же подход, что и для «угадай число» — в свой ход нужно было закодировать число спичек внутри одной из инструкций. Даже можно было считерить и взять все спички сразу, а компьютер ничего не заметит.
Но потом я переписал и эту программу тоже. Теперь в три регистра (B, C, D) компьютер заносит по 1, а игрок должен сбросить 0, 1 или 2 из них. Оставшиеся единицы — это те спички, которые он берёт. Читерить тоже можно, если сбросить все три регистра (как будто не берёшь ничего).
MOVI A, 21 ; 00: 10000000 00010101
Loop:
MOVI B, 1 ; 01: 10000001 00000001
MOVI C, 1 ; 02: 10000010 00000001
MOVI D, 1 ; 03: 10000011 00000001
HALT ; 04: 00010000 00000000
SUB A, A, B ; 05: 01011000 00001001
SUB A, A, C ; 06: 01011000 00001010
SUB A, A, D ; 07: 01011000 00001011
AND C, A, 3 ; 08: 01100010 10001011
MOVI Z, C, 1 ; 09: 10010010 00000001
SUB A, A, C ; 0a: 01011000 00001010
JC Exit ; 0b: 10110111 00001101
JNZ Loop ; 0c: 11100111 00000001
Exit:
HALT ; 0d: 00010000 00000000
Конечно программа получилось несколько длиннее, но зато пользоваться ей значительно удобнее.
Дальше я планирую допаять ПЗУ (сейчас есть только 32 слова из возможных 64), а также добавить-таки устройство ввода в виде матрицы из тумблеров. Может тогда получится сделать хотя бы крестики-нолики.
Автор: Dovgaluk