我正在开发一个项目,它基本上是一个具有游戏逻辑的 prolog 服务器,它与一个 c++ openGL 程序通信,该程序呈现从 prolog 接收到的信息以进行游戏绘图。
这是服务器循环,连接成功后开始:
serverLoop(Stream) :-
repeat,
write('reading'), nl,
read(Stream, ClientMsg),
write('Received: '), write(ClientMsg), nl,
write('Parsing'), nl,
parse_input(ClientMsg, MyReply),
write('formatting'), nl,
format(Stream, '~q.~n', [MyReply]),
write('Wrote: '), write(MyReply), nl,
write('flushing'), nl,
flush_output(Stream),
write('end condition'), nl,
(ClientMsg == quit; ClientMsg == end_of_file), !.
它充满了写入,因为我已经调试了几个小时。
这里需要注意的重要部分是:
parse_input(ClientMsg, MyReply)
这是我发送从 C++ 收到的所有消息的地方,目前我对 parse_input 的方法如下:
parse_input(putpieceHuman(BOARD, PIECE, LINE, COLUMN), Answer) :-
write('Parsing putpieceHuman'), nl,
drawBoard(BOARD), nl,
putpieceHuman(BOARD, PIECE, LINE, COLUMN, Answer).
parse_input(putpiecePC(BOARD, PIECE, AI), Answer):-
write('Parsing putpiecePC'), nl,
drawBoard(BOARD), nl,
putpiecePC(BOARD, PIECE, Answer, AI).
它们非常相似。第一个是播放器播放(指定播放位置),第二个是电脑播放(AI是我想让电脑拥有的智能值,我们只考虑0值,这是完全随机的)
这些是解析器调用的谓词:
putpieceHuman(BOARD, PIECE, LINE, COLUMN, NEXTBOARD):-
putPiece(BOARD, PIECE, LINE, COLUMN, NEXTBOARD).
putpiecePC(BOARD, PIECE, NEXTBOARD, 0):-
write('enter putpiecePC'), nl,
random(0, 6, LINE),
random(0, 6, COLUMN),
putPiece(BOARD, PIECE, LINE, COLUMN, NEXTBOARD).
putpiecePC(BOARD, PIECE, NEXTBOARD, 0):- write('putpiecePC failed'), putpiecePC(BOARD, PIECE, NEXTBOARD, 0).
我确实意识到 putpieceHuman 有点多余,但这是为了保持模式。因此,putPiece 是在用新游戏修改棋盘后返回棋盘的谓词,如果已经有棋子可以玩,它就会失败。
当人类放置一块时,C++ 程序会过滤错误的输入,因此 putPiece 不可能失败,因此它可以直接使用,如您所见。另一方面, putpiecePC 是由随机完成的,因此它可能会失败我添加了一个基本重复第一个的 perdicate,如果它失败了。
问题是:当我使用 putpieceHuman 玩游戏时,它工作得很好,但是当我尝试使用 putpiecePC 时,它会进入无限循环。
这是在人类 putpiece 之后的 Sicstus 日志,人类旋转(忽略这个),最后是一个 pc putpiece,请注意我上面写的内容被翻译了,日志不是所以请注意以下几点:
colocaHumano = putpieceHuman
rodaHumano -> ignore this
colocaPC = putpiecePC
好的,现在日志:
| ?- server.
Accepted connection
reading
Received: colocaHumano([[[0,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0]]],1,5,0)
Parsing
Parsing colocaHumano
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
formatting
Wrote: [[[0,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[1,0,0]],[[0,0,0],[0,0,0],[0,0,0]]]
flushing
end condition
reading
Received: rodaHumano([[[0,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[1,0,0]],[[0,0,0],[0,0,0],[0,0,0]]],2,1)
Parsing
Parsing rodaHumano
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
1 0 0 0 0 0
formatting
Wrote: [[[0,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0]],[[1,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0]]]
flushing
end condition
reading
Received: colocaPC([[[0,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0]],[[1,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0]]],2,0)
Parsing
Parsing colocaPC
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
1 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
enter colocaPC
formatting
Wrote: [[[0,0,0],[0,0,0],[0,0,0]],[[0,0,0],[2,0,0],[0,0,0]],[[1,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0]]]
flushing
end condition
colocaPC failedenter colocaPC
formatting
Wrote: [[[0,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0]],[[1,0,0],[0,0,2],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0]]]
flushing
end condition
colocaPC failedenter colocaPC
formatting
Wrote: [[[0,0,0],[0,2,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0]],[[1,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0]]]
flushing
end condition
colocaPC failedenter colocaPC
formatting
Wrote: [[[0,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0]],[[1,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,2,0]]]
flushing
end condition
colocaPC failedenter colocaPC
formatting
Wrote: [[[0,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,2,0],[0,0,0]],[[1,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0]]]
flushing
end condition
colocaPC failedenter colocaPC
formatting
Wrote: [[[0,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,2],[0,0,0]],[[1,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0]]]
flushing
end condition
colocaPC failedenter colocaPC
formatting
Wrote: [[[0,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,2,0],[0,0,0]],[[1,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0]]]
flushing
end condition
colocaPC failedenter colocaPC
formatting
Wrote: [[[0,2,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0]],[[1,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0]]]
flushing
end condition
colocaPC failedenter colocaPC
formatting
Wrote: [[[0,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0]],[[1,2,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0]]]
flushing
end condition
colocaPC failedenter colocaPC
formatting
Wrote: [[[0,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,2]],[[1,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,
Prolog interruption (h for help)?
我还必须注意,如果我在 sicstus 的直接调用中调用 putpiecePC,它就可以工作,所以问题不应该来自它。
为什么会这样?
最佳答案
问题与您实现主循环的方式有关(使用重复)。这种编写方式只有在所有代码都是确定性的情况下才有效,因此,只有在 ClientMsg
时才有效。是 quit
或 end_of_file
程序将结束,否则它将返回到最初的重复。
但这在您的代码中并非如此。您的代码中内置了一个 super 明显的无限循环
putpiecePC(BOARD, PIECE, NEXTBOARD, 0):-
write('putpiecePC failed'),
putpiecePC(BOARD, PIECE, NEXTBOARD, 0).
如果有理由在代码后面的任何地方回溯,这可以无限期地重复。一旦您的代码命中
ClientMsg
的最终检查,它将回溯到这个循环并永远停留在那里(它不会重新考虑证明 putpiecePC 的第一种方法,因为它认为证明它的方法已经失败——它不考虑随机性)。就我个人而言,我真的不喜欢使用额外的逻辑结构,但如果你已经这样做了,我相信引入另一个重复可能会成功:
putpiecePC(BOARD, PIECE, NEXTBOARD, 0):-
write('enter putpiecePC'), nl,
repeat,
random(0, 6, LINE),
random(0, 6, COLUMN),
putPiece(BOARD, PIECE, LINE, COLUMN, NEXTBOARD).
不过,解决这个问题的更好方法是避免主循环中的重复逻辑,并使其成为适当的递归。
编辑:
如果你遵循这个模式,事情应该会奏效。你可以试试这个代码。只需尝试目标“循环”并在 [0, 6] 之间输入数字。
test
将猜测它然后返回到主循环。 test
就像你的 putpiecePC 谓词。 loop
当然是主循环。loop :- loop(ignore).
loop(q) :- !.
loop(_) :-
writeln('guess!'),
read(X),
test(X),
loop(X).
test(q).
test(X) :-
writeln('test'),
repeat,
random(0, 6, LINE),
writeln(LINE),
LINE == X.
关于debugging - 为什么prolog进入无限循环?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20777091/