为什么prolog进入无限循环?

时间:2013-12-25 21:58:44

标签: 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).

我确实认识到,人体有点多余,但这是为了保持模式。因此,putPiece是在使用新游戏修改后返回棋盘的终结者,如果已经有一个位置可以玩,则会失败。

当一个人放置一个片段时,c ++程序会过滤坏的输入,因此putPiece失败是不可能的,因此它可以直接使用,正如你所看到的。另一方面,putpiecePC是由randoms完成的,因为它可能会失败我添加了一个基本重复第一个,如果它失败的perdicate。

问题是:当我使用putpieceHuman玩时,它的效果很奇妙,但是当我尝试使用putpiecePC时它会无限循环。

这是Sicstus日志之后的人类putpiece,人类旋转(忽略这一点),并且finnaly是一个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可以工作,所以问题不应该来自它。 为什么会这样?

1 个答案:

答案 0 :(得分:6)

问题与实现主循环的方式有关(使用repeat)。这种编写方式只有在所有代码都是确定性的情况下才有效,因此,只有当ClientMsgquitend_of_file时,程序才会结束,否则它将回溯到初始状态重复。

但是在你的代码中并非如此。你的代码中内置了一个非常明显的无限循环

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.