我什至从哪里开始这个序言程序?

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。

编辑: 我更新了我的代码以合并您的两个更好的想法:

  1. 我定义了 not_member/2,因此我可以 maplist 检查其他列表中的唯一项目。这是一般性和您的 unique_coin/2 之间的折衷。尽管您的 unique_coin/2 可能只是一个更好的选择。
  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 函数中的构建。希望这对您有所帮助