Шахматы. Мат ладьёй

Простые окончания в шахматах. ПМК ставит мат королём и ладьёй одинокому королю.

Предыстория

Исходно вариант программы, которая ставит мат, была предложена в журнале Техника молодёжи №9 за 1987 год. Представленная версия программы – модификация, которая проверяет дополнительные условия до начала игры.

Общее описание

Игра по правилам шахмат. За белых, имеющих ладью и конечно короля, играет ПМК. За чёрных королём - игрок. Программа просто демонстрирует, как ставится мат с помощью ладьи.

Игровой процесс

Координаты

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

 8 1828384858687888
71727374757677787
61626364656667686
51525354555657585
41424344454647484
31323334353637383
21222324252627282
11121314151617181
12345678

Как и в классических обозначениях, первый знак – вертикаль. В дальнейшем будем обозначать это координата X, а номер горизонтали - координата Y.

Неверное положение

Дело в том, что мощности ПМК не хватит на перерасчёт координат для произвольного положения, поэтому условие 1: король белых должен быть ниже чёрного, причём минимум через одну горизонталь.

Если это не так, то поверните доску на 90 градусов. Если по-прежнему не так, то ещё раз. С учётом симметрии условие выполнится.

Более того, в алгоритме, используемом ПМК, король не защищает свою ладью. С учётом этого условие 2: ладья в самом начале не должна стоять на соседних вертикалях с королём черных.

Такое ограничение связано с тем, что в этом случае король чёрных может прорваться ниже и тем самым нарушить условие 1. В исходной версии программы такой прорыв проверялся позднее и снова предлагалось перевернуть доску. Посчитав это неудобным, игра то уже началась, условие проверяется до начала.

Кстати, вариант, когда ладья стоит на одной вертикали с чёрным королём не запрещён. Это возможно, не нарушая правила шахмат, когда король белых закрывает чёрного от шаха по той же вертикали.

Начало

Перед первым запуском несколько констант в регистры:

Регистр Значение
R7 36
R8 3
R9 9------0. Признак неверного начального положения: необходимо повернуть доску на 90 градусов. Формирование: 66555555. , КИНВ, К{x}, ВП, 8.
Ra 10
Re 98

Если используется образ, загруженный в эмулятор, то они уже введены.

Затем традиционное В/0 и С/П. На экране отобразится единица – признак готовности.

Далее вводим координаты белого короля (x, y) в регистры R3, R4. Затем координаты белой ладьи в R5, R6. И вместо отдельного ввода координат чёрного короля делаем ход.

Игра

Для скорости ввода ход чёрного короля указываем одним двузначным числом XY, затем С/П. Варианты ответов ПМК:

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

Ограничения

ПМК не проверяет:

Разбор реализации…

Регистры

Приведём для удобства в одном месте описание всех регистров:

Регистр Значение
R0 Признак начала игры. Первый раз сюда заносится единица. Если первоначальная проверка положения прошла успешно, то будет не единица.
R1 Координата X чёрного короля.
R2 Координата Y чёрного короля.
R3 Координата X белого короля.
R4 Координата Y белого короля.
R5 Координата X белой ладьи.
R6 Координата Y белой ладьи.
R7 36. Адрес кода отхода ладьёй (MoveRook).
R8 3, адрес начала хода (ввод).
R9 9------0. Признак неверного начального положения, и адрес (A0) функции формирования хода ладьи (PrintRook).
Ra 10.
Rb Не используется в программе.
Rc Рабочий. Хранит число вертикалей между белыми фигурами. Проверяется только на ноль.
Rd Рабочий. Хранит число вертикалей между чёрным королём и белым минус 2. При нулевом значении короли расположены через одну горизонталь.
Re 98. Адрес вывода неверного положения (PrintErr).

Алгоритм

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

Алгоритм описан на псевдокоде, похожем на JavaScript.

	Start:
	R0 = 1 // Установить признак начала игры

	Input:
	stopAndWaitRx()
	R1 = Math.floor(RX/10)
	R2 = RX - (R1 * 10)
	Rd = R2 - R4 - 2
	if (Rd < 0) { // Короли слишком близко по вертикали
		continue PrintErr
	}
	Rc = R5 - R3 // Если 0, то белые фигуры на одной вертикали
	RX = 1 - Math.abs(R5 - R1); // Удаленность ладьи и чёрного короля в вертикалях
		// RX == 1 - на одной вертикали
		// RX == 0 - на соседних, ладья не сможет отрезать черного короля
		// RX <= -1 - далеко
	if (R0 == 1) // Если начало игры {
		if (RX >= 0) { // Если ладья и черный король на одной или соседних вертикалях
			if (Rc != 0) { // Если белые фигуры не на одной вертикали
				continue PrintErr
			}
			R0 = RX // Сбросить признак начала игры (R0 = 0)
	MoveRook: // Отход ладьёй. В другую половину от чёрного короля 1..4 -> 7, 5..8 -> 1
			RX = Math.floor(R1 / 5)
			if (RX == 0) {
				RX = 7
			} // Или остаётся RX = 1
			RY = R5
			R5 = RX
			if ((RX - RY) == 0) { Если ладья тут и стояла, сдвигаем её правее
				R5++
			}
			RX = PrintRook(R6)
			continue Input
		}
	}
	R0 = RX // Сбросить признак начала игры (R0 <= 0)
	if (RX == 0) { // Если ладья и черный король на соседних вертикалях
		continue MoveRook // Отходим ладьёй
	}
	RX1 = R2 - 1 // Сохраняем значение на горизонталь ниже чёрного короля
	if ((-R6 + RX1) != 0) { // Если ладья не на горизонталь ниже черного короля, т.е. не отрезает его
		if (Rc == 0) { // Если белый король и ладья на одной вертикали, то король мешает своей ладье
			continue MoveRook // Поэтому сначала отходим ладьёй
		} else {
			PrintRook(RX1) // Отрезаем чёрного короля
			continue Input
		}
	} else { // Если ладья уже отрезает черного короля
		if (Rd != 0) { // Если белый король слишком низко
			R4++   // Поднимаем белого короля
	PrintKing: // Вывод координат белого короля
			RX = R3 + R4/10
			continue Input
		} else { // Белый король уже через одну горизонталь от черного
			RX = R1 - R3
			if (RX == 0) { // Короли напротив друг друга
				RX = 10 ** PrintRook(R2) // Делаем шах
				continue Input
			} else { // Не напротив и RX != 0
				RY = RX
				if (Math.log10(Math.abs(RX)) == 0) { // Если короли на соседних вертикалях (RX == ±1)
					continue MoveRook // Отходим ладьёй - выжидательный ход
				} else {
					R3 = R3 + sign(RY) // Продвигаем по горизонтали белого короля к чёрному
					continue PrintKing
				}
			}
		}
	}

	PrintRook: // RX - новое положение ладьи по вертикали
		R6 = RX
		RX = R5 * 10 + R6
		return

	PrintErr:
		RX = R9
		continue Input

Текст программы

 # |  00 01 02 03 04 05 06 07 08 09
 00 |  В/О 1 x→П0 С/П В↑ П→xa ÷ К[x] x→П1 П→xa
 10 |  × x→П2 П→x4 2 x→Пd Кx≥0e П→x5
 20 |  П→x3 x→Пc 1 П→x5 П→x1 К∣x∣ FL0
 30 |  53 Fx≥0 53 П→xc Кx=0e x→П0 П→x1 5 ÷ К[x]
 40 |  Fx=0 43 7 П→x5 <-> x→П5 Fx=0 50 КП→x5
 50 |  П→x6 КПП9 КБП8 x→П0 Кx≠07 П→x6 /-/ П→x2 1
 60 |  + Fx≠0 68 П→xc Кx≠07 FВx КПП9 КБП8 П→xd Fx≠0
 70 |  78 КП→x4 П→x3 П→x4 П→xa ÷ + КБП8 П→x1 П→x3
 80 |  Fx≠0 94 В↑ К∣x∣ FLg Кx≠07 <-> КЗН П→x3
 90 |  + x→П3 БП 73 П→x2 КПП9 F10x КБП8 П→x9 КБП8
 A0 |  x→П6 П→x5 П→xa × +

Программа один в один выполняет шаги по указанному выше алгоритму. С учётом того, что никаких сложностей (в отличие от оригинала) не производится, то можно легко понять реализацию.

Единственное пояснение: команда В/О перенесена из конца в начало, чтобы обезопасить ввод единицы. Иначе, если до нажатия С/П были введены какие-то цифры, то ввод продолжится и единица не получится.