Recent

Author Topic: TProcess - Catching output from several Process.Input.Write(...) commands  (Read 5225 times)

ajosifoski

  • Jr. Member
  • **
  • Posts: 55
Hi,
I want chess engine to analyze some game in pgn format.

Till now I have.
Code: [Select]
  P:=TProcess.Create(nil);
   stL:=TStringList.create;
   P.Commandline:='Houdini'; // <- this is chess engine, Houdini.exe
   P.Options:=P.Options+[poUsePipes];
   P.ShowWindow:=swoHide;
   P.Execute;


     st:='uci'+ Lineending;
     P.Input.Write(st[1], Length(st));
     // st:=P.Output.ReadAnsiString;    <- this is my try
     // showmessage(st);
     st:='setoption name multipv value 3'+lineending;
     P.Input.Write(st[1], Length(st)); // so after second command how to catch different output
     st:='isready'+lineending;
     P.Input.Write(st[1], Length(st));
     st:='ucinewgame'+lineending;
     P.Input.Write(st[1], Length(st));
     st:='isready'+lineending;
     P.Input.Write(st[1], Length(st));

    // This for loop is main loop for analyzing chess game
     for i:=1 to moves do begin
      st:='position fen '+arrayFen[i]+lineending;
      P.Input.Write(st[1], Length(st));
      st:='go movetime 1000'+lineending;  // Fen is position 1000ms is 1sec, so engine Must analyze 1 sec. that position, so go movetime 1000 is command.
      P.Input.Write(st[1], Length(st));
      Sleep(1000); // <- is this neccessary?
     end;


     st:='quit'+lineending;
     P.Input.Write(st[1], Length(st)); // quiting the engine


     stL.LoadFromStream(P.Output);
     stL.SaveToFile('AjDaVidime.txt');  // nothing stores particular
 


   P.Free;
   stL.Free;                     

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: TProcess - Catching output from several Process.Input.Write(...) commands
« Reply #1 on: November 19, 2013, 05:13:48 am »
 :) Hmm chess engine, nice idea. I'll try to help a little bit:

Code: [Select]
// st:=P.Output.ReadAnsiString;    <- this is my try
It will *not* work, because it was meant to be used after WriteAnsiString had been used. To be more accurate, it reads 4 bytes size of string from the stream prior to reading the string itself. Of course in your case the chess engine is not going to write the 4 bytes for size of string!!

Solution, maybe:

Code: [Select]
  if P.Output.NumBytesAvailable>0 then
  begin
    SetLength(st, P.Output.NumBytesAvailable);
    P.Output.ReadBuffer(st[1], P.Output.NumBytesAvailable);
  end;

Quote
// so after second command how to catch different output

Again, read NumBytesAvailable using ReadBuffer. That's the new output. NumBytesAvailable holds the number of bytes that you did NOT read yet.

Quote
Sleep(1000); // <- is this neccessary?

I tend to believe that the answer depends on the application you are running, chess engine here, so I don't know. If it did not work, just give it enough time to write its response before you hit it with another request!

I expected it to work, while using nslookup but it proved me wrong. And in general according to TProcess docs:

Quote
Note that writing to the stream may cause the calling process to be suspended when the created process is not reading from it's input, ...

Maybe someone with better knowledge can give us more.

Quote
     stL.LoadFromStream(P.Output);
     stL.SaveToFile('AjDaVidime.txt');  // nothing stores particular

It should work, but maybe data was not ready. stL.LoadFromStream(P.Output) internally calls P.Output.Read which is implemented. Do check:

Code: [Select]
  if P.Output.NumBytesAvailable>0 then

before your call LoadFromStream, ReadBuffer, or Read

You might want to know about TAsyncProcess in unit AsyncProcess, it has an event that fires when data is available.

ajosifoski

  • Jr. Member
  • **
  • Posts: 55
Re: TProcess - Catching output from several Process.Input.Write(...) commands
« Reply #2 on: November 19, 2013, 12:43:29 pm »
:) Hmm chess engine, nice idea. I'll try to help a little bit:

Code: [Select]
  if P.Output.NumBytesAvailable>0 then
  begin
    SetLength(st, P.Output.NumBytesAvailable);
    P.Output.ReadBuffer(st[1], P.Output.NumBytesAvailable);
  end;

You might want to know about TAsyncProcess in unit AsyncProcess, it has an event that fires when data is available.

That was quite helpfull, my understandig is better now.
However now I have idea to put that lines with checking NumBytesAvailable and reading buffer in ontimer event for let say 500ms but  interesting with TProcess  ontimer is not working at all?!

 >:(

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: TProcess - Catching output from several Process.Input.Write(...) commands
« Reply #3 on: November 19, 2013, 03:10:33 pm »
... ontimer is not working at all?!

One of a few things might cause your " >:( "

Being too tired.  ;D

Wrong event being used, like OnStartTimer or OnStopTimer instead of OnTimer

The timer is not started, enable your Timer:

Code: [Select]
YourTimer.Enabled := True
Misplaced code that stops the timer before closing the application, double check it or comment it out.

Edit:
One more thing. You are in trouble if OnTimer checks:

Code: [Select]
  if Process.Output.NumBytesAvailable>0 then

before you call Process.Execute, because Output is not valid yet!!. I have a strong feeling that this is your problem now.
« Last Edit: November 19, 2013, 04:32:41 pm by engkin »

 

TinyPortal © 2005-2018