如何解决';6本书';用Prolog解谜?
我刚刚在math.SE()上看到了这个问题: 六本大小相同的书(A、B、C、D、E、F)如图所示堆叠在一起 图为: 我们知道以下事实:如何解决';6本书';用Prolog解谜?,prolog,Prolog,我刚刚在math.SE()上看到了这个问题: 六本大小相同的书(A、B、C、D、E、F)如图所示堆叠在一起 图为: 我们知道以下事实: A和D不接触 E位于两本书之间,两本书都是垂直的或水平的 C正好接触到两本书 A和F触摸 E和F沿其盖接触(长侧) 有多少本书知道它们的位置 我想我可以用Prolog解决这个问题: % Those are the books: book(a). book(b). book(c). book(d). book(e). book(f). % This is ho
% Those are the books:
book(a).
book(b).
book(c).
book(d).
book(e).
book(f).
% This is how 'touching' works:
touching(X,Y):- touching(Y,X). % touching is symmetric
touching(p1,p2).
touching(p2,p3).
touching(p3,p4).
touching(p3,p5).
touching(p3,p6).
touching(p4,p5).
touching(p5,p6).
% List all possible positions:
position(a):- p1,p2,p3,p4,p5,p6.
position(b):- p1,p2,p3,p4,p5,p6.
position(c):- p1,p2,p3,p4,p5,p6.
position(d):- p1,p2,p3,p4,p5,p6.
position(e):- p1,p2,p3,p4,p5,p6.
position(f):- p1,p2,p3,p4,p5,p6.
% Every position has one book
getBook(p1) :- a,b,c,d,e,f.
getBook(p2) :- a,b,c,d,e,f.
getBook(p3) :- a,b,c,d,e,f.
getBook(p4) :- a,b,c,d,e,f.
getBook(p5) :- a,b,c,d,e,f.
getBook(p6) :- a,b,c,d,e,f.
% Add your facts:
not(touching(position(a),position(d))).
position(e):- p5,p2.
% C touches exactly two books: eventually something like aggregate_all(count, touching(e,X), Count):-2.
position(c):- p2, p4,p6.
touching(position(a),position(f)).
touching(position(e),position(f)).
但当我尝试位置(a)
时,我得到:
?- consult(books).
Warning: /home/moose/Downloads/LaTeX-examples/documents/Programmierparadigmen/scripts/prolog/books.pl:37:
Clauses of position/1 are not together in the source-file
Warning: /home/moose/Downloads/LaTeX-examples/documents/Programmierparadigmen/scripts/prolog/books.pl:40:
Clauses of touching/2 are not together in the source-file
% books compiled 0.00 sec, 32 clauses
true.
?- position(a).
ERROR: position/1: Undefined procedure: p1/0
Exception: (7) p1 ?
- 问题1:为什么会出现异常,如何修复
- 问题2:有没有一种更接近文本的方法来描述序言中的事实3
- 问题3:如何打印所有组合
- 关键在于此。您需要使用满足特定约束的逻辑变量查找
[1,2,3,4,5,6]
的排列,标记为[A,B,C,D,E,F]
。约束是书本接触和书本水平或垂直对齐。我们掌握的事实是
vert(1).
vert(2).
vert(3).
horz(4).
horz(5).
horz(6).
以及书籍之间的一些关系,即
touch(3, 4).
touch(3, 5).
touch(3, 6).
touch_long(1, 2).
touch_long(2, 3).
touch_long(4, 5).
touch_long(5, 6).
touching(X, Y) :-
touch(X, Y) ; touch(Y, X); touching_long(X, Y).
touching_long(X, Y) :-
touch_long(X, Y) ; touch_long(Y, X).
蛮力方法(对于这样一个小问题来说足够了)就是生成置换并检查约束。这在Prolog编程中称为生成和测试方法
% books(A, B, C, D, E, F) unifies its variables with the
% integers 1 through 6 to meet the constraints.
books(A, B, C, D, E, F) :-
permutation([1, 2, 3, 4, 5, 6], [A, B, C, D, E, F]),
% 1. A and D are not touching.
\+ touching(A, D),
% 2. E is between two books which are both vertical or both horizontal.
% We can take a shortcut by exploiting the asymmetry in touch_long.
touch_long(_, E),
touch_long(E, _),
% 3. C touches exactly two books. That means that the set of all books
% touching C has cardinality 2.
setof(X, touching(X, C), TouchingC),
length(TouchingC, 2),
% 4. A and F touch.
touching(A, F),
% 5. E and F touch along their cover (long side).
touching_long(E, F).
您现在可以运行书籍(A、B、C、D、E、F)
生成有效排列:
?- books(A,B,C,D,E,F).
A = 3,
B = 2,
C = 4,
D = 1,
E = 5,
F = 6 ;
A = 3,
B = 2,
C = 6,
D = 1,
E = 5,
F = 4
等。可以通过观察输出来解决原始问题;为原始程序编写一个全自动的解决方案只是一个练习(这有点乏味)。这里是关键。您需要使用满足特定约束的逻辑变量查找
[1,2,3,4,5,6]
的排列,标记为[A,B,C,D,E,F]
。约束是书本接触和书本水平或垂直对齐。我们掌握的事实是
vert(1).
vert(2).
vert(3).
horz(4).
horz(5).
horz(6).
以及书籍之间的一些关系,即
touch(3, 4).
touch(3, 5).
touch(3, 6).
touch_long(1, 2).
touch_long(2, 3).
touch_long(4, 5).
touch_long(5, 6).
touching(X, Y) :-
touch(X, Y) ; touch(Y, X); touching_long(X, Y).
touching_long(X, Y) :-
touch_long(X, Y) ; touch_long(Y, X).
蛮力方法(对于这样一个小问题来说足够了)就是生成置换并检查约束。这在Prolog编程中称为生成和测试方法
% books(A, B, C, D, E, F) unifies its variables with the
% integers 1 through 6 to meet the constraints.
books(A, B, C, D, E, F) :-
permutation([1, 2, 3, 4, 5, 6], [A, B, C, D, E, F]),
% 1. A and D are not touching.
\+ touching(A, D),
% 2. E is between two books which are both vertical or both horizontal.
% We can take a shortcut by exploiting the asymmetry in touch_long.
touch_long(_, E),
touch_long(E, _),
% 3. C touches exactly two books. That means that the set of all books
% touching C has cardinality 2.
setof(X, touching(X, C), TouchingC),
length(TouchingC, 2),
% 4. A and F touch.
touching(A, F),
% 5. E and F touch along their cover (long side).
touching_long(E, F).
您现在可以运行书籍(A、B、C、D、E、F)
生成有效排列:
?- books(A,B,C,D,E,F).
A = 3,
B = 2,
C = 4,
D = 1,
E = 5,
F = 6 ;
A = 3,
B = 2,
C = 6,
D = 1,
E = 5,
F = 4
等。可以通过观察输出来解决原始问题;为原始程序编写一个全自动的解决方案只是一个练习(有点乏味)。编辑:修复了一个错误(关于“E和F沿封面(长边)触摸”的规则)使用了D而不是F 使用ECLiPSe CLP Prolog的约束编程解决方案:
:- lib(gfd).
model(Books) :-
[A, B, C, D, E, F] = Books,
Books :: 1..6,
alldifferent(Books),
% A and D are not touching.
abs(A - D) #\= 1, (A #= 3) => (D #< 4), (D #= 3) => (A #< 4),
% E is between two books which are both vertical or both horizontal.
E :: [2, 5],
% C touches exactly two books.
C :: [2, 4, 6],
% A and F touch.
(abs(A - F) #= 1) or (A #= 3 and F #> 4) or (F #= 3 and A #> 4),
% E and F touch along their cover (long side)
abs(E - F) #= 1, (E #> 3) => (F #> 3), (E #< 4) => (F #< 4).
find(Books) :-
findall(Books, (model(Books), labeling(Books)), Sols),
table(Books, Sols).
因此,只有书D知道位置-1。编辑:修复了一个错误(关于“E和F沿封面(长边)接触”的规则)使用了D而不是F 使用ECLiPSe CLP Prolog的约束编程解决方案:
:- lib(gfd).
model(Books) :-
[A, B, C, D, E, F] = Books,
Books :: 1..6,
alldifferent(Books),
% A and D are not touching.
abs(A - D) #\= 1, (A #= 3) => (D #< 4), (D #= 3) => (A #< 4),
% E is between two books which are both vertical or both horizontal.
E :: [2, 5],
% C touches exactly two books.
C :: [2, 4, 6],
% A and F touch.
(abs(A - F) #= 1) or (A #= 3 and F #> 4) or (F #= 3 and A #> 4),
% E and F touch along their cover (long side)
abs(E - F) #= 1, (E #> 3) => (F #> 3), (E #< 4) => (F #< 4).
find(Books) :-
findall(Books, (model(Books), labeling(Books)), Sols),
table(Books, Sols).
所以,只有D本书知道位置-1。您还没有定义
p1
事实。要解决这个问题,您需要以完全不同的方式设置程序。您能解释一下如何解决这个问题吗?我是Prolog新手,目前不知道解决此问题的其他方法。例外情况是,您没有名为p1
且没有参数的事实或谓词。您将在p2
到p6
中遇到相同的异常<代码>位置(a):-p1、p2、p3、p4、p5、p6。尝试以谓词或事实的形式查询p1
等,但它们本身并不存在。您尚未定义p1
事实。要解决这个问题,您需要以完全不同的方式设置程序。您能解释一下如何解决这个问题吗?我是Prolog新手,目前不知道解决此问题的其他方法。例外情况是,您没有名为p1
且没有参数的事实或谓词。您将在p2
到p6
中遇到相同的异常<代码>位置(a):-p1、p2、p3、p4、p5、p6。尝试以谓词或事实的形式查询p1
等,但它们本身并不存在。\+
中的\+
是什么?从上下文来看,我会说它有点像not
,但写“not”是一种奇怪的方式。@moose,它是“not”,看起来确实有点奇怪,但它是prolog语法。有些序言(如SWI序言)允许not/1
@moose It's negation。我想它应该代表一个⊢ (“provable”)带有斜杠。在\+触摸(a,D),
中什么是\+
?从上下文来看,我会说它有点像not
,但写“not”是一种奇怪的方式。@moose,它是“not”,看起来确实有点奇怪,但它是prolog语法。有些序言(如SWI序言)允许not/1
@moose It's negation。我想它应该代表一个⊢ (“provable”)带有斜杠。它约束双方的值相等@SergeyDymchenko如何打印出所有可能的配置?@Maesumifindall(书籍,(模型(书籍),标签(书籍),writeln(书籍)),Sols)。
@SergeyDymchenko推荐的免费windows程序是什么,可以处理上述文件?@Maesumi ECLiPSe CLP在windows上工作。您可以从it下载它来约束两边的值相等@SergeyDymchenko如何打印出所有可能的配置?@Maesumifindall(书籍,(模型(书籍),标签(书籍),writeln(书籍)),Sols)。
@SergeyDymchenko推荐的免费windows程序是什么,可以处理上述文件?@Maesumi ECLiPSe CLP在windows上工作。你可以从