我什至从哪里开始这个序言程序?
where do i even start with this prolog program?
我花时间好好翻译了
面前有四个人:男魔法师、女魔法师、巫师
和。每个人有一袋一枚或多枚硬币。
硬币由青铜、铜、黄铜或锡制成。
哪个袋子里的硬币最少?
鉴于:
1 - 没有两袋内容相同。
2 – 一个袋子里不能有两枚相同的硬币。
3 - 一个袋子可以装一枚、两枚或四枚硬币。
4 - 巫师和男魔术师各有一枚硬币,其他三人
none 都有。
5 - 所有没有黄铜硬币的袋子都包含一枚青铜硬币。
6 - 所有没有锡币的袋子也不包含铜币。
使用深度优先搜索创建一个 Prolog 程序来找到这个问题的解决方案
我不知道从这里去哪里
coin(bronze).
coin(copper).
coin(brass).
coin(tin).
% 5: All bags without a brass coin contain a bronze coin.
hint_1(B) :- \+ \+ ( memberchk(brass, B) ; memberchk(bronze, B) ).
% 6: All bags without tin coins do not contain a bronze coin either.
hint_2(B) :- \+ ( \+ memberchk(tin, B), memberchk(bronze, B) ).
unique_coin(Us, Bags) :-
member(U, Us),
\+ (member(Bag, Bags), memberchk(U, Bag)).
bag(Cs) :-
% 3: A bag can contain either one, two or four coins
member(L, [1,2,4]), length(Cs, L),
% 2: In a bag, there cannot be two of the same coins.
foldl(ascending_coin, Cs, _, _).
ascending_coin(C, Prev, C) :-
coin(C),
Prev @< C..
%All bags are different
all_dif([]).
all_dif([L|Ls]) :-
maplist(dif(L), Ls),
all_dif(Ls).
bags(Bs) :-
Bs = [MM,FM,Wizard,Witch],
maplist(bag, Bs),
% 1: There are no two bags of identical content
all_dif(Bs),
% 4: The Wizard and the male magician each have a unique coin.
unique_coin(Wizard, [MM,FM,Witch]),
unique_coin(MM, [FM,Wizard,Witch]),
maplist(hint_1, Bs),
maplist(hint_2, Bs).
这是我尝试的解决方案。它似乎有效,但我对这类谜题的练习不是很好。带有 #n
的注释表明该行中的代码旨在解决您的谜题中的规则 n。
编辑: 我更新了我的代码以合并您的两个更好的想法:
- 我定义了
not_member/2
,因此我可以 maplist
检查其他列表中的唯一项目。这是一般性和您的 unique_coin/2
之间的折衷。尽管您的 unique_coin/2
可能只是一个更好的选择。
- 跟着你,我将我的条件句(执行 "if a list doesn't have a brass coin..." 规则)翻译成析取。
bag_with_fewest_coins(Answers) :-
Bags = [A, B, C, D], % there are four bags...
maplist(coin_bag, Bags), % ... of coins
is_set(Bags), % #1
member(MemA, A), maplist(not_member(MemA), [B,C,D]), % #4
member(MemB, B), maplist(not_member(MemB), [A,C,D]), % #4
predsort(compare_lengths, Bags, [Answer|_]). % Answer is shortest list.
not_member(X, Ys) :-
\+ member(X, Ys).
%% To be used with predsort/3:
compare_lengths(Comp, A, B) :-
length(A, LenA), length(B, LenB),
compare(Comp, LenA, LenB). % Per @mat's suggestion in comments.
coin_bag(Bag) :-
Coins = [bronze, copper, brass, tin], % types of coins
member(Len, [1,2,4]), length(Bag, Len), % #3
set_subset(Coins, Bag), % #2
(member(brass, Bag) ; member(bronze, Bag)), % #5
(member(tin, Bag) ; \+ member(bronze, Bag)). % #6
% Taken form gusbro's SO answer:
% For the purposes of this predicate, each element of Set is thought of as
% distinct, qua differentiable entity, regardless of whether it would unify,
% equate with, or otherwise match another element in Set.
set_subset([], []).
set_subset([X|Set], [X|Subset]) :-
set_subset(Set, Subset).
set_subset([_|Set], Subset) :-
set_subset(Set, Subset).
然后,根据@mat 在评论中的建议,我们可以使用 set_of/3
来确保我们收集到所有不同的答案:
?- setof(B, bag_with_fewest_coins(B), Answers).
Answers = [[brass]].
这表明只有一个唯一的答案。
这些提示与以前版本的问题有关。我留下它们以防它们将来对某人有帮助:
对规则和事实使用描述性很强的名称会很有帮助。 rule
没有帮助,因为它没有告诉我们我们正在描述什么样的规则。在 Prolog 中,<head> :- <body>.
形式的任何东西都是规则,因此我们知道某物是基于其语法的规则。这让我们可以自由地为我们的规则命名一些描述性的东西,例如 bag_contents
.
你的一些规则对我来说意义不大,我认为这是因为你对 Prolog 中的表达式有些误解。因此,这里有一些关于您的规则的提示:
我想你的意思是这条规则说 "M2 is the first element of a list and it is a either a list with length 2, or a list with length 4":
rule(M2,[M2|_]):- length(M2,X), X=2; X = 4.
但实际上是"M2 has length X and X = 2, or X = 4",这是因为第;/2
运算符的优先级大于,/2
运算符的优先级。因此,您需要使用括号以正确的方式对表达式进行分组,例如:length(M2,X), (X=2; X = 4)
.
此规则的第二个析取永远不会成功:
rule([A|B]):- length(A,Y), Y= 1; Y = 2, Y=4, rule(B).
因为第二部分(在;
之后)读取"Y = 2 and Y = 4 and rule(B)",但是如果Y = 2
然后\+ Y = 4
,所以它总是会失败。
因此,我的进一步改进建议是为您的规则提供描述性的、不同的名称,更正某些条款中有缺陷的逻辑,并尝试设置您可以随时在顶层测试规则的案例。
尝试http://swish.swi-prolog.org/ 这会起作用.. SWI-Prolog 桌面版可能有一些问题。桌面版 veriosn 无法检查 memberchek 和 foldl 函数中的构建。希望这对您有所帮助
我花时间好好翻译了
面前有四个人:男魔法师、女魔法师、巫师
和。每个人有一袋一枚或多枚硬币。
硬币由青铜、铜、黄铜或锡制成。
哪个袋子里的硬币最少?
鉴于:
1 - 没有两袋内容相同。
2 – 一个袋子里不能有两枚相同的硬币。
3 - 一个袋子可以装一枚、两枚或四枚硬币。
4 - 巫师和男魔术师各有一枚硬币,其他三人
none 都有。
5 - 所有没有黄铜硬币的袋子都包含一枚青铜硬币。
6 - 所有没有锡币的袋子也不包含铜币。
使用深度优先搜索创建一个 Prolog 程序来找到这个问题的解决方案
我不知道从这里去哪里
coin(bronze).
coin(copper).
coin(brass).
coin(tin).
% 5: All bags without a brass coin contain a bronze coin.
hint_1(B) :- \+ \+ ( memberchk(brass, B) ; memberchk(bronze, B) ).
% 6: All bags without tin coins do not contain a bronze coin either.
hint_2(B) :- \+ ( \+ memberchk(tin, B), memberchk(bronze, B) ).
unique_coin(Us, Bags) :-
member(U, Us),
\+ (member(Bag, Bags), memberchk(U, Bag)).
bag(Cs) :-
% 3: A bag can contain either one, two or four coins
member(L, [1,2,4]), length(Cs, L),
% 2: In a bag, there cannot be two of the same coins.
foldl(ascending_coin, Cs, _, _).
ascending_coin(C, Prev, C) :-
coin(C),
Prev @< C..
%All bags are different
all_dif([]).
all_dif([L|Ls]) :-
maplist(dif(L), Ls),
all_dif(Ls).
bags(Bs) :-
Bs = [MM,FM,Wizard,Witch],
maplist(bag, Bs),
% 1: There are no two bags of identical content
all_dif(Bs),
% 4: The Wizard and the male magician each have a unique coin.
unique_coin(Wizard, [MM,FM,Witch]),
unique_coin(MM, [FM,Wizard,Witch]),
maplist(hint_1, Bs),
maplist(hint_2, Bs).
这是我尝试的解决方案。它似乎有效,但我对这类谜题的练习不是很好。带有 #n
的注释表明该行中的代码旨在解决您的谜题中的规则 n。
编辑: 我更新了我的代码以合并您的两个更好的想法:
- 我定义了
not_member/2
,因此我可以maplist
检查其他列表中的唯一项目。这是一般性和您的unique_coin/2
之间的折衷。尽管您的unique_coin/2
可能只是一个更好的选择。 - 跟着你,我将我的条件句(执行 "if a list doesn't have a brass coin..." 规则)翻译成析取。
bag_with_fewest_coins(Answers) :-
Bags = [A, B, C, D], % there are four bags...
maplist(coin_bag, Bags), % ... of coins
is_set(Bags), % #1
member(MemA, A), maplist(not_member(MemA), [B,C,D]), % #4
member(MemB, B), maplist(not_member(MemB), [A,C,D]), % #4
predsort(compare_lengths, Bags, [Answer|_]). % Answer is shortest list.
not_member(X, Ys) :-
\+ member(X, Ys).
%% To be used with predsort/3:
compare_lengths(Comp, A, B) :-
length(A, LenA), length(B, LenB),
compare(Comp, LenA, LenB). % Per @mat's suggestion in comments.
coin_bag(Bag) :-
Coins = [bronze, copper, brass, tin], % types of coins
member(Len, [1,2,4]), length(Bag, Len), % #3
set_subset(Coins, Bag), % #2
(member(brass, Bag) ; member(bronze, Bag)), % #5
(member(tin, Bag) ; \+ member(bronze, Bag)). % #6
% Taken form gusbro's SO answer:
% For the purposes of this predicate, each element of Set is thought of as
% distinct, qua differentiable entity, regardless of whether it would unify,
% equate with, or otherwise match another element in Set.
set_subset([], []).
set_subset([X|Set], [X|Subset]) :-
set_subset(Set, Subset).
set_subset([_|Set], Subset) :-
set_subset(Set, Subset).
然后,根据@mat 在评论中的建议,我们可以使用 set_of/3
来确保我们收集到所有不同的答案:
?- setof(B, bag_with_fewest_coins(B), Answers).
Answers = [[brass]].
这表明只有一个唯一的答案。
这些提示与以前版本的问题有关。我留下它们以防它们将来对某人有帮助:
对规则和事实使用描述性很强的名称会很有帮助。 rule
没有帮助,因为它没有告诉我们我们正在描述什么样的规则。在 Prolog 中,<head> :- <body>.
形式的任何东西都是规则,因此我们知道某物是基于其语法的规则。这让我们可以自由地为我们的规则命名一些描述性的东西,例如 bag_contents
.
你的一些规则对我来说意义不大,我认为这是因为你对 Prolog 中的表达式有些误解。因此,这里有一些关于您的规则的提示:
我想你的意思是这条规则说 "M2 is the first element of a list and it is a either a list with length 2, or a list with length 4":
rule(M2,[M2|_]):- length(M2,X), X=2; X = 4.
但实际上是"M2 has length X and X = 2, or X = 4",这是因为第;/2
运算符的优先级大于,/2
运算符的优先级。因此,您需要使用括号以正确的方式对表达式进行分组,例如:length(M2,X), (X=2; X = 4)
.
此规则的第二个析取永远不会成功:
rule([A|B]):- length(A,Y), Y= 1; Y = 2, Y=4, rule(B).
因为第二部分(在;
之后)读取"Y = 2 and Y = 4 and rule(B)",但是如果Y = 2
然后\+ Y = 4
,所以它总是会失败。
因此,我的进一步改进建议是为您的规则提供描述性的、不同的名称,更正某些条款中有缺陷的逻辑,并尝试设置您可以随时在顶层测试规则的案例。
尝试http://swish.swi-prolog.org/ 这会起作用.. SWI-Prolog 桌面版可能有一些问题。桌面版 veriosn 无法检查 memberchek 和 foldl 函数中的构建。希望这对您有所帮助