4. Текст программы
%*************************************************************************************************
% Список, содержащий параметры всех кораблей
%*************************************************************************************************
navy([[X1/Y1/1/0,X2/Y2/1/0,X3/Y3/1/0,X4/Y4/1/0], % однопалубные корабли
[X5/Y5/2/R5,X6/Y6/2/R6,X7/Y7/2/R7], % двухпалубные корабли
[X8/Y8/3/R8,X9/Y9/3/R9], % трехпалубные корабли
[X10/Y10/4/R10]]). % четырехпалубный корабль
%*************************************************************************************************
% Главная функция
%*************************************************************************************************
main(Ships,Reefs):-navy(Ships),read(Reefs),search(Ships,Reefs).
%*************************************************************************************************
% Поиск решения
%*************************************************************************************************
search([],_).
search([Head|Tail],Reefs):-search(Tail,Reefs),search_navy(Head,Reefs,Tail).
%*************************************************************************************************
% Расстановка всех кораблей
%*************************************************************************************************
search_navy([X/Y/N/R|Others],Reefs,Tail):-
(N=:=1,search_1deck([X/Y/N/R|Others],Reefs,Tail));
(N=:=2,search_2deck([X/Y/N/R|Others],Reefs,Tail));
(N=:=3,search_3deck([X/Y/N/R|Others],Reefs,Tail));
(N=:=4,search_4deck([X/Y/N/R|Others],Reefs)).
%*************************************************************************************************
% Расстановка четырех однопалубных кораблей
%*************************************************************************************************
search_1deck([X1/Y1/N1/R1,X2/Y2/N2/R2,X3/Y3/N3/R3,X4/Y4/N4/R4],Reefs,Tail):-
% Выбор места для 1-го однопалубного корабля
choose_place(X1/Y1/N1/R1,0,0),A1 is X1+R1*(N1-1),B1 is Y1+(1-R1)*(N1-1),
is_ship_ndeck(X1/Y1/A1/B1,Tail),is_reef_ndeck(X1/Y1/A1/B1,Reefs),
% Выбор места для 2-го однопалубного корабля
choose_place(X2/Y2/N2/R2,X1,Y1),A2 is X2+R2*(N2-1),B2 is Y2+(1-R2)*(N2-1),
conc([X1/Y1/N1/R1],Tail,Tail1),
is_ship_ndeck(X2/Y2/A2/B2,Tail1),is_reef_ndeck(X2/Y2/A2/B2,Reefs),
% Выбор места для 3-го однопалубного корабля
choose_place(X3/Y3/N3/R3,X2,Y2),A3 is X3+R3*(N3-1),B3 is Y3+(1-R3)*(N3-1),
conc([X2/Y2/N2/R2],Tail1,Tail2),
is_ship_ndeck(X3/Y3/A3/B3,Tail2),is_reef_ndeck(X3/Y3/A3/B3,Reefs),
% Выбор места для 4-го однопалубного корабля
choose_place(X4/Y4/N4/R4,X3,Y3),A4 is X4+R4*(N4-1),B4 is Y4+(1-R4)*(N4-1),
conc([X3/Y3/N3/R3],Tail2,Tail3),
is_ship_ndeck(X4/Y4/A4/B4,Tail3),is_reef_ndeck(X4/Y4/A4/B4,Reefs).
%*************************************************************************************************
% Расстановка трех двухпалубных кораблей
%*************************************************************************************************
search_2deck([X1/Y1/N1/R1,X2/Y2/N2/R2,X3/Y3/N3/R3],Reefs,Tail):-
% Выбор места для 1-го двухпалубного корабля
choose_place(X1/Y1/N1/R1,0,0),A1 is X1+R1*(N1-1),B1 is Y1+(1-R1)*(N1-1),
is_ship_ndeck(X1/Y1/A1/B1,Tail),is_reef_ndeck(X1/Y1/A1/B1,Reefs),
% Выбор места для 2-го двухпалубного корабля
choose_place(X2/Y2/N2/R2,X1,Y1),A2 is X2+R2*(N2-1),B2 is Y2+(1-R2)*(N2-1),
conc([X1/Y1/N1/R1],Tail,Tail1),
is_ship_ndeck(X2/Y2/A2/B2,Tail1),is_reef_ndeck(X2/Y2/A2/B2,Reefs),
% Выбор места для 3-го двухпалубного корабля
choose_place(X3/Y3/N3/R3,X2,Y2),A3 is X3+R3*(N3-1),B3 is Y3+(1-R3)*(N3-1),
conc([X2/Y2/N2/R2],Tail1,Tail2),
is_ship_ndeck(X3/Y3/A3/B3,Tail2),is_reef_ndeck(X3/Y3/A3/B3,Reefs).
%*************************************************************************************************
% Расстановка двух трехпалубных кораблей
%*************************************************************************************************
search_3deck([X1/Y1/N1/R1,X2/Y2/N2/R2],Reefs,Tail):-
% Выбор места для 1-го трехпалубного корабля
choose_place(X1/Y1/N1/R1,0,0),A1 is X1+R1*(N1-1),B1 is Y1+(1-R1)*(N1-1),
is_ship_ndeck(X1/Y1/A1/B1,Tail),is_reef_ndeck(X1/Y1/A1/B1,Reefs),
% Выбор места для 2-го трехпалубного корабля
choose_place(X2/Y2/N2/R2,X1,Y1),A2 is X2+R2*(N2-1),B2 is Y2+(1-R2)*(N2-1),
conc([X1/Y1/N1/R1],Tail,Tail1),
is_ship_ndeck(X2/Y2/A2/B2,Tail1),is_reef_ndeck(X2/Y2/A2/B2,Reefs).
%*************************************************************************************************
% Расстановка одного четырехпалубного корабля
%*************************************************************************************************
search_4deck([X1/Y1/N1/R1],Reefs):-
choose_place(X1/Y1/N1/R1,0,0),A1 is X1+R1*(N1-1),B1 is Y1+(1-R1)*(N1-1),
is_reef_ndeck(X1/Y1/A1/B1,Reefs).
%*************************************************************************************************
% Выбор места для корабля
%*************************************************************************************************
choose_place(X/Y/N/R,StartX,StartY):-
member(X,[0,1,2,3,4,5,6,7,8,9]),X>=StartX,
member(Y,[0,1,2,3,4,5,6,7,8,9]),
member(R,[0,1]),X*10+Y>StartX*10+StartY,
A is X+R*(N-1),member(A,[0,1,2,3,4,5,6,7,8,9]),
B is Y+(1-R)*(N-1),member(B,[0,1,2,3,4,5,6,7,8,9]).
%*************************************************************************************************
% Проверка на столкновение с рифами
%*************************************************************************************************
% Одна из палуб корабля попадает на риф
is_reef_ndeck(_,[]).
is_reef_ndeck(X/Y/A/B,[Xx/Yy|Rest]):-is_reef_1deck(X/Y/A/B,Xx/Yy),is_reef_ndeck(X/Y/A/B,Rest).
% Палуба корабля попадает на риф
is_reef_1deck(X/Y/A/B,Xx/Yy):-X>Xx,A>Xx,!.
is_reef_1deck(X/Y/A/B,Xx/Yy):-X<Xx,A<Xx,!.
is_reef_1deck(X/Y/A/B,Xx/Yy):-Y>Yy,B>Yy,!.
is_reef_1deck(X/Y/A/B,Xx/Yy):-Y<Yy,B<Yy,!.
%*************************************************************************************************
% Проверка на столкновение с другими кораблями
%*************************************************************************************************
% Одна из палуб корабля попадает на другой корабль
is_ship_ndeck(_,[]).
is_ship_ndeck(X/Y/A/B,[List|Rest]):-is_deck_ndeck(X/Y/A/B,List),is_ship_ndeck(X/Y/A/B,Rest),!.
is_ship_ndeck(X/Y/A/B,[Xx/Yy/Nn/Rr|Rest]):- is_deck_ndeck(X/Y/A/B,[Xx/Yy/Nn/Rr]),is_ship_ndeck(X/Y/A/B,Rest).
% Одна из палуб корабля попадает на палубу другого корабля
is_deck_ndeck(_,[]).
is_deck_ndeck(X/Y/A/B,[Xx/Yy/Nn/Rr|Rest]):- Aa is Xx+Rr*(Nn-1),Bb is Yy+(1-Rr)*(Nn-1),
is_ship_1deck(X/Y/A/B,Xx/Yy/Aa/Bb),is_ship_ndeck(X/Y/A/B,Rest).
% Палуба корабля попадает на палубу другого корабля
is_ship_1deck(X/Y/A/B,_):- X>A,!.
is_ship_1deck(X/Y/A/B,_):- Y>B,!.
is_ship_1deck(X/Y/A/B,Xx/Yy/Aa/Bb):-
X=:=A,X1 is X,Y1 is Y+1,is_deck_1deck(Xx/Yy/Aa/Bb,X/Y),
is_ship_1deck(X1/Y1/A/B,Xx/Yy/Aa/Bb),!.
is_ship_1deck(X/Y/A/B,Xx/Yy/Aa/Bb):-
Y=:=B,X1 is X+1,Y1 is Y,is_deck_1deck(Xx/Yy/Aa/Bb,X/Y),
is_ship_1deck(X1/Y1/A/B,Xx/Yy/Aa/Bb),!.
is_deck_1deck(X/Y/A/B,Xx/Yy):-X>Xx+1,A>Xx+1,!.
is_deck_1deck(X/Y/A/B,Xx/Yy):-X<Xx-1,A<Xx-1,!.
is_deck_1deck(X/Y/A/B,Xx/Yy):-Y>Yy+1,B>Yy+1,!.
is_deck_1deck(X/Y/A/B,Xx/Yy):-Y<Yy-1,B<Yy-1,!.
%*************************************************************************************************
% Вспомогательные функции
%*************************************************************************************************
% Конкатенация двух списков
conc([],L,L).
conc([X|L1],L2,[X|L3]):-conc(L1,L2,L3).
