Getting stockfish running as child process in C++ - c++

I am currently trying to run simple tests with the Stockfish chess engine in C++ to get the best possible move. I am starting Stockfish as a child process and want to use the input and output streams to pass on the desired UCI commands, which I am exchanging with the parent process via a pipe. However, when I run the code, Stockfish just starts and nothing else happens. Typing in the UCI commands in the CLI then works, but that's obviously not the goal. What am I doing wrong?
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
using namespace std;
void sig_handler(int sig) {}
int main() {
int fd1[2];
if (pipe(fd1) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
int pid = fork();
if (pid == 0) {
execl("./stockfish", "./stockfish", nullptr);
close(fd1[1]);
char position[60];
read(fd1[0], position, 60);
close(fd1[0]);
cout << "position " << position << endl;
cout << "go" << endl;
sleep(5000);
cout << "stop" << endl;
string move;
cin >> move;
exit(0);
}
else {
close(fd1[0]);
cout << "Parent process" << endl;
string line = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
write(fd1[1], line.c_str(), strlen(line.c_str()) + 1);
close(fd1[1]);
signal(SIGINT, &sig_handler);
wait(NULL);
cout << "Parent done" << endl;
}
return 0;
}

Thanks to #TedLyngmo and some research about the Boost library, it was very easy to implement:
#include <boost/process.hpp>
#include <boost/asio.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
using namespace std;
namespace bp = boost::process;
int main() {
bp::ipstream is;
bp::opstream os;
bp::child c("./stockfish", bp::std_in < os, bp::std_out > is);
os << "uci" << endl;
os << "isready" << endl;
os << "position fen rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" << endl;
os << "go depth 30" << endl;
string line;
string move_string;
while (getline(is, line)) {
if (!line.compare(0, 8, "bestmove")) {
move_string = line;
break;
}
}
// Delete the "bestmove" part of the string and get rid of any trailing characters divided by space
move_string = move_string.substr(9, move_string.size()-9);
vector<string> mv;
boost::split(mv, move_string, boost::is_any_of(" "));
cout << "Stockfish move: " << mv.at(0) << endl;
return 0;
}

Related

Read during a few second in C++

I want to know how can i read the standard input just for 5 seconds like you just have 5 seconds to write.
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string mystr;
cout << "What's your name? ";
getline (cin, mystr);
cout << "Hello " << mystr << ".\n";
cout << "What is your favorite team? ";
getline (cin, mystr);
cout << "I like " << mystr << " too!\n";
return 0;
}
Like that the user have all the time he want to write. Did getline or read have any option to force the getline to stop after 5sec ?
Thank you
A possible solution is to use poll() and write your own getline() function (tested on xubuntu 18.04 with g++ 7.5.0):
Here the implementation of my getline_timeout(int, std::string):
std::string getline_timeout(int ms, std::string def_value)
{
struct pollfd fds;
fds.fd = STDIN_FILENO;
fds.events = POLLIN;
int ret = poll(&fds, 1, ms);
std::string val;
if (ret > 0 && ((fds.revents & POLLIN) != 0)) {
//cout << "has data" << endl;
std::getline(std::cin, val);
} else {
//cout << "timeout / no data" << endl;
val = def_value;
}
return val;
}
#include <iostream>
#include <string>
#include <poll.h>
#include <unistd.h>
std::string getline_timeout(int ms, std::string def_value);
int main(int argc, char *argv[])
{
std::cout << "What's your name ? " << std::flush;
// Ask for the name
std::string mystr = getline_timeout(5000, "John Doe");
std::cout << "Hello " << mystr << std::endl;
std::cout << "What is your favorite team ? " << std::flush;
// Ask for the team
mystr = getline_timeout(5000, "Gryffindor");
std::cout << "I like " << mystr << " too!" << std::endl;
return 0;
}
The API getline() can not do what you want.
There are two way you can try:
- multi thread can work
- single thread with multiplexing IO like select/poll/epoll/iocp
In fact, they work same : setting a timer and wait for I/O input or timeout.

c++ evecvp error handling for invalid command

I am trying to implement a simple shell. Everything else works fine except for the error handling.
When I try to do execute an invalid command like "cat ff", in which "ff" does not exist, I got this:
The expected behavior should be like the third one "catt f". It must start with "ERROR:" and then the error message, which means it should be "ERROR:cat: ff: No such file or directory"
How should I modify my code to achieve that? Thanks in advance!
#include <fcntl.h>
#include <iostream>
#include <unistd.h>
#include <cstring>
#include <errno.h>
#include <sys/wait.h>
using namespace std;
int main(){
int pid;
int status;
char *cmd[] = {"cat", "ff", NULL};
if ((pid = fork()) == 0){
if (execvp(cmd[0], cmd) == -1){
cout << "ERROR:" << strerror(errno) << '\n';
}
}else if (pid == -1){
cout << "ERROR:" << strerror(errno) << '\n';
}else{
waitpid(pid, &status, 0);
cout << "Status: " << status << '\n';
}
}
The status here isn't very much necessary here. It is just my attempt to figure out whether it comes before that error message. I am super new to this and I am very confused and lost. Please forgive me if I did anything unnecessarily.
the second line cat: ff: No suche file... is an error output to stderr pipe written by cat command. If you want to suppress this you need to redirect stderr pipe. The execution of your shell command "cat" was successful, so it's handled through your last else condition. You need to check there for e.g. status 256 "no such file" and then print the error yourself.
#include <fcntl.h>
#include <iostream>
#include <unistd.h>
#include <cstring>
#include <errno.h>
#include <sys/wait.h>
#include <cstdio>
using namespace std;
int main(int argc, char** argv){
int pid;
int status;
char *cmd[] = {"cat", "ff", NULL};
int pipes[2];
pipe(pipes);
if ((pid = fork()) == 0){
dup2(pipes[1], STDERR_FILENO);
if (execvp(cmd[0], cmd) == -1){
cout << "ERROR:" << strerror(errno) << '\n';
}
}else if (pid == -1){
cout << "ERROR:" << strerror(errno) << '\n';
}else{
waitpid(pid, &status, 0);
if(256 == status) {
cout << "ERROR: ";
char buffer[100];
int count = read(pipes[0], buffer, sizeof(buffer)-1);
if (count >= 0) {
buffer[count] = 0;
cout << buffer;
cout << endl;
} else {
cout << "IO Error" << endl;
}
} else {
cout << "Status: " << status << '\n';
}
}
}

Placing Printed text in the same line as text before it

I'm currently making a basic program design to behave somewhat like a chell. The code is here:
#include <iostream>
#include <cstdlib>
#include <time.h>
#include <Windows.h>
#include <Stdio.h>
#include <string>
using namespace std;
main()
{
SetConsoleTextAttribute (GetStdHandle(STD_OUTPUT_HANDLE),10);
std::string name;
std::string pass;
std::string msg;
int x = 1;
srand(time(0));
cout << "Booting up system..." << endl;
cout << "Serial Code: " << (rand()%1000) << "." << endl;
cout << "Username: ";
std::getline(std::cin, name);
cout << "Password: ";
std::getline(std::cin, pass);
cout << "" << endl;
while (true)
{
cout<<x<<": ";
std::getline(std::cin, msg);
x += 1;
if (msg == "Hello!"){
cout << "Hi!" << endl;
}
if (msg == ""){
cout << "[No Text Inserted]" << endl;
}
system ("pause");
}
And, if no text is input it displays:
1:
[No Text Inserted]
How do I get this output?
1: [No Text Inserted]
Thank you in advance!
-DJ
In your if statements, store the string into a variable and print out in the end. Also if you're comparing the same variable, I recommend using if else statements. It makes it more readable. So:
string output;
if (msg == "Hello!)
{
output = "Hi!";
}
else if (msg == "")
{
output = "[No Text Inserted]";
}
output = x.str() + ": " + output;
cout << output << endl;
Try that out and let me know if that works.
What you could do is remember input cursor position and if the input is empty string, go back to that position and print your fail message, something like this:
#include <iostream>
#include <string>
#include <windows.h>
int main()
{
HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE);
std::string input;
std::cout << "Enter something: ";
// remember cursor position
CONSOLE_SCREEN_BUFFER_INFO info;
COORD inputPos = GetConsoleScreenBufferInfo(conout, &info) ? info.dwCursorPosition : COORD{ 0, 0 };
if (!std::getline(std::cin, input) || input.empty())
{
SetConsoleCursorPosition(conout, inputPos);
std::cout << "[No Text Inserted]" << std::endl;
}
}

write Unicode strings into a txt file

I made my simple txt scanner who writes the text into a file that matches my selection. The problem is writing to file when instead of the pen writes, for example, 洀漀. On picture you can see for example:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
int offset;
wstring DBSearchLine, ScanLine;
wifstream ScanFile, DBSearchFile;
wofstream ResultFile;
ScanFile.open("ScanFile.txt", ios_base::binary);
ResultFile.open("ResultFile.txt", ios::out, ios_base::binary);
if (ScanFile.is_open())
{
while (!ScanFile.eof())
{
DBSearchFile.open("DBSearchFile.txt", ios_base::binary);
if (!DBSearchFile.is_open())
{
cout << "Error open DBSearchFile.txt" << "\n";
break;
}
getline(ScanFile, ScanLine);
wcout << "Scan line is - " << ScanLine << "\n";
while (!DBSearchFile.eof())
{
getline(DBSearchFile, DBSearchLine);
wcout << "DBSearchLine is -" << DBSearchLine << "\n";
if ((offset = ScanLine.find(DBSearchLine, 0)) != string::npos)
{
ResultFile << ScanLine << L"\n";
}
}
DBSearchFile.close();
}
ScanFile.close();
}
else
{
cout << "Error open ScanFile.txt" << "\n";
}
system("PAUSE");
return 0;
}
#include <iostream>
#include <fstream>
#include <string>
#include <locale>
#include <codecvt>
using namespace std;
int main()
{
/* via http://stackoverflow.com/a/5105192/4005233
changes the encoding of the console and all subsequently opened
files */
std::locale::global(std::locale(""));
wifstream ScanFile;
ScanFile.open("ScanFile.txt", ios_base::binary);
if (!ScanFile.is_open()) {
cout << "Error open ScanFile.txt" << "\n";
return 1;
}
wofstream ResultFile("ResultFile.txt", ios::out);
while (!ScanFile.eof())
{
wifstream DBSearchFile;
DBSearchFile.open("DBSearchFile.txt", ios_base::binary);
if (!DBSearchFile.is_open())
{
cout << "Error open DBSearchFile.txt" << "\n";
break;
}
wstring ScanLine;
getline(ScanFile, ScanLine);
wcout << "Scan line is - " << ScanLine << "\n";
do
{
wstring DBSearchLine;
getline(DBSearchFile, DBSearchLine);
// have all lines been read?
if(!DBSearchLine.length())
break;
wcout << "DBSearchLine is -" << DBSearchLine << "\n";
if (ScanLine.find(DBSearchLine, 0) != string::npos)
{
ResultFile << ScanLine << L"\n";
break; // found a match, no need to search further
}
}while(1);
DBSearchFile.close();
}
ScanFile.close();
return 0;
}
This was tested using files with and without a BOM.
The innermost loop had to be changed to handle files with a newline character at the end; if I hadn't done that it would have match with an empty string which is always true.
(I've also changed a few other things according to my coding style, the important change is the one right at the top)

fstream get(char*, int) how to operate empty line?

code in strfile.cpp:
#include <fstream>
#include <iostream>
#include <assert.h>
#define SZ 100
using namespace std;
int main(){
char buf[SZ];
{
ifstream in("strfile.cpp");
assert(in);
ofstream out("strfile.out");
assert(out);
int i = 1;
while(!in.eof()){
if(in.get(buf, SZ))
int a = in.get();
else{
cout << buf << endl;
out << i++ << ": " << buf << endl;
continue;
}
cout << buf << endl;
out << i++ << ": " << buf << endl;
}
}
return 0;
}
I want to operate all file
but in strfile.out:
1: #include <fstream>
2: #include <iostream>
3: #include <assert.h>
4: ...(many empty line)
I know that fstream.getline(char*, int) this function can manage it,but I want to know how to do this just use the function "fstream.get()".
Because ifstream::get(char*,streamsize) will leave the delimiter (in this case \n) on the stream, your call never advances and thus it appears to your calling program that you are endlessly reading blank lines.
Instead you need to determine if a newline is waiting on the stream, and move past it using in.get() or in.ignore(1):
ifstream in("strfile.cpp");
ofstream out("strfile.out");
int i = 1;
out << i << ": ";
while (in.good()) {
if (in.peek() == '\n') {
// in.get(buf, SZ) won't read newlines
in.get();
out << endl << i++ << ": ";
} else {
in.get(buf, SZ);
out << buf; // we only output the buffer contents, no newline
}
}
// output the hanging \n
out << endl;
in.close();
out.close();