【问题标题】:Prolog puzzle baker, meatman and carpenterProlog 谜题面包师、肉工和木匠
【发布时间】:2014-07-10 00:47:46
【问题描述】:

这是我在网上找到的一个非常简单的谜题,我在网上找不到任何解决方案。规则很简单:

  • 有 6 位工匠,M.Baker 和他的儿子,M.Carpenter 和他的儿子,M.Meatman 和他的儿子
  • 每个工匠都可以是面包师、木匠或肉匠
  • 儿子和父亲不能做同样的工作
  • 姓氏不能是工作名称(M.Baker 和他的儿子不能是面包师)

我们知道: - M.Meatman 的儿子是面包师 - M.Baker 和 M.Carpenter 的儿子做同样的工作

我实现了这个谓词:

% swipl prolog
% M.Meatman's son is baker
% M. Baker do job of M. Carpenter's son

% jobs
job(baker).
job(meatman).
job(carpenter).

% fathers
artisan(fatherbaker).
artisan(fathercarpenter).
artisan(fathermeatman).

% sons
artisan(sonbaker).
artisan(soncarpenter).
artisan(sonmeatman).

% some links
father(fatherbaker, sonbaker).
father(fathermeatman, sonmeatman).
father(fathercarpenter, soncarpenter).

son(S, F) :- father(F, S).

same_name(fathercarpenter, soncarpenter,  carpenter).
same_name(fathermeatman, sonmeatman, meatman).
same_name(fatherbaker, sonbaker, baker).

% rules:
do_job(Artisan, Job) :-
    Artisan==sonmeatman,!, 
    artisan(Artisan),
    job(Job),
    Job=baker. % M.Meatman's son is baker (rule 1)

do_job(Artisan, Job) :- 
    Artisan==fatherbaker,!, 
    artisan(Artisan),
    job(Job),
    do_job(soncarpenter, Job). % M.Baker do M.Carpenter's son job

% not relevant...
%do_job(Artisan, Job) :-
%        Artisan == soncarpenter,!,
%   job(Job),
%   artisan(Artisan),
%        do_job(fatherbaker, Job). % rule 2 inverted

% checking if father job is not the same and name are not forgotten
do_job(Artisan, Job) :-
    artisan(Artisan),
    job(Job),
    father(Father, Artisan),
    do_job(Father, JobFather),
    Job \== JobFather,
    not(same_name(Artisan,_,Job)).

% checking if son job is not the same and name are not forgotten
do_job(Artisan, Job) :-
    artisan(Artisan),
    job(Job),
    son(Artisan, Son),
    do_job(Son, JobSon),
    Job \== JobSon,
    not(same_name(_, Artisan, Job)).

那我试试:

swipl
?- do_job(sonmeatman, X).
X = baker ;
false.
?- do_job(fatherbaker, X).
false.

你能告诉我哪里错了吗?

  • 注意:我是 Prolog 的新手。我以前从未使用过这种语言(我是 Golang、Python、C 程序员......)。
  • 注 2:请原谅我的英语,我刚刚翻译了我的法语示例,可能工作名称或动词不正确...
  • 注 3:我已经尝试过实现斑马拼图,但我意识到这比这个更容易解决……奇怪吗?

【问题讨论】:

    标签: prolog zebra-puzzle


    【解决方案1】:

    您过度设计,reifying 问题太多(典型的 Prolog 初学者错误)。你需要写的是一个六元谓词

    jobs(BakerSrJob, BakerJrJob,
         CarpenterSrJob, CarpenterJrJob,
         MeatmanSrJob, MeatmanJrJob) :-
        ...
    

    在正文中,对这些变量的约束。例如

    member(BakerJrJob, [carpenter, meatman])
    

    表示 Baker jr.要么是木匠,要么是肉工,并且

    BakerJrJob \= BakerSrJob
    

    表示贝克父子有不同的工作。这些member 调用和\= 约束中的几个应该足以编码所有必要的知识。 (只需在变量名称中硬编码人员的身份,而不是将名称表示和检查为原子。如果您刚刚开始,请不要尝试编写通用的解谜程序。)

    【讨论】:

    • 好的,今晚我会检查一下(法国是 14:50 :)) - 我很确定你是对的,准确地说,我之前尝试过其他一些例子......我对层次解析、路径解析等没有任何问题……我只是尝试阅读文档、测试等等。
    • 经过一些测试,我确实填充这种方式比CappelliC解决方案“更简单”。它易读、易于理解并且只返回一个解决方案。 CapelliC 解决方案很好,但返回许多相同但顺序不同的解决方案。
    【解决方案2】:

    我认为你这里有错误

    ...
    son(Artisan, Son),
    ...
    

    正如您将儿子/2 关系定义为儿子(儿子,父亲)

    edit 说,我会以完全不同的方式解决

    solve(Puzzle) :-
        % There are 6 artisans, M.Baker and his son, M.Carpenter and his son and M.Meatman and his son
        Puzzle = [N1/F1/S1, N2/F2/S2, N3/F3/S3],
    
        % Each artisan can be baker, carpenter or meatman
        Symbols = [baker, carpenter, meatman],
        permutation([N1,N2,N3], Symbols),
        permutation([F1,F2,F3], Symbols),
        permutation([S1,S2,S3], Symbols),
    
        % Son and father cannot do the same job
        foreach(member(_/F/S, Puzzle), F\=S),
    
        % The lastname couldn't be the job name
        foreach(member(N/F/S, Puzzle), (N\=F, N\=S)),
    
        % M.Meatman's son is baker
        member(meatman/_/baker, Puzzle),
    
        % M.Baker do the same job than M.Carpenter's son
        member(baker/J/_, Puzzle),
        member(carpenter/_/J, Puzzle).
    

    foreach/2 这是一个棘手的谓词,您可以尝试用自己的(递归)定义替换。 permutation/2 更简单,可以轻松替换...

    最后一点:“注 3:我已经尝试过实现斑马拼图,但我意识到解决这个问题比这个更简单......奇怪?”是的,这很奇怪,我认为斑马拼图要复杂得多比这个

    【讨论】:

    • "如果Goal 不包含任何不与Generator 共享的变量,则实现执行forall/2。"看起来 forall 可以用在那里代替。
    • @WillNess:你说得对,我的错
    • 不知道 X/Y/Z 表示法,与 python 元组相媲美...真不错!
    • @Metal3d:您可以在 Prolog 中使用任何 binop 作为对构造函数。 a+b+c 也可以,或者(A, B, C)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-03
    • 2017-10-29
    • 1970-01-01
    • 1970-01-01
    • 2016-12-20
    • 1970-01-01
    • 2013-06-03
    相关资源
    最近更新 更多