【问题标题】:Why is prolog entering infinite loop?为什么prolog进入无限循环?
【发布时间】:2016-04-20 20:30:44
【问题描述】:

我正在开发一个项目,该项目基本上是一个带有游戏逻辑的 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 是由随机完成的,因此它可能会失败,我添加了一个谓词,如果它失败了,它基本上会重复第一个。

问题是:当我使用 putpieceHuman 玩游戏时,它工作得非常好,但是当我尝试使用 putpiecePC 时,它进入了无限循环。

这是 Sicstus 日志,在人类推杆、人类旋转(忽略此)和最后一个 pc 推杆之后,请注意我上面写的内容已被翻译,因此请注意以下内容:

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,它就可以工作,所以问题不应该来自它。 为什么会这样?

【问题讨论】:

    标签: debugging prolog infinite-loop


    【解决方案1】:

    问题与您实现主循环的方式有关(使用重复)。这种编写方式只有在您的所有代码都是确定性的情况下才有效,因此,只有当 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.
    

    【讨论】:

    • 该解决方案虽然不起作用):并且使用适当的递归进行循环也失败了,它仍然是无限循环:/
    • 好的,我已经用一个相当详细的概念解决方案更新了答案,包括你的主循环。这似乎对我有用。
    • Nvm 我找到了解决方案,我用 OR 子句递归了主循环,它似乎工作正常,虽然我没有使用你的编辑你的回答让我意识到问题的位置所以非常感谢你的所有麻烦:)
    猜你喜欢
    • 1970-01-01
    • 2011-04-19
    • 2011-11-21
    • 2018-08-21
    • 2012-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多