Мы можем сделать общий предикат, который может идти в обоих направлениях (влево и вправо).
Нам в основном здесь нужны два параметра: индекс первого столбца 1004 * и «направление», в котором мы идем, это -1
для «правильного» и 1
для « левый».
Таким образом, мы можем реализовать предикат diagonal/4
, который будет генерировать такой диагональ.
По сути, мы должны принять во внимание три случая:
- матрица не имеет строк, в этом случае диагональ представляет собой пустой список;
- матрица имеет хотя бы одну строку, но индекс слишком низкий / высокий, в этом случае диагональ также является пустым списком; и
- матрица имеет хотя бы одну строку, и индекс не выходит за пределы диапазона, в этом случае мы добавляем элемент первой строки для данного столбца и рекурсивно вызываем предикат, где мы сдвигаем столбец на один вправо или один слева.
Таким образом, мы можем реализовать это с помощью:
diagonal([], _, _, []).
diagonal([Row|Rest], Col, DCol, Result) :-
( nth0(Col, Row, El)
-> (Result = [El | R2],
Col2 is Col + DCol,
diagonal(Rest, Col2, DCol, R2))
; Result = []).
Итак, теперь мы можем получить диагонали с:
?- diagonal([[4,5,6],[7,8,9]], 1, -1, Diagonal).
Diagonal = [5, 7].
?- diagonal([[1,2,3],[4,5,6],[7,8,9]], 1, -1, Diagonal).
Diagonal = [2, 4].
?- diagonal([[4,5,6],[7,8,9]], 0, 1, Diagonal).
Diagonal = [4, 8].
Конечно, вышесказанное еще не завершено: поскольку в вопросе вводятся две координаты. Однако, если мы берем правильную координату, для пары координат (X, Y)
это эквивалентно (X+Y, 0)
. То же самое для левой диагонали: диагональ, содержащая (X, Y)
, совпадает с диагональю, содержащей (0, Y-X)
. Однако обратите внимание, что возможно, что X+Y
или Y-X
находятся вне диапазона, поэтому мы можем сначала «нормализовать» координату, но в случае, если координата «слишком высокая» или «слишком низкая», мы, таким образом, будем нужно отбросить определенное количество строк и каждый раз обновлять число, пока мы не достигнем значения, которое находится в диапазоне.
Таким образом, мы можем реализовать предикат, который сначала делает несколько итераций, пока не найдет действительный индекс, а затем передает управление предикату diagonal/4
, например prediagonal/4
:
prediagonal([], _, _, []).
prediagonal([Row|Rest], Col, DCol, Result) :-
Col2 is Col + DCol,
( nth0(Col, Row, El)
-> (Result = [El | R2],
diagonal(Rest, Col2, DCol, R2))
; prediagonal(Rest, Col2, DCol, Result)).
Итак, теперь мы можем написать наши left_diagonal/4
и right_diagonal
в терминах prediagonal/4
:
left_diagonal(M, R, C, Diagonal) :-
Delta is C-R,
prediagonal(M, Delta, 1, Diagonal).
right_diagonal(M, R, C, Diagonal) :-
Delta is R+C,
prediagonal(M, Delta, -1, Diagonal).
тогда это дает нам:
?- right_diagonal([[1,2,3],[4,5,6],[7,8,9]], 1, 0, Diagonal).
Diagonal = [2, 4].
?- left_diagonal([[1,2,3],[4,5,6],[7,8,9]], 1, 0, Diagonal).
Diagonal = [4, 8].
Вышеуказанное не самое элегантное решение. Возможно, было бы лучше «объединить» diagonal/4
и prediagonal/4
в одном предикате. Я оставляю это как упражнение.