Chapter 12

Miscellaneous Functions

The final functions in ABC are small utilities that connect the search with the outside world. They provide a portable millisecond timer and allow the engine to notice commands such as stop and quit while it is thinking.

int get_time_ms() {
    #ifdef WIN64
        return GetTickCount ();
    #else
        struct timeval t;
        gettimeofday (&t, NULL);
        return t.tv_sec*1000 + t.tv_usec/1000;
    #endif	
}

// Interact between search and GUI input
void communicate() {
    if(timeset == 1 && get_time_ms() > stoptime) stopped = 1;
    read_input();
}

// read GUI/user input
void read_input() {
    int bytes;
    char input[256] = "", *endc;
    if (input_waiting()) {
        stopped = 1;
        do bytes=read(fileno(stdin), input, 256);
        while (bytes < 0);
        endc = strchr(input,'\n');
        if (endc) *endc=0;
        if (strlen(input) > 0) {
            if (!strncmp(input, "quit", 4)) quit = 1;
            else if (!strncmp(input, "stop", 4)) quit = 1;
        }   
    }
}

// Listen to GUI input during search
int input_waiting() {
    #ifndef WIN32
        fd_set readfds;
        struct timeval tv;
        FD_ZERO (&readfds);
        FD_SET (fileno(stdin), &readfds);
        tv.tv_sec=0; tv.tv_usec=0;
        select(16, &readfds, 0, 0, &tv);
        return (FD_ISSET(fileno(stdin), &readfds));
    #else
        static int init = 0, pipe;
        static HANDLE inh;
        DWORD dw;
        if (!init) {
            init = 1;
            inh = GetStdHandle(STD_INPUT_HANDLE);
            pipe = !GetConsoleMode(inh, &dw);
            if (!pipe) {
                SetConsoleMode(inh, dw & ~(ENABLE_MOUSE_INPUT|ENABLE_WINDOW_INPUT));
                FlushConsoleInputBuffer(inh);
            }
        } if (pipe) {
           if (!PeekNamedPipe(inh, NULL, 0, NULL, &dw, NULL)) return 1;
           return dw;
        } else {
           GetNumberOfConsoleInputEvents(inh, &dw);
           return dw <= 1 ? 0 : dw;
        }
    #endif
}

Measuring Time

get_time_ms() provides a simple millisecond timer. On Windows it uses GetTickCount(), while on other systems it uses gettimeofday(). The rest of the engine can therefore work with the same time representation regardless of the operating system.

Communicating During Search

communicate() is called periodically by the search. It first checks whether the allocated search time has expired and sets stopped when the deadline is reached. It then calls read_input() so the engine can also react to commands from the GUI.

Reading Stop and Quit

read_input() first checks whether input is waiting. If it is, the command is read from standard input and the newline is removed. The important commands here are quit and stop. Both cause the engine to signal that the current search should stop; quit additionally sets quit so the main UCI loop can terminate.

Checking for Input

The last function, input_waiting(), is the platform-specific part. On Unix-like systems, select() performs a non-blocking check of standard input. On Windows, the function handles both pipe input and console input using the appropriate Windows APIs.

These utilities are small, but they complete an important part of the engine architecture: the search does not have to block while waiting for the GUI. It can continue thinking, periodically check the clock and input, and stop when the GUI or time control asks it to.

With these functions in place, the implementation of ABC is complete. From the 0x88 board and move encoding all the way through evaluation, search, UCI communication, and time management, every major component of the engine is now connected.