Prolog项目/谜题的结果不正确

Prolog项目/谜题的结果不正确,prolog,maze,Prolog,Maze,我在一个艰难的序言项目/难题中工作,但我找不到解决方案。 我将感谢任何帮助 实践是通过迷宫建模和求解逻辑编程。 它由房间、门和钥匙组成。当两个房间连接时,它们通过一扇门连接,这扇门由一个或多个锁关闭,需要打开才能从一个房间移动到另一个房间。钥匙和锁模糊不清。打开一扇门后,它总是打开的,但钥匙卡在锁里,无法恢复(永远丢失),因此打开每扇门时,他们会带上许多钥匙和锁。每个房间都有未使用的钥匙,这些钥匙可以收集起来,以便进一步打开新的门。起初我们没有钥匙 解决方案程序必须定义一个谓词camino/3(

我在一个艰难的序言项目/难题中工作,但我找不到解决方案。 我将感谢任何帮助

实践是通过迷宫建模和求解逻辑编程。 它由房间、门和钥匙组成。当两个房间连接时,它们通过一扇门连接,这扇门由一个或多个锁关闭,需要打开才能从一个房间移动到另一个房间。钥匙和锁模糊不清。打开一扇门后,它总是打开的,但钥匙卡在锁里,无法恢复(永远丢失),因此打开每扇门时,他们会带上许多钥匙和锁。每个房间都有未使用的钥匙,这些钥匙可以收集起来,以便进一步打开新的门。起初我们没有钥匙

解决方案程序必须定义一个谓词camino/3(camino在西班牙语中是road),这样(
a
F
X
)在
X
是一条通往房间的道路的情况下(
F
)是真的,这样您就可以随时用相应的钥匙开门。道路应按照房间名称的交叉顺序(从
a
开始,到
F
结束)作为房间名称列表进行计算

程序将为每个房间
e
定义一个
e(e,L)
形式的谓词
e/2
,其中
L
是该房间中包含的钥匙数量。您还可以为每个门定义一个形式为
p(E1,E2,C)
的谓词
p/3
,其中
C
是具有连接
E1
E2
房间的门的锁的数量。程序应保持房间(是否有钥匙)和门(是否已打开)的状态 锁定)在任何时候

例如():

结果应该是:

?‐ camino(a,f,X). 
X = [a,b,a,c,d,f] ? 
yes 
?‐ camino(a,f,X). 
X = [a,c,d,f] ? 
yes 
这是我当前的代码。它找到了通往命运的路,但它并不正确。此外,我还没有应用削减,因此它只给了我一个答案:

%CODE

% these are the rooms and the number of keys they contain
e(a,1).
e(b,2).
e(c,1).
e(d,0).
e(e,0). 
e(f,0).

%these are the doors and the number of keys needed to open them
p(a,b,1).
p(a,c,1).    
p(b,d,1).    
p(c,e,1).    
p(d,f,1).    
p(e,f,2).          

concatenate([],L,L).        
concatenate([X|M],L,[X|Y]) :-        
   concatenate(M,L,Y).

%%%%%%%%%%%%%
camino(A,F,X):-    
   A==F,                     %check if we start at the destiny    
   concatenate([],[F],X).    
%%%%%%%%%%%%%%%%%%%%%%%%%%    
camino(A,F,X):-    
   A\==F,                     %check if we dont start at the destiny    
   concatenate([],[A],R),    
   findRoad(A,F,0,R,X).    
%%%%%%%%%%%%%%%%%%
%TRUE if x is a road (list) that leads to room F starting from A
%
findRoad(A,F,K,R,X):-     %k is key ---  initial keys    
    addkey(A,K,L),        %L new key--- number of keys after we add the keys of the room    
    pickkey(A),           %we put the number of keys of the room to 0    
    passDoor(A,L,P,_),    %P is position-- position of the new room    
    opendoor(A,P),        %we put the number of keys needed to pass the door to 0    
    P == F,               %we check if we have finished    
    concatenate(R,[P],X). %we concatenate the destiny and end   
findRoad(A,F,K,R,X):-     %k is key ---  initial keys   
    addkey(A,K,L),        %L new key--- number of keys after we add the keys of the room    
    pickkey(A),           %we put the number of keys of the room to 0    
    passDoor(A,L,P,L2),   %P is position-- position of the new room   

    opendoor(A,P),        %we put the number of keys needed to pass the door to 0    
    P \== F,              %we check we haven't finished   
    concatenate(R,[P],R2),%we concatenate the path we have for the moment   
    findRoad(P,F,L2,R2,X).

addkey(A,K,L):-    
    e(A,N),    
    L is K+N.    

passDoor(A,L,P,L2):-    
    p(A,P,W),    
    L2 is L-W,    
    L2 >= 0.   
passDoor(A,L,P,L2):-   
    p(P,A,W),   
    L2 is L-W,    
    L2 >= 0.    

pickkey(A):-    
    e(A,_) = e(A,0).    

opendoor(A,P):-    
    p(A,P,_) = p(A,P,0).       
opendoor(A,P):-    
    p(P,A,_) = p(P,A,0).

这里是解决它的另一个尝试,但是它被无限循环卡住了

%房间+钥匙数量 e(a,1)

e(b,2)

e(c,1)

e(d,0)

e(e,0)

e(f,0)

%门

p(a,b,1)

p(a,c,1)

p(b,d,2)

p(c,e,1)

p(d,f,1)

p(e,f,2)

%普罗西卡

连接([],L,L)

连接([X | M],L[X | Y]):-

路径(A,F,X):-

A==F

连接([],[F],X)

路径(A,F,X):-

A\==F

连接([],[A],R)

探路者(A、F、0、R、[]、[]、[]、[]、X)

%如果x是从a开始通向F室的道路(列表),则为TRUE

探路者(A、F、K、R、房间、门、房间2、门3、X):-%K是钥匙---初始钥匙

    addkey(A,K,L,ROOM,ROOM2),     %L new key--- number of keys after we add the keys of the room 

    passDoor(A,L,P,_,DOOR,DOOR3),             %P is position-- position of the new room   

    P == F,                                 %we check if we have finished  

    concatenate([P],[R],X).               %we concatenate the destiny and end 
    addkey(A,K,L,ROOM,ROOM2),      %L new key--- number of keys after we add the keys of the room 

    passDoor(A,L,P,L2,DOOR,DOOR3),%P=new room L2 = new Nº of keys

    P \== F,                               %we check we havent finished

    concatenate([R],[P],R2),            %we add the room we are to the path

    pathfinder(P,F,L2,R2,ROOM2,DOOR3,_,_,X).       %
探路者(A、F、K、R、房间、门、房间2、门3、X):-%K是钥匙---初始钥匙

    addkey(A,K,L,ROOM,ROOM2),     %L new key--- number of keys after we add the keys of the room 

    passDoor(A,L,P,_,DOOR,DOOR3),             %P is position-- position of the new room   

    P == F,                                 %we check if we have finished  

    concatenate([P],[R],X).               %we concatenate the destiny and end 
    addkey(A,K,L,ROOM,ROOM2),      %L new key--- number of keys after we add the keys of the room 

    passDoor(A,L,P,L2,DOOR,DOOR3),%P=new room L2 = new Nº of keys

    P \== F,                               %we check we havent finished

    concatenate([R],[P],R2),            %we add the room we are to the path

    pathfinder(P,F,L2,R2,ROOM2,DOOR3,_,_,X).       %
地址(A、K、L、房间、房间):-

地址(A、K、L、房间、房间2):-

安全门(A、L、p、L2、门、门):-

安全门(A、L、p、L2、门、门3):-


下面是一种方法,它不提供最佳路径(在房间之间的最小步骤数的意义上),但满足请求。主要规则是:

path( Orig, Dest, Res ) :-
   e( Orig, Keys ),
   nextDoor( Dest, [(Orig,Orig)], Keys, [_|OpenDoors] ), !,
   joinDoors( Orig, OpenDoors, [Orig], Res ), !.
这意味着,在初始化初始房间的钥匙数量后,算法将决定门必须打开的顺序(nextDoor),第二个将在上一个列表中找到一扇门到下一扇门之间的路径

理由是:在给定的时刻,我们有一组打开的门,以及一组由这些打开的门连接的房间。在开放的门和到访的房间区域内的移动是免费的,门已经打开,并且到访的房间还没有钥匙。因此,我们感兴趣的只是决定我们必须打开哪一扇门。决定开门顺序的规则如下:

nextDoor( Dest, OpenDoors, _, Res ) :-
  visitedRoom( Dest, OpenDoors ), 
  !,
  reverse( OpenDoors, Res ). 

nextDoor( Dest, OpenDoors, Keys, Res ) :-
  /* choice a visited room */
  visitedRoom( Room, OpenDoors ), 

  /* next door not yet open */
  door( Room, NextRoom, DoorCost ),
  \+ member( (Room,NextRoom), OpenDoors ),
  \+ member( (NextRoom,Room), OpenDoors ),

  /* we can open door ? */
  DoorCost =< Keys,

  /* do not open doors to rooms already visited */
  \+ visitedRoom( NextRoom, OpenDoors ),

  /* ok, cross door and next one */
  e( NextRoom, RoomAward ),
  Keys2 is Keys-DoorCost+RoomAward,
  nextDoor( Dest, [(Room,NextRoom)|OpenDoors], Keys2, Res ).
另一个用于查找已访问区域内的房间(通过打开的门连接的房间):

第二步是按照前面的顺序从一个门走到另一个门

joinDoors( _, [], Path, Res ) :-
   reverse( Path, Res ).
joinDoors( CurrentRoom, [ (RoomBeforeDoor, RoomAfterRoom ) | Q ], Path, Res ) :-
   roomToRoom( CurrentRoom, RoomBeforeDoor, [], Path2 ),
   append( Path2, Path, Path3 ),
   joinDoors( RoomAfterRoom, Q, [RoomAfterRoom|Path3], Res ).
其中roomToRoom是查找路径的经典算法(TODO:优化以查找最短路径):

如果我们尝试使用示例中提供的数据:

e(a,1).
e(b,2).
e(c,1).
e(d,0).
e(e,0).
e(f,0).

p(a,b,1).
p(a,c,1).
p(b,d,2). /* corrected */
p(c,d,1). /* add */
p(c,e,1).
p(d,f,1).
p(e,f,2).
结果是:

?- path(a,f,Path).
Path = [a, b, a, c, d, f].

为了确保获得最短路径,您可以使用BFS搜索:

:- use_module(library(lambda)).

%rooms + number of keys
e(a,1).
e(b,2).
e(c,1).
e(d,0).
e(e,0).
e(f,0).

%Doors
p(a,b,1).
p(a,c,1).
p(b,d,2).
p(c,d,1).
p(c,e,1).
p(d,f,1).
p(e,f,2).

% Doors are closed at the beginning of the puzzle
% state(CurrentRoom, NumberKeys, StateRooms, StateDoors)
init(state(a, 0, LstRooms, LstDoors)) :-
    setof(e(X,Y), X^Y^e(X,Y), LstRooms),
    setof(p(X,Y,Z, closed), X^Y^Z^p(X,Y,Z), LstDoors).

% final state
final(state(f, _, _, _)).

% skeleton of BFS search
:- dynamic(states/1).
puzzle :-
    retractall(states(_)),
    % set the initial state
    init(State),
    assert(states([[State]])),
    repeat,
        nextstates,
    % if we get to the final state,
    % eneded/1 succeeds with a path
    ended(Path),
    maplist(writeln, Path).

% test if we have finished the puzzle
% succeeds with a Path to the solution
% This BFS gives a reverse path to the solution
ended(Path) :-
    final(State),
    states(LstStates),
    % may be there is no solution ?
    (   LstStates = []
    ->  Path = []
    ;   include(=([State|_]), LstStates, Paths),
        Paths = [RPath|_],
        reverse(RPath, Path)).

nextstates :-
    retract(states(LstStates)),
    foldl(\States^Y^Z^(nextstates_one(States, NewStates),
               append(Y, NewStates, Z)),
          LstStates, [], LstNewStates),
        assert(states(LstNewStates)).

% First we search the rooms near the current room
% Next we build the new paths
nextstates_one([Head | Tail], NewStates) :-
    nextrooms(Head, LState),
    foldl([Head, Tail] +\X^Y^Z^(member(X, Tail)
             ->  Z = Y
             ;   append([[X, Head | Tail]], Y, Z)),
          LState, [], NewStates),
    % we must put a cut here,
    % if **ended(Path)** fails, we must continue at **repeat**
    !.

% fetch all the rooms near the current room
nextrooms(state(R, K, SR, SD), States) :-
    % we fetch keys (even when there is no more keys left !)
    select(e(R, Key), SR, TSR),
    NK is K + Key,
    sort([e(R, 0) | TSR], NSR),
    % we test all the doors
    foldl([R,NK,NSR,SD]+\X^Y^Z^(X = p(R1, R2, Keys, Open),
                    % can we go to the next door ?
                   (   select(R, [R1,R2], [NR])
                   -> (    Open = opened
                       % the door is opened, we came in without changint anything
                       ->  Z = [state(NR, NK, NSR, SD) | Y]
                       % the door is closed, have we enough keys ?
                       ;   (   Keys =< NK
                        ->  NK1 is NK - Keys,
                            select(p(R1, R2, Keys, Open), SD, TSD),
                        sort([p(R1, R2, 0, opened) | TSD], NSD),
                        Z = [state(NR, NK1, NSR, NSD) | Y]
                        ;   Z = Y))
                   ;  Z = Y)),
          SD, [], States).
:-使用_模块(库(lambda))。
%房间+钥匙数量
e(a,1)。
e(b,2)。
e(c,1)。
e(d,0)。
e(e,0)。
e(f,0)。
%门
p(a,b,1)。
p(a,c,1)。
p(b,d,2)。
p(c,d,1)。
p(c,e,1)。
p(d,f,1)。
p(e,f,2)。
%在拼图开始时,门是关着的
%状态(当前房间、号码、房间、房间门)
初始(状态(a、0、L房间、L门)):-
一组(e(X,Y),X^Y^e(X,Y),l个房间,
一组(p(X,Y,Z,闭合),X^Y^Z^p(X,Y,Z),门)。
%最终状态
最终(状态(f,,,,,))。
%BFS搜索的框架
:-动态(状态/1)。
谜题:-
收回所有(状态()),
%设置初始状态
初始(状态),
断言(状态([[State]]),
重复一遍,
下一个州,
%如果我们到达最后的状态,
%eneded/1使用路径成功
结束(路径),
映射列表(writeln,Path)。
%测试我们是否完成了拼图
%通过指向解决方案的路径成功
%此BFS提供了解决方案的反向路径
结束(路径):-
最终(状态),
州(州),
%也许没有解决办法?
(州=[]
->路径=[]
;包括(([状态|))、状态、路径),
路径=[RPath | 124;],
反向(RPath,Path))。
下表:-
收回(状态(LstStates)),
foldl(\States^Y^Z^(nextstates\u one(States,NewStates),
追加(Y,NewStates,Z)),
州、州、州、,
断言(状态(LstNewStates))。
%首先,我们搜索当前房间附近的房间
%接下来,我们构建新的路径
下一个状态([头|尾],新闻状态):-
nextrooms(首部,第一州),
foldl([Head,Tail]+\X^Y^Z^(成员(X,Tail))
->Z=Y
;附加([[X,头|尾]],Y,Z)),
第一状态,[],新状态),
%我们必须在这里划一道口子,
%如果**结束(路径)**f
door(From,To,Cost) :-
  ( p(From,To,Cost); p(To,From,Cost) ).
visitedRoom( Room, OpenDoors ) :-
  ( member( (_,Room), OpenDoors ); member( (Room,_), OpenDoors ) ).
joinDoors( _, [], Path, Res ) :-
   reverse( Path, Res ).
joinDoors( CurrentRoom, [ (RoomBeforeDoor, RoomAfterRoom ) | Q ], Path, Res ) :-
   roomToRoom( CurrentRoom, RoomBeforeDoor, [], Path2 ),
   append( Path2, Path, Path3 ),
   joinDoors( RoomAfterRoom, Q, [RoomAfterRoom|Path3], Res ).
roomToRoom( DestRoom, DestRoom, Path, Path ) :- !.
roomToRoom( CurrentRoom, DestRoom, Path, Res ) :-
  door( CurrentRoom, NextRoom, _ ),
  \+ member( NextRoom, Path ),
  roomToRoom( DestRoom, NextRoom, [NextRoom|Path], Res ).
e(a,1).
e(b,2).
e(c,1).
e(d,0).
e(e,0).
e(f,0).

p(a,b,1).
p(a,c,1).
p(b,d,2). /* corrected */
p(c,d,1). /* add */
p(c,e,1).
p(d,f,1).
p(e,f,2).
?- path(a,f,Path).
Path = [a, b, a, c, d, f].
:- use_module(library(lambda)).

%rooms + number of keys
e(a,1).
e(b,2).
e(c,1).
e(d,0).
e(e,0).
e(f,0).

%Doors
p(a,b,1).
p(a,c,1).
p(b,d,2).
p(c,d,1).
p(c,e,1).
p(d,f,1).
p(e,f,2).

% Doors are closed at the beginning of the puzzle
% state(CurrentRoom, NumberKeys, StateRooms, StateDoors)
init(state(a, 0, LstRooms, LstDoors)) :-
    setof(e(X,Y), X^Y^e(X,Y), LstRooms),
    setof(p(X,Y,Z, closed), X^Y^Z^p(X,Y,Z), LstDoors).

% final state
final(state(f, _, _, _)).

% skeleton of BFS search
:- dynamic(states/1).
puzzle :-
    retractall(states(_)),
    % set the initial state
    init(State),
    assert(states([[State]])),
    repeat,
        nextstates,
    % if we get to the final state,
    % eneded/1 succeeds with a path
    ended(Path),
    maplist(writeln, Path).

% test if we have finished the puzzle
% succeeds with a Path to the solution
% This BFS gives a reverse path to the solution
ended(Path) :-
    final(State),
    states(LstStates),
    % may be there is no solution ?
    (   LstStates = []
    ->  Path = []
    ;   include(=([State|_]), LstStates, Paths),
        Paths = [RPath|_],
        reverse(RPath, Path)).

nextstates :-
    retract(states(LstStates)),
    foldl(\States^Y^Z^(nextstates_one(States, NewStates),
               append(Y, NewStates, Z)),
          LstStates, [], LstNewStates),
        assert(states(LstNewStates)).

% First we search the rooms near the current room
% Next we build the new paths
nextstates_one([Head | Tail], NewStates) :-
    nextrooms(Head, LState),
    foldl([Head, Tail] +\X^Y^Z^(member(X, Tail)
             ->  Z = Y
             ;   append([[X, Head | Tail]], Y, Z)),
          LState, [], NewStates),
    % we must put a cut here,
    % if **ended(Path)** fails, we must continue at **repeat**
    !.

% fetch all the rooms near the current room
nextrooms(state(R, K, SR, SD), States) :-
    % we fetch keys (even when there is no more keys left !)
    select(e(R, Key), SR, TSR),
    NK is K + Key,
    sort([e(R, 0) | TSR], NSR),
    % we test all the doors
    foldl([R,NK,NSR,SD]+\X^Y^Z^(X = p(R1, R2, Keys, Open),
                    % can we go to the next door ?
                   (   select(R, [R1,R2], [NR])
                   -> (    Open = opened
                       % the door is opened, we came in without changint anything
                       ->  Z = [state(NR, NK, NSR, SD) | Y]
                       % the door is closed, have we enough keys ?
                       ;   (   Keys =< NK
                        ->  NK1 is NK - Keys,
                            select(p(R1, R2, Keys, Open), SD, TSD),
                        sort([p(R1, R2, 0, opened) | TSD], NSD),
                        Z = [state(NR, NK1, NSR, NSD) | Y]
                        ;   Z = Y))
                   ;  Z = Y)),
          SD, [], States).