Chess Engine
C++ chess engine with movegen, bitboards, and Arduino-friendly docs
Loading...
Searching...
No Matches
misc.cpp
Go to the documentation of this file.
1#include "misc.h"
2
3#include <chrono>
4#include <cstdio>
5#include <cstring> // std::strchr, std::strncmp, std::strlen
6
7#ifdef _WIN32
8 #define NOMINMAX
9 #include <windows.h>
10#else
11 #include <sys/select.h>
12 #include <sys/time.h>
13 #include <unistd.h>
14#endif
15
16
17int GetTimeMs() {
18 using namespace std::chrono;
19 // steady_clock is monotonic; good for measuring elapsed time
20 const auto now = steady_clock::now().time_since_epoch();
21 const auto ms = duration_cast<milliseconds>(now).count();
22 // Match legacy signature: int (wrap after ~24 days is fine for engines)
23 return static_cast<int>(ms);
24}
25
27#ifdef _WIN32
28 // Handle both console and pipe input (similar idea to original)
29 static bool initialized = false;
30 static HANDLE hIn = nullptr;
31 static bool isPipe = false;
32
33 if (!initialized) {
34 initialized = true;
35 hIn = GetStdHandle(STD_INPUT_HANDLE);
36
37 DWORD mode = 0;
38 isPipe = (hIn == nullptr) || !GetConsoleMode(hIn, &mode);
39 if (!isPipe && hIn) {
40 // Disable mouse/window input so keypresses register as events
41 SetConsoleMode(hIn, mode & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT));
42 FlushConsoleInputBuffer(hIn);
43 }
44 }
45
46 if (isPipe) {
47 DWORD bytesAvailable = 0;
48 if (!PeekNamedPipe(hIn, nullptr, 0, nullptr, &bytesAvailable, nullptr)) {
49 // If PeekNamedPipe fails, assume something is there (like closed pipe)
50 return 1;
51 }
52 return static_cast<int>(bytesAvailable);
53 } else {
54 // Console: check number of pending events
55 DWORD events = 0;
56 if (!GetNumberOfConsoleInputEvents(hIn, &events)) return 0;
57 // The console always maintains at least one event; consider >1 as real input
58 return (events <= 1) ? 0 : static_cast<int>(events);
59 }
60#else
61 fd_set readfds;
62 FD_ZERO(&readfds);
63 FD_SET(STDIN_FILENO, &readfds);
64
65 timeval tv;
66 tv.tv_sec = 0;
67 tv.tv_usec = 0;
68
69 const int nfds = STDIN_FILENO + 1;
70 const int ret = select(nfds, &readfds, nullptr, nullptr, &tv);
71 if (ret <= 0) return 0;
72 return FD_ISSET(STDIN_FILENO, &readfds) ? 1 : 0;
73#endif
74}
75
76
78 if (!info) return;
79
80 if (!InputWaiting()) return;
81
82 // Mirror original behavior: mark stopped when we detect input
83#ifdef TRUE
84 info->stopped = TRUE;
85#else
86 info->stopped = true;
87#endif
88
89#ifdef _WIN32
90 static HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
91
92 // Read one line if available
93 char buffer[256] = {0};
94 DWORD readBytes = 0;
95
96 // Use non-blocking Peek then ReadConsole/ReadFile depending on mode
97 DWORD bytesAvail = 0;
98 if (PeekNamedPipe(hIn, nullptr, 0, nullptr, &bytesAvail, nullptr) && bytesAvail > 0) {
99 if (ReadFile(hIn, buffer, sizeof(buffer) - 1, &readBytes, nullptr)) {
100 // Normalize to line
101 if (char* eol = std::strchr(buffer, '\n')) *eol = '\0';
102 }
103 } else {
104 // Fall back to fgets on stdin (console scenario)
105 if (std::fgets(buffer, sizeof(buffer), stdin)) {
106 if (char* eol = std::strchr(buffer, '\n')) *eol = '\0';
107 }
108 }
109
110 if (std::strlen(buffer) > 0) {
111 if (!std::strncmp(buffer, "quit", 4)) {
112#ifdef TRUE
113 info->quit = TRUE;
114#else
115 info->quit = true;
116#endif
117 }
118 }
119#else
120 // POSIX: safe to read because InputWaiting() confirmed data is there
121 char buffer[256] = {0};
122 ssize_t n = ::read(STDIN_FILENO, buffer, sizeof(buffer) - 1);
123 if (n > 0) {
124 buffer[n] = '\0';
125 if (char* eol = std::strchr(buffer, '\n')) *eol = '\0';
126
127 if (std::strlen(buffer) > 0) {
128 if (!std::strncmp(buffer, "quit", 4)) {
129#ifdef TRUE
130 info->quit = TRUE;
131#else
132 info->quit = true;
133#endif
134 }
135 }
136 }
137#endif
138}
@ TRUE
Definition defs.h:57
int GetTimeMs()
Definition misc.cpp:17
void ReadInput(S_SEARCHINFO *info)
Definition misc.cpp:77
int InputWaiting()
Definition misc.cpp:26
int quit
Definition defs.h:147
int stopped
Definition defs.h:148