debugging - 为什么prolog进入无限循环?

标签 debugging prolog infinite-loop

我正在开发一个项目,它基本上是一个具有游戏逻辑的 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 时才有效。是 quitend_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/

相关文章:

c++ - 用于调试内存使用情况的工具?

windows - 如何让调试器强制 Windows 线程从 sleep 状态唤醒?

测试 "Safe term order"谓词

java - 使用推土机进行集合映射时无限循环

java - 使用 Java 8 在 Windows 上调试 spark 进程

c - CodeBlocks 13.12 上的 Valgrind

list - Prolog 中的元素处理问题,但不在常规列表中?

prolog - 简单的 Prolog 生成器

Javascript 正则表达式导致脚本无响应

c - 由于舍入,c 中的无限循环?