Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Prolog中的锁挑战_Prolog - Fatal编程技术网

Prolog中的锁挑战

Prolog中的锁挑战,prolog,Prolog,我刚开始学习prolog,我一直在努力解决这个难题: 我试图添加一些类似于此示例的规则,但我找不到解决方案 到目前为止,我尝试的是: % Render the houses term as a nice table. :- use_rendering(table, [header(h('N1', 'N2', 'N3'))]). numbers(Hs) :- length(Hs, 1), member(h(6,8,2), Hs), member(h(6,

我刚开始学习prolog,我一直在努力解决这个难题:

我试图添加一些类似于此示例的规则,但我找不到解决方案

到目前为止,我尝试的是:

% Render the houses term as a nice table.
:- use_rendering(table,
         [header(h('N1', 'N2', 'N3'))]).
numbers(Hs) :-
    length(Hs, 1),
    member(h(6,8,2), Hs),
    member(h(6,1,4), Hs),
    member(h(2,0,6), Hs),
    member(h(7,3,8), Hs),
    member(h(7,8,0), Hs),
    correct_and_placed(6, 8, 2, Hs).

correct_and_place(A, B, C, R).

但我甚至不知道如何编写一条规则来检查一个数字是否正确,是否在正确的位置。

我不确定是否需要解释这么多。生成所有可能性,然后对约束进行编码

code(A,B,C) :-
  member(A,[0,1,2,3,4,5,6,7,8,9]),
  member(B,[0,1,2,3,4,5,6,7,8,9]),
  member(C,[0,1,2,3,4,5,6,7,8,9]),
  ( A = 6 ; B = 8 ; C = 2 ),
  ( A = 1, \+ member(B,[6,4]), \+ member(C,[6,4])
  ; A = 4, \+ member(B,[6,1]), \+ member(C,[6,1])
  ; B = 6, \+ member(A,[1,4]), \+ member(C,[1,4])
  ; B = 4, \+ member(A,[6,1]), \+ member(C,[6,1])
  ; C = 6, \+ member(B,[1,4]), \+ member(A,[1,4])
  ; C = 1, \+ member(B,[6,4]), \+ member(A,[6,4]) ),
  ( A = 0, B = 2, C \= 6
  ; A = 0, B = 6, C \= 2
  ; A = 6, B = 2, C \= 0
  ; B = 2, C = 0, A \= 6
  ; B = 6, C = 2, A \= 0
  ; B = 6, C = 0, A \= 2
  ; C = 2, A = 0, B \= 6
  ; C = 2, A = 6, B \= 0
  ; C = 0, A = 6, B \= 2 ),
  \+ member(A,[7,3,8]), \+ member(B,[7,3,8]), \+ member(C,[7,3,8]),
  ( A = 8, \+ member(B,[7,0]), \+ member(C,[7,0])
  ; A = 0, \+ member(B,[7,8]), \+ member(C,[7,8])
  ; B = 7, \+ member(A,[8,0]), \+ member(C,[8,0])
  ; B = 0, \+ member(A,[7,8]), \+ member(C,[7,8])
  ; C = 7, \+ member(B,[8,0]), \+ member(A,[8,0])
  ; C = 8, \+ member(B,[7,0]), \+ member(A,[7,0]) ).
结果如下:

| ?- code(A,B,C).
A = 0,
B = 4,
C = 2 ? ;
no

我希望有更好的方法,但是

您可以按如下方式实现“一个数字正确且位置正确”

oneRightPlace(X, Y, Z, X, S2, S3) :-
  \+ member(Y, [S2, S3]),
  \+ member(Z, [S2, S3]).

oneRightPlace(X, Y, Z, S1, Y, S3) :-
  \+ member(X, [S1, S3]),
  \+ member(Z, [S1, S3]).

oneRightPlace(X, Y, Z, S1, S2, Z) :-
  \+ member(X, [S1, S2]),
  \+ member(Y, [S1, S2]).
对于“一个数字正确但位置错误,您可以使用

oneWrongPlace(X, Y, Z, S1, S2, S3) :-
  member(X, [S2, S3]),
  \+ member(Y, [S1, S2, S3]),
  \+ member(Z, [S1, S2, S3]).

oneWrongPlace(X, Y, Z, S1, S2, S3) :-
  member(Y, [S1, S3]),
  \+ member(X, [S1, S2, S3]),
  \+ member(Z, [S1, S2, S3]).

oneWrongPlace(X, Y, Z, S1, S2, S3) :-
  member(Z, [S1, S2]),
  \+ member(X, [S1, S2, S3]),
  \+ member(Y, [S1, S2, S3]).
对于“两个数字正确但位置错误”,您可以这样写

twoWrongPlace(X, Y, Z, S1, S2, S3) :-
  member(X, [S2, S3]),
  member(Y, [S1, S3]),
  \+ member(Z, [S1, S2, S3]).

twoWrongPlace(X, Y, Z, S1, S2, S3) :-
  member(X, [S2, S3]),
  member(Z, [S1, S2]),
  \+ member(Y, [S1, S2, S3]).

twoWrongPlace(X, Y, Z, S1, S2, S3) :-
  member(Y, [S1, S3]),
  member(Z, [S1, S2]),
  \+ member(X, [S1, S2, S3]).
并且,因为“没有什么是正确的”,变得简单

zeroPlace(X, Y, Z, S1, S2, S3) :-
  \+ member(X, [S1, S2, S3]),
  \+ member(Y, [S1, S2, S3]),
  \+ member(Z, [S1, S2, S3]).
现在你可以把所有的东西放在一起写了

  member(S1, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
  member(S2, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
  member(S3, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
  oneRightPlace(6, 8, 2, S1, S2, S3),
  oneWrongPlace(6, 1, 4, S1, S2, S3),
  twoWrongPlace(2, 0, 6, S1, S2, S3),
  zeroPlace(7, 3, 8, S1, S2, S3),
  oneWrongPlace(7, 8, 0, S1, S2, S3).
获取(在
S1
S2
S3
中)正确的解决方案


前面的例子没有使用clp(fd)编写,我不太清楚,但(我想)可能会有很大的意义。

因此,与所有这方面的问题一样,我倾向于编写一个通用的解算器,而不是一个特定的解算器我提出以下意见:

compare(List,Reference,RightPlace,ErrorPlace)
获取两个列表,并将RightPlace与第一个列表中出现在第二个列表中同一点的元素数统一起来,将ErrorPlace与出现在第二个列表中不同点的元素数统一起来(其中重复的元素只有在两个列表中都重复时才被计数)。它使用

right\u place(List,Reference,RightPlace)
它包装一个累加器并使用每个列表头部的元素,在匹配的地方递增,然后

any_match(List,Reference,Matches)
包装消耗列表头部的累加器,并在可能的情况下从引用列表中选择该累加器,在发生这种情况时递增

ErrorPlace
则是从
匹配项的数量中减去
RightPlace
元素的数量

最后,
find_solutions(Soln)
使用clpfd在域(0-9)中创建一个元素列表,然后映射indomain以创建组合。然后使用
forall
将每个组合与每个提示进行比较,以确保满足所有提示约束。将其与提示放在一起,您将得到:

:- use_module(library(clpfd)).

compare(List,Reference,RightPlace,WrongPlace) :-
    right_place(List,Reference,RightPlace),
    any_match(List,Reference,Matches),
    WrongPlace #= Matches - RightPlace.

right_place(List,Reference,RightPlace) :-
    right_place(List,Reference,0,RightPlace).

right_place([],[],RightPlace,RightPlace).
right_place([Match|List],[Match|Reference],Accumulator,RightPlace) :-
    NewAccumulator is Accumulator + 1,
    right_place(List,Reference,NewAccumulator,RightPlace).
right_place([A|List],[B|Reference],Accumulator,RightPlace) :-
    A \= B,
    right_place(List,Reference,Accumulator,RightPlace).

any_match(List,Reference,Matches) :-
    any_match(List,Reference,0,Matches).

any_match([],_,Matches,Matches).
any_match([Match|List],Reference,Accumulator,Matches) :-
    select(Match,Reference,NewReference),
    NewAccumulator is Accumulator + 1,
    any_match(List,NewReference,NewAccumulator,Matches).
any_match([Match|List],Reference,Accumulator,Matches) :-
    \+member(Match,Reference),
    any_match(List,Reference,Accumulator,Matches).

find_solutions(Soln) :-
    length(Soln,3),
    Soln ins 0..9,
    maplist(indomain,Soln),
    forall(hint(X,Y,Z),compare(Soln,X,Y,Z)).

hint([6,8,2],1,0).
hint([6,1,4],0,1).
hint([2,0,6],0,2).
hint([7,3,8],0,0).
hint([7,8,0],0,1).

对于现有的答案,我想添加一个使用CLP(FD)约束的版本

我将使用的两个构建块是
num\u correct/3
num\u well\u placed/3

首先,
num\u correct/3
,将两个整数列表与公共元素的数量关联起来:

num_correct(Vs, Ns, Num) :- foldl(num_correct_(Vs), Ns, 0, Num). num_correct_(Vs, Num, N0, N) :- foldl(eq_disjunction(Num), Vs, 0, Disjunction), Disjunction #<==> T, N #= N0 + T. eq_disjunction(N, V, D0, D0 #\/ (N #= V)). 同样,一个示例查询和回答:

?- num_well_placed([8,3,4], [0,3,4], Num). Num = 2.
为此,我会生成所有可能的解决方案,并通过逐个应用事实排除不正确的解决方案。在您的尝试中,您将list
Hs
的长度设置为1,这意味着它只有一个元素,但随后检查它必须有6个不同的唯一元素。这将始终失败。
更正和放置/4
不考虑参数,只会成功。这是一个最大的推广吗?谢谢,看起来是一个很好的解决方案,但我无法让它工作。我终于完成了库clp(fd)被加载,但当我尝试执行
num\u correct\u
时,它说一些谓词的算术是错误的。我看到
num\u correct\u
/4
,但在
num\u correct
上,你只使用
Vs
@edit“调用它”:似乎我犯了一些错误(可能是打字错误)而且我也忘记了foldl是如何工作的,但我现在记起来了,我的评论很愚蠢。对此我很抱歉,因为它是非常地道的,工作很好,并且引入了关于prolog的新知识,所以被标记为正确答案。 ?- num_correct([A], [B], Num). B#=A#<==>Num, Num in 0..1. num_well_placed(Vs, Ns, Num) :- maplist(num_well_placed_, Vs, Ns, Bs), sum(Bs, #=, Num). num_well_placed_(V, N, B) :- (V #= N) #<==> B. ?- num_well_placed([8,3,4], [0,3,4], Num). Num = 2. num_correct_placed(Vs, Hs, C, P) :- num_correct(Vs, Hs, C), num_well_placed(Vs, Hs, P). lock(Vs) :- Vs = [_,_,_], Vs ins 0..9, num_correct_placed(Vs, [6,8,2], 1, 1), num_correct_placed(Vs, [6,1,4], 1, 0), num_correct_placed(Vs, [2,0,6], 2, 0), num_correct_placed(Vs, [7,3,8], 0, 0), num_correct_placed(Vs, [7,8,0], 1, 0). ?- lock(Vs). Vs = [0, 4, 2]. lock(Vs) :- Vs = [_,_,_], Vs ins 0..9, num_correct_placed(Vs, [6,8,2], 1, 1), num_correct_placed(Vs, [6,1,4], 1, 0), num_correct_placed(Vs, [2,0,6], 2, 0), num_correct_placed(Vs, [7,3,8], 0, 0), * num_correct_placed(Vs, [7,8,0], 1, 0). ?- lock(Vs). Vs = [0, 4, 2]. lock(Vs) :- Vs = [_,_,_], Vs ins 0..9, num_correct_placed(Vs, [6,8,2], 1, 1), num_correct_placed(Vs, [6,1,4], 1, 0), num_correct_placed(Vs, [2,0,6], 2, 0), * num_correct_placed(Vs, [7,3,8], 0, 0), * num_correct_placed(Vs, [7,8,0], 1, 0). ?- lock(Vs), label(Vs). Vs = [0, 4, 2] ; false.