Prolog - 获得用坐标绘制的三角形的最大周长
Prolog - get the greatest perimeter of triangles drawn with coordinates
平面中点的名称和坐标可以用点(A,X,Y)给出。
Prolog语言中按照这个关系定义10个点[比如point(a, 13, 47)
]创建数据库
由于其中三个点将定义一个三角形,因此创建列出这些三角形的规则。
创建一条规则,通过识别三角形中周长最大的三角形在屏幕上打印。
您已经打印出程序列表,其中包含关系和规则,三角形列表,以及最大周长的三角形。
nokta(a, 3,1).
nokta(b, 6,2).
nokta(c, 7,1).
nokta(d, 9,1).
nokta(e, 6,3).
nokta(f, 4,3).
nokta(g, 9,3).
nokta(h, 13, 47).
nokta(i, 15, 49).
istriangle(A, B, C) :-
A > 0 ,
B > 0 ,
C > 0 ,
A + B >= C ,
A + C >= B ,
B + C >= A .
calculate_the_perimeter_triangle(P1,P2,P3,AB,AC,BC,S) :-
nokta(P1, X1, Y1),
nokta(P2, X2, Y2),
nokta(P3, X3, Y3),
dif(P1, P2),
dif(P2, P3),
dif(P1, P3),
\+ (X1 == X2, X2 == X3, X1 == X3),
\+ (Y1 == Y2, Y2 == Y3, Y1 == Y3),
%IABI = √((x2 – x1) ² + (y2 – y1) ² )
AB is sqrt((X2-X1)^2 + (Y2-Y1)^2),
%IACI = √((x3 – x1) ² + (y3 – y1) ² )
AC is sqrt((X3-X1)^2 + (Y3-Y1)^2),
%IBCI = √((x3 – x2) ² + (y3 – y2) ² )
BC is sqrt((X3-X2)^2 + (Y3-Y2)^2),
S is AB + AC + BC,
AB > 0 ,
AC > 0 ,
BC > 0 .
calculate_perimeter_triangle(N1,N2,N3) :-
calculate_the_perimeter_triangle(X,Y,Z,N1,N2,N3,S),
istriangle(N1,N2,N3),
write(S - ' Bu koordinatlardan oluşan üçgen.'),
nl,
fail.
我得到了三角形的周长但是我无法得到三角形的周长
,nl,fail.
这导致 calculate_perimeter_triangle
失败,Prolog 回溯并重试。回溯之后,就好像谓词中的代码根本就没有 运行 一样,变量未绑定,状态丢失。只有使用 write()
会留下副作用(屏幕上的文本),您才能看到它的发生,但无法捕获该信息并将其保存在程序中。
你可以使用 findall/3
findall([nokta(ID1, X1, Y1), nokta(ID2, X2, Y2), nokta(ID3, X3, Y3)],
(
nokta(ID1, X1, Y1), nokta(ID2, X2, Y2), nokta(ID3, X3, Y3),
dif(ID1, ID2), dif(ID2, ID3), dif(ID3, ID1)
),
Triangles)
构建一个列表三角形,其中包含具有 3x nokta(ID, X, Y)
和不同 ID 的所有列表,然后使用这些三角形计算周长。
我可能会这样表示点,用一个方便的谓词给我一个更简洁的符号,p( Name, X:Y )
。
point( p(N,P) ) :- point(N,P).
point( a , 3 : 1 ).
point( b , 6 : 2 ).
point( c , 7 : 1 ).
point( d , 9 : 1 ).
point( e , 6 : 3 ).
point( f , 4 : 3 ).
point( g , 9 : 3 ).
point( h , 13 : 47 ).
point( i , 15 : 49 ).
然后可以通过简单地从数据库中绘制 3 个不同的点来构造一个三角形。我们可以通过
- 获得每一分
- 将所有 3 个组合成一个列表
- 使用
sort/2
对列表进行排序。
sort/2
通过删除重复元素确保列表代表 set,这确保我们不会创建三角形 AAB。那只是一个线段。
sort/2
同样,由于我们将点的名称作为输出 p/2
结构中的第一个参数,因此按规范顺序对点进行排序,因此三角形 ABC 将被视为与三角形 CBA 相同。
然后,我们使用built-in atom_chars/2
谓词,将三个点名称组合成一个原子来唯一标识三角形,并计算其周长。
最后我们把它组装成一个t/5
这种形式的结构:
t( Name, Point1, Point2, Point3, perimeter(Perimeter) )
代码如下所示:
triangle( t(N,Pa,Pb,Pc,perimeter(P)) ) :-
point(P1) ,
point(P2) ,
point(P3) ,
sort([P1,P2,P3],[p(A,Pa),p(B,Pb),p(C,Pc)]) ,
atom_chars(N,[A,B,C]),
perimeter(Pa,Pb,Pc,P) .
计算周长很简单:我们只需计算三角形每条边的长度并将它们相加即可:
perimeter( P1, P2, P3, P ) :-
distance(P1,P2,L1),
distance(P2,P3,L2),
distance(P3,P1,L3),
P is L1+L2+L3
.
并且计算线段的长度很容易:它只是笛卡尔平面上两点之间的距离,使用从勾股定理导出的距离公式:
distance( X1:Y1, X2:Y2, D ) :- D is sqrt( (X2 - X1)^2 + (Y2 - Y1)^2 ).
现在,每个三角形都带有所需的所有信息。我们可以使用 built-in set_of/3
谓词收集可以从数据库中的点集构造的三角形集:它既排序又 de-duplicates 要排序的列表:
triangles( Ts ) :- setof( T , triangle(T), Ts ).
剩下的唯一任务就是找出周长最长的三角形。这只是递归遍历列表的问题,使用 辅助谓词 将在我们进行时跟踪具有最长周长的三角形:
max_perimeter( [T|Ts] , Tmax ) :-
max_perimeter( Ts, T, Tmax ).
max_perimeter( [] , Tmax , Tmax ).
max_perimeter( [T|Ts] , T0 , Tmax ) :-
maxp(T,T0,T1),
max_perimeter(Ts,T1,Tmax).
maxp( T1, T2, T1 ) :- perimeter(T1,P1), perimeter(T2,P2), P1 >= P2, !.
maxp( T1, T2, T2 ) :- perimeter(T1,P1), perimeter(T2,P2), P1 < P2 .
perimeter( t(_,_,_,_,perimeter(P)) , P ).
然后我们可以将它们与一个 main/0
谓词放在一起来驱动它:
point( p(N,P) ) :- point(N,P).
point( a , 3: 1 ).
point( b , 6: 2 ).
point( c , 7: 1 ).
point( d , 9: 1 ).
point( e , 6: 3 ).
point( f , 4: 3 ).
point( g , 9: 3 ).
point( h , 13:47 ).
point( i , 15:49 ).
main :-
triangles(Ts) ,
list_triangles(Ts) ,
max_perimeter(Ts, Tmax),
nl(),
writeln(longest_perimeter) ,
writeln(Tmax).
triangles( Ts ) :- setof( T , triangle(T), Ts ) .
triangle( t(N,Pa,Pb,Pc,perimeter(P)) ) :-
point(P1) ,
point(P2) ,
point(P3) ,
sort([P1,P2,P3],[p(A,Pa),p(B,Pb),p(C,Pc)]) ,
atom_chars(N,[A,B,C]) ,
perimeter(Pa,Pb,Pc,P)
.
perimeter( P1, P2, P3, P ) :-
distance(P1,P2,L1),
distance(P2,P3,L2),
distance(P3,P1,L3),
P is L1+L2+L3
.
distance( X1:Y1, X2:Y2, D ) :- D is sqrt( (X2 - X1)^2 + (Y2 - Y1)^2 )
.
list_triangles( [T|Ts] ) :-
writeln(T),
list_triangles(Ts).
list_triangles( [] ).
max_perimeter( [T|Ts] , Tmax ) :-
max_perimeter( Ts, T, Tmax ).
max_perimeter( [] , Tmax , Tmax ).
max_perimeter( [T|Ts] , T0 , Tmax ) :-
maxp(T,T0,T1),
max_perimeter(Ts,T1,Tmax).
maxp( T1, T2, T1 ) :- perimeter(T1,P1), perimeter(T2,P2), P1 >= P2, ! .
maxp( T1, T2, T2 ) :- perimeter(T1,P1), perimeter(T2,P2), P1 < P2
.
perimeterf( t(_,_,_,_,perimeter(P)) , P ).
由于您有一个包含 9 个点的数据集,因此有 9 * 8 * 7 个或 504 个可能的三角形。 运行这表明周长最长的三角形是
- 三角形:ADI
- 周长:103.85081399720322
平面中点的名称和坐标可以用点(A,X,Y)给出。
Prolog语言中按照这个关系定义10个点[比如point(a, 13, 47)
]创建数据库
由于其中三个点将定义一个三角形,因此创建列出这些三角形的规则。
创建一条规则,通过识别三角形中周长最大的三角形在屏幕上打印。
您已经打印出程序列表,其中包含关系和规则,三角形列表,以及最大周长的三角形。
nokta(a, 3,1).
nokta(b, 6,2).
nokta(c, 7,1).
nokta(d, 9,1).
nokta(e, 6,3).
nokta(f, 4,3).
nokta(g, 9,3).
nokta(h, 13, 47).
nokta(i, 15, 49).
istriangle(A, B, C) :-
A > 0 ,
B > 0 ,
C > 0 ,
A + B >= C ,
A + C >= B ,
B + C >= A .
calculate_the_perimeter_triangle(P1,P2,P3,AB,AC,BC,S) :-
nokta(P1, X1, Y1),
nokta(P2, X2, Y2),
nokta(P3, X3, Y3),
dif(P1, P2),
dif(P2, P3),
dif(P1, P3),
\+ (X1 == X2, X2 == X3, X1 == X3),
\+ (Y1 == Y2, Y2 == Y3, Y1 == Y3),
%IABI = √((x2 – x1) ² + (y2 – y1) ² )
AB is sqrt((X2-X1)^2 + (Y2-Y1)^2),
%IACI = √((x3 – x1) ² + (y3 – y1) ² )
AC is sqrt((X3-X1)^2 + (Y3-Y1)^2),
%IBCI = √((x3 – x2) ² + (y3 – y2) ² )
BC is sqrt((X3-X2)^2 + (Y3-Y2)^2),
S is AB + AC + BC,
AB > 0 ,
AC > 0 ,
BC > 0 .
calculate_perimeter_triangle(N1,N2,N3) :-
calculate_the_perimeter_triangle(X,Y,Z,N1,N2,N3,S),
istriangle(N1,N2,N3),
write(S - ' Bu koordinatlardan oluşan üçgen.'),
nl,
fail.
我得到了三角形的周长但是我无法得到三角形的周长
,nl,fail.
这导致 calculate_perimeter_triangle
失败,Prolog 回溯并重试。回溯之后,就好像谓词中的代码根本就没有 运行 一样,变量未绑定,状态丢失。只有使用 write()
会留下副作用(屏幕上的文本),您才能看到它的发生,但无法捕获该信息并将其保存在程序中。
你可以使用 findall/3
findall([nokta(ID1, X1, Y1), nokta(ID2, X2, Y2), nokta(ID3, X3, Y3)],
(
nokta(ID1, X1, Y1), nokta(ID2, X2, Y2), nokta(ID3, X3, Y3),
dif(ID1, ID2), dif(ID2, ID3), dif(ID3, ID1)
),
Triangles)
构建一个列表三角形,其中包含具有 3x nokta(ID, X, Y)
和不同 ID 的所有列表,然后使用这些三角形计算周长。
我可能会这样表示点,用一个方便的谓词给我一个更简洁的符号,p( Name, X:Y )
。
point( p(N,P) ) :- point(N,P).
point( a , 3 : 1 ).
point( b , 6 : 2 ).
point( c , 7 : 1 ).
point( d , 9 : 1 ).
point( e , 6 : 3 ).
point( f , 4 : 3 ).
point( g , 9 : 3 ).
point( h , 13 : 47 ).
point( i , 15 : 49 ).
然后可以通过简单地从数据库中绘制 3 个不同的点来构造一个三角形。我们可以通过
- 获得每一分
- 将所有 3 个组合成一个列表
- 使用
sort/2
对列表进行排序。
sort/2
通过删除重复元素确保列表代表 set,这确保我们不会创建三角形 AAB。那只是一个线段。
sort/2
同样,由于我们将点的名称作为输出 p/2
结构中的第一个参数,因此按规范顺序对点进行排序,因此三角形 ABC 将被视为与三角形 CBA 相同。
然后,我们使用built-in atom_chars/2
谓词,将三个点名称组合成一个原子来唯一标识三角形,并计算其周长。
最后我们把它组装成一个t/5
这种形式的结构:
t( Name, Point1, Point2, Point3, perimeter(Perimeter) )
代码如下所示:
triangle( t(N,Pa,Pb,Pc,perimeter(P)) ) :-
point(P1) ,
point(P2) ,
point(P3) ,
sort([P1,P2,P3],[p(A,Pa),p(B,Pb),p(C,Pc)]) ,
atom_chars(N,[A,B,C]),
perimeter(Pa,Pb,Pc,P) .
计算周长很简单:我们只需计算三角形每条边的长度并将它们相加即可:
perimeter( P1, P2, P3, P ) :-
distance(P1,P2,L1),
distance(P2,P3,L2),
distance(P3,P1,L3),
P is L1+L2+L3
.
并且计算线段的长度很容易:它只是笛卡尔平面上两点之间的距离,使用从勾股定理导出的距离公式:
distance( X1:Y1, X2:Y2, D ) :- D is sqrt( (X2 - X1)^2 + (Y2 - Y1)^2 ).
现在,每个三角形都带有所需的所有信息。我们可以使用 built-in set_of/3
谓词收集可以从数据库中的点集构造的三角形集:它既排序又 de-duplicates 要排序的列表:
triangles( Ts ) :- setof( T , triangle(T), Ts ).
剩下的唯一任务就是找出周长最长的三角形。这只是递归遍历列表的问题,使用 辅助谓词 将在我们进行时跟踪具有最长周长的三角形:
max_perimeter( [T|Ts] , Tmax ) :-
max_perimeter( Ts, T, Tmax ).
max_perimeter( [] , Tmax , Tmax ).
max_perimeter( [T|Ts] , T0 , Tmax ) :-
maxp(T,T0,T1),
max_perimeter(Ts,T1,Tmax).
maxp( T1, T2, T1 ) :- perimeter(T1,P1), perimeter(T2,P2), P1 >= P2, !.
maxp( T1, T2, T2 ) :- perimeter(T1,P1), perimeter(T2,P2), P1 < P2 .
perimeter( t(_,_,_,_,perimeter(P)) , P ).
然后我们可以将它们与一个 main/0
谓词放在一起来驱动它:
point( p(N,P) ) :- point(N,P).
point( a , 3: 1 ).
point( b , 6: 2 ).
point( c , 7: 1 ).
point( d , 9: 1 ).
point( e , 6: 3 ).
point( f , 4: 3 ).
point( g , 9: 3 ).
point( h , 13:47 ).
point( i , 15:49 ).
main :-
triangles(Ts) ,
list_triangles(Ts) ,
max_perimeter(Ts, Tmax),
nl(),
writeln(longest_perimeter) ,
writeln(Tmax).
triangles( Ts ) :- setof( T , triangle(T), Ts ) .
triangle( t(N,Pa,Pb,Pc,perimeter(P)) ) :-
point(P1) ,
point(P2) ,
point(P3) ,
sort([P1,P2,P3],[p(A,Pa),p(B,Pb),p(C,Pc)]) ,
atom_chars(N,[A,B,C]) ,
perimeter(Pa,Pb,Pc,P)
.
perimeter( P1, P2, P3, P ) :-
distance(P1,P2,L1),
distance(P2,P3,L2),
distance(P3,P1,L3),
P is L1+L2+L3
.
distance( X1:Y1, X2:Y2, D ) :- D is sqrt( (X2 - X1)^2 + (Y2 - Y1)^2 )
.
list_triangles( [T|Ts] ) :-
writeln(T),
list_triangles(Ts).
list_triangles( [] ).
max_perimeter( [T|Ts] , Tmax ) :-
max_perimeter( Ts, T, Tmax ).
max_perimeter( [] , Tmax , Tmax ).
max_perimeter( [T|Ts] , T0 , Tmax ) :-
maxp(T,T0,T1),
max_perimeter(Ts,T1,Tmax).
maxp( T1, T2, T1 ) :- perimeter(T1,P1), perimeter(T2,P2), P1 >= P2, ! .
maxp( T1, T2, T2 ) :- perimeter(T1,P1), perimeter(T2,P2), P1 < P2
.
perimeterf( t(_,_,_,_,perimeter(P)) , P ).
由于您有一个包含 9 个点的数据集,因此有 9 * 8 * 7 个或 504 个可能的三角形。 运行这表明周长最长的三角形是
- 三角形:ADI
- 周长:103.85081399720322