243 lines
5.8 KiB
C++
243 lines
5.8 KiB
C++
#pragma once
|
|
|
|
#include <fstream>
|
|
#include <sstream>
|
|
#include <vector>
|
|
#include <stdarg.h>
|
|
#include <stdexcept>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <algorithm>
|
|
#include <metrohash128/metrohash128.h>
|
|
|
|
// If we use NCurses, we need to use the appropriate printing function
|
|
#ifdef NCURSES
|
|
#include <ncurses.h>
|
|
#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<uint8_t *>(&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 <typename Out> 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<std::string> split(const std::string &s, char delim)
|
|
{
|
|
std::string newString = s;
|
|
std::replace(newString.begin(), newString.end(), '\n', ' ');
|
|
std::vector<std::string> 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 <typename T> inline std::vector<T> splitVector(const T size, const T n)
|
|
{
|
|
std::vector<T> 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<typename T> 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); };
|