4
votes

Im working on a project which is basicly a prolog server with the logic for a game, which is communicating with a c++ openGL program that renders the information received from prolog for the game drawing.

This is the server loop, which starts after the connection is successful:

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), !.

Its filled with writes because ive been debugging this for hours.

The important parts to note here are:

parse_input(ClientMsg, MyReply)

which is where i send all messages received from c++, and the methods i have for parse_input at the moment are the following:

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).

They are pretty similar. The first is for a player play (the position of the play is specified) and the second is for computer play (the AI is the value of inteligence i want the computer to have, lets only consider the value 0, which is completely random)

These are the perdicates called by the parsers:

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).

I do realise the putpieceHuman is kinda redundant but it was for the sake of maintaining the pattern. So, putPiece is the perdicate that returns a board after it's been modified with the new play, and it fails if there is already a piece in the position to play.

when a human puts a piece, the c++ program filters bad input so its impossible the putPiece fails, therefore its a direct use, as u can see. putpiecePC in the other hand is done by randoms so as it can fail i added a perdicate that basicly repeats the first one, if it fails.

The problem is: when i play using the putpieceHuman, it works wonderfuly, but when i try to use the putpiecePC it goes infinite loop.

Here is Sicstus log after a human putpiece, a human rotation (ignore this), and finnaly a pc putpiece, beware that what i wrote above was translated and the log isnt so note the following:

colocaHumano = putpieceHuman
rodaHumano -> ignore this
colocaPC = putpiecePC

Ok, now the log:

| ?- 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)?                                     

I must also note that putpiecePC works if i call it in a direct call from sicstus, so the problem shouldnt be from it. Why is this happening?

1

1 Answers

6
votes

The problem has to do with the way you implemented your main loop (using repeat). This way of writing it will only work if all your code is deterministic, and hence, only if the ClientMsg is quit or end_of_file the program would end and otherwise it would backtrack to the initial repeat.

But that's not true in your code. You have a super obvious infinite loop built into your code

putpiecePC(BOARD, PIECE, NEXTBOARD, 0):- 
  write('putpiecePC failed'),
  putpiecePC(BOARD, PIECE, NEXTBOARD, 0).

This can be repeated indefinitely if there is a reason to backtrack anywhere later in the code. As soon as your code hits the eventual check of ClientMsg, it will backtrack into this loop and stay there forever (it will not reconsider the first way of proving putpiecePC because it believes that that way of proving it has already failed -- it doesn't reason about randomness).

Personally, I really don't like using extra-logical constructs, but if you are doing it already, I believe introducing yet another repeat might do the trick:

putpiecePC(BOARD, PIECE, NEXTBOARD, 0):-
    write('enter putpiecePC'), nl,
    repeat,
    random(0, 6, LINE),
    random(0, 6, COLUMN),
    putPiece(BOARD, PIECE, LINE, COLUMN, NEXTBOARD).

The better way to solve this though, would be to avoid the repeat logic in the main loop and make it a proper recursion instead.

EDIT:

If you follow this pattern, things should work. You can try this code. Just try the goal "loop" and enter numbers between in [0, 6]. test will guess it and then return to the main loop. test is like your putpiecePC predicate. loop is of course the main 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.