#pragma once #include #include #include #include #include #include #include #include #include // If we use NCurses, we need to use the appropriate printing function #ifdef NCURSES #include #define LOG printw #else #define LOG printf #endif // If we use NCurses, define the following useful functions #ifdef NCURSES // Function to check for keypress taken from https://github.com/ajpaulson/learning-ncurses/blob/master/kbhit.c inline int kbhit() { int ch, r; // turn off getch() blocking and echo nodelay(stdscr, TRUE); noecho(); // check for input ch = getch(); if (ch == ERR) // no input r = FALSE; else // input { r = TRUE; ungetch(ch); } // restore block and echo echo(); nodelay(stdscr, FALSE); return (r); } inline int getKeyPress() { while (!kbhit()) { usleep(100000ul); refresh(); } return getch(); } void initializeTerminal() { // Initializing ncurses screen initscr(); cbreak(); noecho(); nodelay(stdscr, TRUE); scrollok(stdscr, TRUE); } void clearTerminal() { clear(); } void finalizeTerminal() { endwin(); } void refreshTerminal() { refresh(); } #endif // NCURSES typedef _uint128_t hash_t; inline hash_t calculateMetroHash(uint8_t *data, size_t size) { MetroHash128 hash; hash.Update(data, size); hash_t result; hash.Finalize(reinterpret_cast(&result)); return result; } // Function to split a string into a sub-strings delimited by a character // Taken from stack overflow answer to https://stackoverflow.com/questions/236129/how-do-i-iterate-over-the-words-of-a-string // By Evan Teran template inline void split(const std::string &s, char delim, Out result) { std::istringstream iss(s); std::string item; while (std::getline(iss, item, delim)) { *result++ = item; } } inline std::vector split(const std::string &s, char delim) { std::string newString = s; std::replace(newString.begin(), newString.end(), '\n', ' '); std::vector elems; split(newString, delim, std::back_inserter(elems)); return elems; } // Taken from https://stackoverflow.com/questions/116038/how-do-i-read-an-entire-file-into-a-stdstring-in-c/116220#116220 inline std::string slurp(std::ifstream &in) { std::ostringstream sstr; sstr << in.rdbuf(); return sstr.str(); } #define EXIT_WITH_ERROR(...) exitWithError(__FILE__, __LINE__, __VA_ARGS__) inline void exitWithError [[noreturn]] (const char *fileName, const int lineNumber, const char *format, ...) { char *outstr = 0; va_list ap; va_start(ap, format); int ret = vasprintf(&outstr, format, ap); if (ret < 0) exit(-1); std::string outString = outstr; free(outstr); char info[1024]; snprintf(info, sizeof(info) - 1, " + From %s:%d\n", fileName, lineNumber); outString += info; throw std::runtime_error(outString.c_str()); } // Loads a string from a given file inline bool loadStringFromFile(std::string &dst, const std::string path) { std::ifstream fi(path); // If file not found or open, return false if (fi.good() == false) return false; // Reading entire file dst = slurp(fi); // Closing file fi.close(); return true; } // Save string to a file inline bool saveStringToFile(const std::string &src, const char *fileName) { FILE *fid = fopen(fileName, "w"); if (fid != NULL) { fwrite(src.c_str(), 1, src.size(), fid); fclose(fid); return true; } return false; } // Function to split a vector into n mostly fair chunks template inline std::vector splitVector(const T size, const T n) { std::vector subSizes(n); T length = size / n; T remain = size % n; for (T i = 0; i < n; i++) subSizes[i] = i < remain ? length + 1 : length; return subSizes; } inline std::string simplifyMove(const std::string &move) { std::string simpleMove; bool isEmptyMove = true; for (size_t i = 0; i < move.size(); i++) if (move[i] != '.' && move[i] != '|') { simpleMove += move[i]; isEmptyMove = false; } if (isEmptyMove) return "."; return simpleMove; } inline bool getBitFlag(const uint8_t value, const uint8_t idx) { if (((idx == 7) && (value & 0b10000000)) || ((idx == 6) && (value & 0b01000000)) || ((idx == 5) && (value & 0b00100000)) || ((idx == 4) && (value & 0b00010000)) || ((idx == 3) && (value & 0b00001000)) || ((idx == 2) && (value & 0b00000100)) || ((idx == 1) && (value & 0b00000010)) || ((idx == 0) && (value & 0b00000001))) return true; return false; } inline size_t countButtonsPressedString(const std::string &input) { size_t count = 0; for (size_t i = 0; i < input.size(); i++) if (input[i] != '.') count++; return count; }; template inline uint16_t countButtonsPressedNumber(const T &input) { uint16_t count = 0; if (input & 0b0000000000000001) count++; if (input & 0b0000000000000010) count++; if (input & 0b0000000000000100) count++; if (input & 0b0000000000001000) count++; if (input & 0b0000000000010000) count++; if (input & 0b0000000000100000) count++; if (input & 0b0000000001000000) count++; if (input & 0b0000000010000000) count++; if (input & 0b0000000100000000) count++; if (input & 0b0000001000000000) count++; if (input & 0b0000010000000000) count++; if (input & 0b0000100000000000) count++; if (input & 0b0001000000000000) count++; if (input & 0b0010000000000000) count++; if (input & 0b0100000000000000) count++; if (input & 0b1000000000000000) count++; return count; }; static auto moveCountComparerString = [](const std::string &a, const std::string &b) { return countButtonsPressedString(a) < countButtonsPressedString(b); }; static auto moveCountComparerNumber = [](const uint8_t a, const uint8_t b) { return countButtonsPressedNumber(a) < countButtonsPressedNumber(b); };