Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Time limit in Prolog user input (read)

I'm writing an interpreter for a game. User enters its move to the interpreter and program executes that move.

Now I want to implement a time limit for each decision. Player shouldn't be able to think more than 30 seconds to write a move and press enter.

call_with_time_limit seemed relevant but it doesnt work properly as such:

call_with_time_limit( 30, read(X) ), Problem, write(Problem).

In this case, it waits for input, and when input is entered, timer starts afterwards. But I want the timer to start at the beginning.

How can I do it?

like image 953
aladagemre Avatar asked Oct 10 '22 06:10

aladagemre


2 Answers

If you are interested in I/O related timeouts please consider wait_for_input/3 or set_stream/2. The built-in you found, call_with_time_limit/2 is not a simple and reliable interface.

Edit: I just see that you use read/1 for input. Please read in above documentation how to avoid blocking in read/1. It is not clear to me why you need this, but a user might simply enter Return, thereby circumventing the initial timeout. read/1 would now read that '\n' but then would wait for further input - without a timeout, while the user lavishly skims Wikipedia for the answer... might even ask the question on SO...

like image 192
false Avatar answered Oct 13 '22 11:10

false


Your approach seems sensible: from the SWI-Prolog docs: 'Blocking I/O can be handled using the timeout option of read_term/3. '.

That's not really informative: changing timeout on user leads to some bug (I'll test more and will report to SWI_prolog mailing list if appropriate), even under catch/3.

The following seems to work

...,
current_input(I),
wait_for_input([I], A, 30),
...

If not input given (shorter time to test here...)

?- current_input(I), wait_for_input([I],A,5).
I = <stream>(0x7fa75bb31880),
A = [].

EDIT: the variable A will keep the list will contain the list of streams with ready input: I just reported the case where the user doesn't input anything before the timeout occurs. To get the actual input, using your supplied code:

tql :-
    current_player(I),
    writef('Its %d. players turn: ', [I]),
    flush_output,
    current_input(Input),
    wait_for_input([Input], [Input], 5),
    read(Input, Move),
    writeln(Move).

current_player(1).

HTH

like image 34
CapelliC Avatar answered Oct 13 '22 09:10

CapelliC