Prolog 桌上有六个座位

Prolog 桌上有六个座位,prolog,Prolog,我想限制坐在桌子旁的人数(准确地说是6人),但用prolog我不知道怎么做 我已经尝试在(0,5,W)之间使用, 但我不明白为什么每次使用活动跟踪时,我都会看到它随着W的增加而前进,但它无法退出下一个函数 (W =: = 0 -> nb_setval (counter, 0), W is 5, 我希望函数在lf之后继续(在prolog中应该是“->”),但它始终保持在那里,不继续。我可以插入跟踪返回给我的内容。我有一个不完整的解决方案。但我希望这足以给你一些希望,让你解决剩下的问题。首先

我想限制坐在桌子旁的人数(准确地说是6人),但用prolog我不知道怎么做

我已经尝试在(0,5,W)之间使用
但我不明白为什么每次使用活动跟踪时,我都会看到它随着W的增加而前进,但它无法退出下一个函数

(W =: = 0 -> nb_setval (counter, 0), W is 5,

我希望函数在lf之后继续(在prolog中应该是“->”),但它始终保持在那里,不继续。我可以插入跟踪返回给我的内容。

我有一个不完整的解决方案。但我希望这足以给你一些希望,让你解决剩下的问题。首先,我稍微回顾了一下您的数据模型:

family(antonella,1).
family(domenico,1).
family(raffaella,1).
family(tommaso,1).
family(vincenzo,1).

family(azzurra,2).
family(cristiano,2).
family(francesca,2).
family(luigi,2).
此外,我还删除了
notinfamily/1
,因为您有一个人不在家或不在家,这花费了我一些调试时间最好推断一下

接下来我们需要几个帮手。首先,为您的数据模型提供一些帮助,以便更容易地确定家庭是否匹配或人们是否在打架。这些应该是相当简单易懂的,我只是确保这些族实际上匹配,或者其中一个不在一个族中(我们用否定而不是
notinfamily/1
)进行检查:

战斗目前不是关联的,所以我做了一个单独的关联谓词:

fighting(X, Y) :- fight(X, Y) ; fight(Y, X).
最初我使用的是
select/3
,这是从列表中提取各种项目的一种很好的方法,但我意识到做不同的排列会让我很痛苦,所以我提出了这个版本,我只能用来生成组合:

select_inorder(X, [X|Xs], Xs).
select_inorder(X, [_|Rem], Xs) :-
    select_inorder(X, Rem, Xs).
这个谓词的用法将在一秒钟内变得清晰

如果可以避免的话,我宁愿不在Prolog中使用算术。乍一看,这就像一个案例,你可以假设有三张五人桌,一切都会很好。事实证明并非如此,但我想我还是会分享我编写的代码,以防它帮助你解决问题。我的计划是这样的:我将有一个谓词,它知道它正在集合一个由五个人组成的列表。我将首先将您的数据库转换为人员列表。我将从列表中选择人员。当我有五个表时,我将验证该表是否有效。我将有一个主谓词来做簿记并运行这个表生成器三次

seating([T1,T2,T3]) :-
    findall(X, person(X), People),
    make_table(People, T1, R1),
    make_table(R1, T2, R2),
    make_table(R2, T3, []).
这可能可以用DCG语法更清楚地重申。但这在你看来应该是明智的。制作桌子也有类似的味道:

make_table(People, [A,B,C,D,E], Unseated) :-
    select_inorder(A, People, P1),
    select_inorder(B, P1, P2),
    select_inorder(C, P2, P3),
    select_inorder(D, P3, P4),
    select_inorder(E, P4, Unseated),
    safe_table([A,B,C,D,E]).
select_inoorder/3
用于确保我们按顺序选择人员,否则我们只会浪费处理时间。一旦我们有了五个人,我们就会核实。这是一个经典的“生成测试”循环

我有点喜欢这里的逻辑解读。这不是超高效的,它将对列表中的所有项进行叉积。然而,我认为这样的事情可能是有道理的,因为家庭匹配是不可传递的(
family\u匹配(antonella,giovanni),家庭匹配(giovanni,Azzura)
是正确的,但是
family\u匹配(antonella,Azzura)
不是正确的)

当然,令人沮丧的是这不起作用。但它不起作用的原因很简单:在我们把一家人都放在一张桌子上,把二家人都放在另一张桌子上之后,我们有一个人移动到他们的桌子上,然后我们必须找到剩下的五个人的组合坐在一起。但不幸的是,三个不在一个家庭中的人正在互相争斗。如果你能让marcella和daniela相处融洽,你将得到一个解决方案:

?- seating([T1,T2,T3]).
T1 = [antonella, domenico, raffaella, tommaso, vincenzo],
T2 = [azzurra, cristiano, francesca, luigi, giovanni],
T3 = [marcella, daniela, nunzio, leonardo, silvia] ;
false.

对我来说,为不完整的表做这项工作听起来有点乏味,所以我将把它放在这里,希望它仍然对您有所帮助。

从如何建模数据开始。你现在的方式有点傻。另外,放下所有的
nb.*
东西,你当然不需要它。最后,您可能希望从阅读教程或教科书开始。你可以尝试“现在就学习Prolog!”或“Prolog的艺术”(你可以在书的网站上免费下载PDF)。好的,谢谢,我试着从这里开始学习,看看是否能找到解决方案。我在这里看到的唯一明显的代表性问题是家庭内容;相反,我会说类似于
family(antonella,a)。
family(Azzura,b)。
如果你知道实际的姓氏,使用它们,你也可以在那里编号。您不需要显式地建模
notinfamily/1
。但是是的,
nb_setval
和朋友是在非常特殊的情况下,而不是在这种情况下。不过,你确实需要一种方法来记录谁坐了,谁没坐。非常感谢你,更好地理解如何解决这个问题非常有用。最后一个问题:在两小时的考试中做这个练习,你对prolog应该了解多少?@MicheleSpedalieri我不知道如何回答这个问题。这不是一个完全无关紧要的问题。我希望如果你已经做了一个月左右的Prolog,你也许能做到。几天的紧张学习,我有点怀疑,但你永远不知道。
make_table(People, [A,B,C,D,E], Unseated) :-
    select_inorder(A, People, P1),
    select_inorder(B, P1, P2),
    select_inorder(C, P2, P3),
    select_inorder(D, P3, P4),
    select_inorder(E, P4, Unseated),
    safe_table([A,B,C,D,E]).
safe_table(Table) :-
    forall((member(L, Table), member(R, Table)),
           (family_matches(L, R), \+ fighting(L, R))).
?- seating([T1,T2,T3]).
T1 = [antonella, domenico, raffaella, tommaso, vincenzo],
T2 = [azzurra, cristiano, francesca, luigi, giovanni],
T3 = [marcella, daniela, nunzio, leonardo, silvia] ;
false.