如何在Prolog中实现锁门游戏?

问题描述 投票:0回答:1

我正在解决序言中的搜索问题,其中代理的目标是找到一些宝藏。在每个时间步骤,代理可以使用根据无向图排列的门在房间之间移动。然而,有些门是锁着的,特工必须获得适当的钥匙才能穿过锁着的门。 我编写代码,代码生成以下操作“Actions = [move(0, 1), move(1, 3), move(3, 4), move(4, 2), move(2, 5), move (5, 6)]”,但假定的动作是:“动作 = [move(0, 1), move(1, 3), move(3, 4), move(4, 2), move(2, 5) ),移动(5, 6)]。” 代码是:

initial(0).

door(0,1).
door(0,2).
door(1,2).
door(1,3).
door(2,4).

locked_door(2,5,red).
locked_door(5,6,blue).

key(3,red).
key(4,blue).

treasure(6).

initial_state(state(Pos, noKey, noKey)) :- % Initial position with no keys
    initial(Pos).

% Moving without picking up a key or using a key
take_action(state(A, RedKey, BlueKey), move(A,B), state(B, RedKey, BlueKey)) :-
    door(A,B).
take_action(state(A, RedKey, BlueKey), move(A,B), state(B, RedKey, BlueKey)) :- 
    door(B,A).


% Picking up a red key
take_action(state(A, noKey, noKey), move(A,B), state(B, hasKey(red), noKey)) :-
    door(A,B),
    key(B, red).


% Picking up a blue key
take_action(state(A, hasKey(red), noKey), move(A,B), state(B, hasKey(red), hasKey(blue))) :-
    door(A,B),
    key(B, blue).


% open locked doors
take_action(state(A, hasKey(red), hasKey(blue)), move(A,B), state(B, hasKey(red), hasKey(blue))) :-
    locked_door(A,B,blue).
take_action(state(A, hasKey(red), hasKey(blue)), move(A,B), state(B, hasKey(red), hasKey(blue))) :-
    locked_door(B,A,blue).
take_action(state(A, hasKey(red), hasKey(blue)), move(A,B), state(B, hasKey(red), hasKey(blue))) :-
    locked_door(A,B,red).
take_action(state(A, hasKey(red), hasKey(blue)), move(A,B), state(B, hasKey(red), hasKey(blue))) :-
    locked_door(B,A,red).

final_state(state(Pos, _, _)) :- treasure(Pos).

take_steps(S0, [Action], S1) :- take_action(S0, Action, S1).
take_steps(S0, [Action | Rest], SFinal) :-
    take_action(S0, Action, SNew),
    take_steps(SNew, Rest, SFinal).

search(Actions) :-
    initial_state(S0),
    length(Actions, _), 
    take_steps(S0, Actions, SFinal),
    final_state(SFinal), !.
prolog swi-prolog
1个回答
0
投票

Logtalk 发行版包含一个“状态空间搜索”编程示例,实现了解决状态空间搜索问题的框架。它包括启发式和非启发式状态空间的抽象以及几种搜索方法,允许将多种搜索方法应用于状态空间并将搜索方法应用于多个状态空间。使用此框架的“锁门”状态空间的正确定义可能是: :- object(doors, instantiates(state_space)). initial_state(start, s(Room, no_key, no_key)) :- initial(Room). goal_state(end, s(Room, _, _)) :- treasure(Room). % moving without picking up a key or using a key next_state(s(A, Red, Blue), s(B, Red, Blue)) :- door(A, B). next_state(s(A, Red, Blue), s(B, Red, Blue)) :- door(B, A). % picking up a red key next_state(s(A, no_key, Blue), s(B, red, Blue)) :- door(A, B), key(B, red). % picking up a blue key next_state(s(A, Red, no_key), s(B, Red, blue)) :- door(A, B), key(B, blue). % open locked doors next_state(s(A, Red, blue), s(B, Red, blue)) :- locked_door(A, B, blue). next_state(s(A, Red, blue), s(B, Red, blue)) :- locked_door(B, A, blue). next_state(s(A, red, Blue), s(B, red, Blue)) :- locked_door(A, B, red). next_state(s(A, red, Blue), s(B, red, Blue)) :- locked_door(B, A, red). print_state(State) :- write(State), nl. initial(0). door(0, 1). door(0, 2). door(1, 2). door(1, 3). door(2, 4). locked_door(2, 5, red). locked_door(5, 6, blue). key(3, red). key(4, blue). treasure(6). :- end_object.

请注意,抓取一个键与是否按住另一个键无关,这在您的代码中是不正确的(除非您对问题的描述不完整)。其他更改是为了使代码更紧凑、更简单或编码指南。

为了获得最短的解决方案,我们可以使用提供的广度优先搜索方法。假设上面的对象保存在

doors.lgt

文件中:

$ tplgt -q
?- {searching(loader), doors}.
   true.
?- doors::initial_state(Initial), breadth_first(20)::solve(doors, Initial, Path), doors::print_path(Path).
s(0,no_key,no_key)
s(1,no_key,no_key)
s(3,red,no_key)
s(1,red,no_key)
s(2,red,no_key)
s(4,red,blue)
s(2,red,blue)
s(5,red,blue)
s(6,red,blue)
   Initial = s(0,no_key,no_key), Path = [s(0,no_key,no_key),s(1,no_key,no_key),s(3,red,no_key),s(1,red,no_key),s(2,red,no_key),s(4,red,blue),s(2,red,blue),s(5,red,blue),s(6,red,blue)]
;

回溯将为您提供长度不断增加的解决方案。

© www.soinside.com 2019 - 2024. All rights reserved.