Running a separate console app from within Xojo

Although I have been using Xojo for many years, I am trying to do something new (for me) and write a chess GUI interface that uses the open source stockfish engine. This engine is a console app and takes input from the console and returns the best move as a string. What I seek is a way to start this app from within a separate Xojo app, feed in the necessary information and use the best move string that is returned. Can anyone point me to a discussion of how to do this?

Although not important to the above question, the stockfish engine use the UCI protocol, which is string based and very simple. So all input and output is in the form of strings that show up inside a terminal window.

Thanks in advance for helping me with this problem.

Can you use a Shell?

I would be happy to use a Shell if I knew what one was!

a Class that behaves in many ways LIKE a terminal window (although there are some significant differences) that you can send commands to a program and get responses

Shell is a Xojo statement.

See the Xojo help example for the details.

Shell will let you run an external program and return the complete output of that command into a string that would normally print to a terminal window. You will then be able to parse that output to get the parts you need.

If the command line program requires keyboard input you will have to likely have to put your “input” into a text file and then redirect that input to the console program as if it came from the keyboard. Something like this:

YourProgramName < TextFileOfCommands.txt

Where the TextFileOfCommands.txt will contain the input you would normally type as keyboard input after launching the program. The LessThan symbol makes the operating system copy the content of the text file into the program as if it was input by the keyboard. It is possible this may not work if the program does not use the standard In/Out method for input and output.

You can test this method by creating the TextFileOfCommands.txt file with a text editor then entering the command line above directly in a console window.

If the command line program can accommodate input as parameter(s) on the command line then the Shell command in Xojo can pass that on the command line when it calls the console program.

I hope this makes sense.

[quote=325737:@Mark Strickland]Shell is a Xojo statement.
[/quote]
Shell is a Class which you create new instances of using “New Shell” (or dropping an instance on a layout but that still calls “New Shell” to create the instance at runtime)

Str(), Mid() etc are statements

Kem, Norman and Mark- Thanks for your helpful comments and suggestions.

The language reference makes a distinction between a shell command and running a console app, and it is not clear I can do what I need to do by using a shell.

Here is the situation. I have a console app called stockfish-8-64. When I double click on it, it opens a terminal window into which I can type commands and receive the output. How would I start up this console app inside a Xojo app and direct input and collect output from it. In essence I need to setup a terminal like operation inside my app, and i cannot figure out how to do that.

While the OS is starting Terminal for you as a convenience, you typically start console apps by getting into a shell (like Terminal) and typing the path to it, then giving it its parameters, like so:

/path/to/stockfish-8-64 params

In Xojo, you’d do it this way:

dim sh as new Shell
sh.Execute "/path/to/stockfish-8-64 params"

Then you can check the Shell’s Result.

I just downloaded the engine (nice!) and it looks like you need to run this in Interactive move (Shell.Mode = 2). This will let you keep the shell up and running and you Write commands to it and read the results in the events.

I suggest writing a class around this, but the Shell can do what you want.

Kem-

I am going to give this a try tomorrow and will let you know how things go. Thanks for your help!

Do this

[code]Dim terminal as shell
Terminal.mode = 2
Terminal.execute (“path-to-shell-app-with-commands”)
Do
Loop until terminal.isrunning

Msgbox terminal.readall[/code]

Of course it would be better to put this in thread because the do-loop will freeze your app.

Following the above suggestions, I tried the following code in my open event…

[code]dim sinput,rtrn,path as string
dim f as new folderitem

// dim mShell as Shell <-- now in window properties
mShell = New Shell
mShell.Mode = 2

path = f.AbsolutePath+“stockfish-8-64”

output_text.text = path+endofline // print the path to my output channel

mshell.execute path[/code]

The above code fails. The path is treated like a command, and the command fails with the error shown.

Macintosh HD:_Active Basic:Chess:stockfish-8-64
bash: Macintosh: command not found

What am I doing wrong? The path to the app is correct, but the path is parsed as a unix command, not a path to my app.

A unix shell requires the unix-style path, even on a Mac. The AbsolutePath property gives you the Mac-style path while NativePath gives you a PosixPath and ShellPath gives you the proper path already escaped.

Short answer: Use ShellPath, not AbsolutePath.

You can use the NativePath too but then you need to use quotes. But ShellPath is preferable.

On a side note to Robert Birge :
You are aware there are backers dozen of frontends for Stockfish (Win, Mac and Linux)? Some really nice with 3D representation. Also, you cannot use it for commercial purposes.

Not according to their page on GitHub:

(emphasis mine)

https://github.com/official-stockfish/Stockfish

.[quote=325845:@Christoph De Vocht]On a side note to Robert Birge :
You are aware there are backers dozen of frontends for Stockfish (Win, Mac and Linux)? Some really nice with 3D representation. Also, you cannot use it for commercial purposes.[/quote]

Actually, I will give my program away for free to anyone who wants it provided I can get it to work. But I agree, there are many excellent frontends already out there, and I use a few of them often. I am doing this project to learn how to run console apps from within Xojo. Ultimately, I seek to use this capability to run molecular orbital calculations from within Xojo.

As Kem pointed out, it appears we can even sell Stockfish on our own provided we include the source code. You have to love the GNU GPL.

Thanks Kem. I can now start Stockfish from within my app. What remains is for me to figure out how to send it additional commands. Based on the language reference, this can be done with the Write command, as follows:

mShell.Write(sinput)
mShell.Write(Chr(13))

where sinput is a string command to the running stockfish. But stockfish either stops running immediately (even though I have set mShell.Mode = 2) or mShell.Write is not the correct statement to use.

Any suggestions would be welcome. I am almost there thanks to all the help!

You need to implement the DataAvailable event and respond to the app from there. Ie., give it time to finish the last command before you give it the next one.

Actually, I was using that event, but I discovered that placing that write commands inside a control was the problem. I made mShell a property of the window, but it was going out of scope when I left the open event of that window. What I clearly dont understand is what defines “going out of scope”. It seems like I must do all manipulation of the shell inside a single method or event, and cannot use a timer or multiple methods to communicate with the shell, even though it is inside the same window. This will make it tricky for me to write an interactive chess program that uses timers to monitor the status of the shell or the player. The alternative is to restart the shell at each move by the computer, but that would be very inefficient.

if you have code that is like in an event

   dim s as new shell
   s.execute

then when that event exits the things declared and instantiated IN that code will disappear (there are some exceptions but this is the normal behaviour)

So if you want to use a shell in more than one place you need to

  1. have an instance of a “shell object” that you dragged on to the window (which keeps the object instance alive until that window is closed at which time the instance is destroyed)
  2. have a property on the window that, when the window opens you set the property to a new instance and that stays around until the window closes at which time the shell property is destroyed