为什么prolog进入无限循环?

 mobiledu2502860983 发布于 2023-02-08 10:37

我正在开发一个项目,它基本上是一个带有游戏逻辑的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)

这是其中i从发送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,这是完全随机的)

这些是解析器调用的perdicates:

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

    2023-02-08 10:40 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有