我在Prolog遇到问题。我正在尝试编写一个转换器,将简单的英语句子转换为Prolog中的命令。 我正在尝试使用教程here创建一个文本冒险游戏。
我的问题是:在启动主命令循环后,当输入一个句子并点击“输入”按钮时,Prolog将只是跳到下一行,似乎根本没有执行命令。无论我多久进入一次全站。在使用这种语言转换器之前,一切正常,游戏可以使用命令播放。问题必须在代码的这一部分内。更确切地说,我认为阅读行或get_command(X)
函数的部分很可能无效。
顺便提一下,我正在使用SWI-Polog(如果有重要的话(有些人将这些信息添加到他们的问题中)。
由于我自己无法发现错误,我会尝试发布相关代码。
首先是主命令循环:
command_loop:-
write('Welcome to Nani Search'), nl,
look,nl,
repeat,
write('>nani> '),
get_command(X),
do(X), nl,
end_condition(X).
现在转换器(get_command(X)
功能位于最底层):
% Natural language converter
command([V], InList):- verb(V, InList-[]).
verb(look, [look|X]-X).
verb(look, [look,around|X]-X).
verb(look, [glotz,ma,alde|X]-X).
verb(list_possessions, [inventory|X]-X).
verb(end, [end|X]-X).
verb(end, [quit|X]-X).
verb(end, [good,bye|X]-X).
command([V,O], InList) :-
verb(Object_Type, V, InList-S1),
object(Object_Type, O, S1-[]).
verb(place, goto, [go,to|X]-X).
verb(place, goto, [go|X]-X).
verb(place, goto, [move,to|X]-X).
% Exceptions for rooms with two words
verb(place, goto, [X|Y]-[X|Y]):- room(X).
verb(place, goto, [dining,room|Y]-[dining,room|Y]).
verb(thing, take, [take|X]-X).
verb(thing, drop, [drop|X]-X).
verb(thing, drop, [put|X]-X).
verb(thing, turn_on, [turn,on|X]-X).
verb(thing, turn_off, [turn,off|X]-X).
object(Type, N, S1-S3) :-
det(S1-S2),
noun(Type, N, S2-S3).
object(Type, N, S1-S2) :-
noun(Type, N, S1-S2).
det([the|X]- X).
det([a|X]-X).
det([an|X]-X).
% Exceptions for rooms with two words
noun(place, R, [R|X]-X):- room(R).
noun(place, 'dining room', [dining,room|X]-X).
% Exceptions for things with two words
noun(thing, T, [T|X]-X):- location(object(T,_),_).
noun(thing, T, [T|X]-X):- have(object(T,_)).
noun(thing, 'washing machine', [washing,machine|X]-X).
noun(thing, flashlight, [light|X]-X):- have(object(flashlight,_)).
noun(thing, light, [light|X]-X).
% read a line of words from the user
read_list(L) :-
write('> '),
read_line(CL),
wordlist(L,CL,[]), !.
read_line(L) :-
get0(C),
buildlist(C,L).
buildlist(13,[]) :- !.
buildlist(C,[C|X]) :-
get0(C2),
buildlist(C2,X).
wordlist([X|Y]) --> word(X), whitespace, wordlist(Y).
wordlist([X]) --> whitespace, wordlist(X).
wordlist([X]) --> word(X).
wordlist([X]) --> word(X), whitespace.
word(W) --> charlist(X), {name(W,X)}.
charlist([X|Y]) --> chr(X), charlist(Y).
charlist([X]) --> chr(X).
chr(X) --> [X],{X>=48}.
whitespace --> whsp, whitespace.
whitespace --> whsp.
whsp --> [X], {X<48}.
% Return a command
get_command(C) :-
read_list(L),
command(CL,L),
C =.. CL, !.
get_command(_) :-
write('I don''t understand'), nl, fail.
最后,来自命令循环的do-function:
do(goto(X)):-goto(X),!.
do(go(X)):-goto(X),!.
do(take(X)):-take(X),!.
do(put(X,Y)):-put(X),!.
do(turn_on(X)):-turn_on(X),!.
do(turn_off(X)):-turn_off(X),!.
do(inventory):-inventory,!.
do(list_things(X)):-list_things(X),!.
do(look):-look,!.
do(end).
do(_) :-
write('Invalid command').
通过将自然语言句子转换为这些命令,程序应该启动相应的功能。它应该像这样工作:当你输入go to the office.
时,转换器应该将frase转换为命令goto(office)
。当一个人写take the flashlight
时,它应该将其转换为take(flashlight)
。当一个人写look around
时。它应该转换为look
。然后应该将转换后的命令发送到命令循环并通过do(X)执行(如do-function中所示,X必须是goto(office)
之类的命令。
我希望很清楚我的问题是什么。
我也做了一个追踪。命令循环正常启动。这是在命令循环结束后发生的事情(write('>nani> ')
仍然是它的一部分。)
Call: (7) write('>nani> ') ? creep
>nani>
Exit: (7) write('>nani> ') ? creep
Call: (7) get_command(_G3903) ? creep
Call: (8) read_list(_G3903) ? creep
Call: (9) write('> ') ? creep
>
Exit: (9) write('> ') ? creep
Call: (9) read_line(_G3903) ? creep
Call: (10) get0(_G3903) ? creep
|:
然后我就可以输入一个新命令了。只需按下Enter按钮而不提供任何输入,它将始终执行以下操作:
Exit: (10) get0(10) ? creep
Call: (10) buildlist(10, _G3904) ? creep
Call: (11) get0(_G3906) ? creep
|:
只要我按下回车,就会重复此操作。当我在按Enter键之前输入一个随机字母或多个字母时,第一个get0的值将会改变,但没有别的。
根据我写的字母,有时会有不同的结果。这是两个例子: 例如,当我尝试编写 dsf 时,会发生这种情况:
|: dsf
Exit: (10) get0(100) ? skip
Call: (10) buildlist(100, _G3904) ? fail
Fail: (9) read_line(_G3903) ? creep
Fail: (8) read_list(_G3903) ? creep
Redo: (7) get_command(_G3903) ? creep
Call: (8) write('I don\'t understand') ? creep
I don't understand
Exit: (8) write('I don\'t understand') ? creep
Call: (8) nl ? creep
Exit: (8) nl ? creep
᠀ Call: (8) fail ? creep
Fail: (8) fail ? creep
Fail: (7) get_command(_G3903) ? creep
Redo: (7) repeat ? creep
Exit: (7) repeat ? creep
Call: (7) write('>nani> ') ? creep
>nani>
Exit: (7) write('>nani> ') ? creep
Call: (7) get_command(_G3903) ? creep
Call: (8) read_list(_G3903) ? creep
Call: (9) write('> ') ? creep
>
Exit: (9) write('> ') ? creep
Call: (9) read_line(_G3903) ? creep
Call: (10) get0(_G3903) ? creep
|:
apg 等其他输入将产生以下结果:
|: apg
Exit: (17) get0(97) ? print
Exit: (17) get0(97) ? goals
[17] get0(97)
[16] buildlist(10, [10|_G3915])
[15] buildlist(10, [10, 10|_G3915])
[14] buildlist(10, [10, 10, 10|_G3915])
[13] buildlist(10, [10, 10, 10, 10|_G3915])
Exit: (17) get0(97) ? creep
Call: (17) buildlist(97, _G3915) ? creep
Call: (18) get0(_G3927) ? creep
当输入更长的命令,随机或类似go to the office.
之类的命令时,程序将完全关闭,而不会发表评论。仅在激活跟踪时才会发生此关闭。如果不是这样,像go to the office.
这样的命令将再次使程序跳转到下一行,似乎没有做任何事情。
可能还有趣的是,在启动命令循环后,程序需要很长时间才能关闭。显示以下消息:
Waiting for Prolog. Close again to force termination ..
由于我是Prolog的新手,我不太清楚如何解释这个。对我来说,对随机字母作为输入的反应是完全随机的。也许别人有线索。
如果有人可以帮助我的话,我会非常感激。我希望这不是一个错误。
问候:)