diff --git a/src/common/lib/Helper.cpp b/src/common/lib/Helper.cpp new file mode 100644 index 0000000..b483a2f --- /dev/null +++ b/src/common/lib/Helper.cpp @@ -0,0 +1,249 @@ +#include "Helper.h" + +#include + +inline bool Helper::traceErrors = true; + +Helper::ScopedTraceErrorDisabler::ScopedTraceErrorDisabler() +{ + DisableTraceErrors(); +} + +Helper::ScopedTraceErrorDisabler::~ScopedTraceErrorDisabler() +{ + ResetTraceErrors(); +} + +std::vector Helper::Split(const std::string& str, const std::string& delim) +{ + std::vector split; + size_t pos = str.find(delim); + size_t lastPos = 0; + while (pos != std::string::npos) + { + split.emplace_back(std::string_view{str.c_str() + lastPos, pos - lastPos}); + lastPos = pos + delim.size(); + pos = str.find(delim, pos + delim.size()); + } + split.emplace_back(std::string_view{str.c_str() + lastPos, str.size() - lastPos}); + return split; +} + +bool Helper::StartsWith(const std::string_view& str, const std::string& prefix, size_t offset) +{ + return str.substr(offset, prefix.size()) == prefix; +} + +bool Helper::EndsWith(const std::string_view& str, const std::string& prefix) +{ + return str.substr(str.size() - prefix.size(), prefix.size()) == prefix; +} + +void Helper::Replace(std::string& str, size_t size, const std::string& other, size_t pos) +{ + str.replace(pos, size, other); +} + +bool Helper::IsDigit(char c) +{ + return c >= '0' && c <= '9'; +} + +int Helper::GetNumberOfDigits(int n) +{ + assert(n > 0); + // clang-format off + if (n < 10) return 1; + if (n < 100) return 2; + if (n < 1'000) return 3; + if (n < 10'000) return 4; + if (n < 100'000) return 5; + if (n < 1'000'000) return 6; + if (n < 10'000'000) return 7; + if (n < 100'000'000) return 8; + if (n < 1'000'000'000) return 9; + // clang-format on + return 10; +} + +int Helper::GetNumberOfDigits(int64_t n) +{ + assert(n > 0); + // clang-format off + if (n < 10) return 1; + if (n < 100) return 2; + if (n < 1'000) return 3; + if (n < 10'000) return 4; + if (n < 100'000) return 5; + if (n < 1'000'000) return 6; + if (n < 10'000'000) return 7; + if (n < 100'000'000) return 8; + if (n < 1'000'000'000) return 9; + if (n < 10'000'000'000) return 10; + if (n < 100'000'000'000) return 11; + if (n < 1'000'000'000'000) return 12; + if (n < 10'000'000'000'000) return 13; + if (n < 100'000'000'000'000) return 14; + if (n < 1'000'000'000'000'000) return 15; + if (n < 10'000'000'000'000'000) return 16; + if (n < 100'000'000'000'000'000) return 17; + if (n < 1'000'000'000'000'000'000) return 18; + // clang-format on + return 19; +} + +int64_t Helper::Pow10(int pow) +{ + int64_t p = 10; + for (int i = 1; i < pow; i++) + { + p *= 10; + } + return p; +} + +int Helper::BinStrToInt(const std::string& str) +{ + if (str.size() >= 32) + { + std::cout << "BinStrToInt: Too big string, use BinStrToInt64 instead" << std::endl; + return 0; + } + + int val = 0; + for (size_t i = 0; i < str.size(); i++) + { + if (str[i] == '1') + val |= (1 << (str.size() - i - 1)); + } + return val; +} + +int64_t Helper::BinStrToInt64(const std::string& str) +{ + if (str.size() >= 64) + { + std::cout << "BinStrToInt64: Too big string" << std::endl; + return 0; + } + + int64_t val = 0; + for (size_t i = 0; i < str.size(); i++) + { + if (str[i] == '1') + val |= (1ll << (str.size() - i - 1)); + } + return val; +} + +std::string Helper::Repeat(const std::string& str, int count) +{ + std::string s; + for (int i = 0; i < count; i++) + { + s += str; + } + return s; +} + +std::vector Helper::GetAllRegexMatches(const std::string& str, const std::string& regex) +{ + std::vector matches; + std::regex reg{regex}; + auto it = std::sregex_iterator(str.begin(), str.end(), reg); + auto end = std::sregex_iterator(); + for (; it != end; it++) + { + matches.emplace_back(it->str()); + } + return matches; +} + +std::vector Helper::GetNeighborDirections() +{ + return std::vector{Index2D{1, 0}, Index2D{0, 1}, Index2D{-1, 0}, Index2D{0, -1}}; +} + +Index2D Helper::GetDirection(char c) +{ + if (c == 'v' || c == 'V') + return Index2D{0, 1}; + if (c == '^') + return Index2D{0, -1}; + if (c == '>') + return Index2D{1, 0}; + if (c == '<') + return Index2D{-1, 0}; + std::cerr << "GetDirection: Invalid char: " << c << std::endl; + return Index2D{-1, -1}; +} + +int64_t Helper::ChineseRemainderTheoremTwo(int64_t mod1, int64_t mod2, int64_t remainder1, int64_t remainder2) +{ + int64_t i = remainder1; + while (true) + { + if (i % mod2 == remainder2) + return i; + + i += mod1; + } + return 0; +} + +int64_t Helper::ChineseRemainderTheorem(const std::vector& mods, const std::vector& remainders) +{ + int64_t currentMod = mods.front(); + int64_t currentRem = remainders.front(); + for (int i = 1; i < mods.size(); i++) + { + int64_t result = ChineseRemainderTheoremTwo(currentMod, mods[i], currentRem, remainders[i]); + currentRem = result; + currentMod = currentMod * mods[i]; + } + return currentRem; +} + +int64_t Helper::ChineseRemainderTheorem(const std::vector& mods, + std::vector remainders, + const std::vector& starts) +{ + for (int i = 0; i < mods.size(); i++) + { + remainders[i] = ((remainders[i] - starts[i]) % mods[i] + mods[i]) % mods[i]; + } + return ChineseRemainderTheorem(mods, remainders); +} + +uint64_t Helper::FastExponentiation(uint64_t start, uint64_t multiplication, uint64_t power, uint64_t mod) +{ + while (power > 0) + { + if (power % 2 == 0) + { + multiplication = (multiplication * multiplication) % mod; + power /= 2; + } + else + { + start = (start * multiplication) % mod; + power--; + } + } + return start; +} + +int64_t Helper::ManhattanDistance(const Index2D& from, const Index2D& to) +{ + return std::abs(from.x - to.x) + std::abs(from.y - to.y); +} + +void Helper::DisableTraceErrors() +{ + traceErrors = false; +} + +void Helper::ResetTraceErrors() +{ + traceErrors = true; +} diff --git a/src/common/lib/Helper.h b/src/common/lib/Helper.h index fba0459..ac090c9 100644 --- a/src/common/lib/Helper.h +++ b/src/common/lib/Helper.h @@ -9,7 +9,6 @@ #include #include #include -#include #include #include @@ -34,15 +33,8 @@ struct Helper { struct ScopedTraceErrorDisabler { - ScopedTraceErrorDisabler() - { - DisableTraceErrors(); - } - - ~ScopedTraceErrorDisabler() - { - ResetTraceErrors(); - } + ScopedTraceErrorDisabler(); + ~ScopedTraceErrorDisabler(); }; template @@ -51,129 +43,21 @@ struct Helper t.erase(std::remove_if(t.begin(), t.end(), func), t.end()); } - static std::vector Split(const std::string& str, const std::string& delim) - { - std::vector split; - size_t pos = str.find(delim); - size_t lastPos = 0; - while (pos != std::string::npos) - { - split.emplace_back(std::string_view{str.c_str() + lastPos, pos - lastPos}); - lastPos = pos + delim.size(); - pos = str.find(delim, pos + delim.size()); - } - split.emplace_back(std::string_view{str.c_str() + lastPos, str.size() - lastPos}); - return split; - } + static std::vector Split(const std::string& str, const std::string& delim); + static bool StartsWith(const std::string_view& str, const std::string& prefix, size_t offset = 0); + static bool EndsWith(const std::string_view& str, const std::string& prefix); + static void Replace(std::string& str, size_t size, const std::string& other, size_t pos); - static bool StartsWith(const std::string_view& str, const std::string& prefix, size_t offset = 0) - { - return str.substr(offset, prefix.size()) == prefix; - } - - static bool EndsWith(const std::string_view& str, const std::string& prefix) - { - return str.substr(str.size() - prefix.size(), prefix.size()) == prefix; - } - - static void Replace(std::string& str, size_t size, const std::string& other, size_t pos) - { - str.replace(pos, size, other); - } - - static bool IsDigit(char c) - { - return c >= '0' && c <= '9'; - } - - static int GetNumberOfDigits(int n) - { - assert(n > 0); - // clang-format off - if (n < 10) return 1; - if (n < 100) return 2; - if (n < 1'000) return 3; - if (n < 10'000) return 4; - if (n < 100'000) return 5; - if (n < 1'000'000) return 6; - if (n < 10'000'000) return 7; - if (n < 100'000'000) return 8; - if (n < 1'000'000'000) return 9; - // clang-format on - return 10; - } - - static int GetNumberOfDigits(int64_t n) - { - assert(n > 0); - // clang-format off - if (n < 10) return 1; - if (n < 100) return 2; - if (n < 1'000) return 3; - if (n < 10'000) return 4; - if (n < 100'000) return 5; - if (n < 1'000'000) return 6; - if (n < 10'000'000) return 7; - if (n < 100'000'000) return 8; - if (n < 1'000'000'000) return 9; - if (n < 10'000'000'000) return 10; - if (n < 100'000'000'000) return 11; - if (n < 1'000'000'000'000) return 12; - if (n < 10'000'000'000'000) return 13; - if (n < 100'000'000'000'000) return 14; - if (n < 1'000'000'000'000'000) return 15; - if (n < 10'000'000'000'000'000) return 16; - if (n < 100'000'000'000'000'000) return 17; - if (n < 1'000'000'000'000'000'000) return 18; - // clang-format on - return 19; - } - - static int64_t Pow10(int pow) - { - int64_t p = 10; - for (int i = 1; i < pow; i++) - { - p *= 10; - } - return p; - } + static bool IsDigit(char c); + static int GetNumberOfDigits(int n); + static int GetNumberOfDigits(int64_t n); + static int64_t Pow10(int pow); // Converts a binary string to an int32_t ie "10100111001" to 1337 - static int BinStrToInt(const std::string& str) - { - if (str.size() >= 32) - { - std::cout << "BinStrToInt: Too big string, use BinStrToInt64 instead" << std::endl; - return 0; - } - - int val = 0; - for (size_t i = 0; i < str.size(); i++) - { - if (str[i] == '1') - val |= (1 << (str.size() - i - 1)); - } - return val; - } + static int BinStrToInt(const std::string& str); // Converts a binary string to an int64_t ie "10100111001" to 1337 - static int64_t BinStrToInt64(const std::string& str) - { - if (str.size() >= 64) - { - std::cout << "BinStrToInt64: Too big string" << std::endl; - return 0; - } - - int64_t val = 0; - for (size_t i = 0; i < str.size(); i++) - { - if (str[i] == '1') - val |= (1ll << (str.size() - i - 1)); - } - return val; - } + static int64_t BinStrToInt64(const std::string& str); template static T Sum(const S& container) @@ -544,15 +428,7 @@ struct Helper return stream; } - static std::string Repeat(const std::string& str, int count) - { - std::string s; - for (int i = 0; i < count; i++) - { - s += str; - } - return s; - } + static std::string Repeat(const std::string& str, int count); template static std::vector Repeat(const std::vector& vec, int count) @@ -568,99 +444,27 @@ struct Helper return ret; } - static std::vector GetAllRegexMatches(const std::string& str, const std::string& regex) - { - std::vector matches; - std::regex reg{regex}; - auto it = std::sregex_iterator(str.begin(), str.end(), reg); - auto end = std::sregex_iterator(); - for (; it != end; it++) - { - matches.emplace_back(it->str()); - } - return matches; - } + static std::vector GetAllRegexMatches(const std::string& str, const std::string& regex); - static std::vector GetNeighborDirections() - { - return std::vector{Index2D{1, 0}, Index2D{0, 1}, Index2D{-1, 0}, Index2D{0, -1}}; - } - - static Index2D GetDirection(char c) - { - if (c == 'v' || c == 'V') - return Index2D{0, 1}; - if (c == '^') - return Index2D{0, -1}; - if (c == '>') - return Index2D{1, 0}; - if (c == '<') - return Index2D{-1, 0}; - std::cerr << "GetDirection: Invalid char: " << c << std::endl; - return Index2D{-1, -1}; - } + static std::vector GetNeighborDirections(); + static Index2D GetDirection(char c); // Solve for N: // remainder1 = N % mod1 // remainder2 = N % mod2 - static int64_t ChineseRemainderTheoremTwo(int64_t mod1, int64_t mod2, int64_t remainder1, int64_t remainder2) - { - int64_t i = remainder1; - while (true) - { - if (i % mod2 == remainder2) - return i; - - i += mod1; - } - return 0; - } + static int64_t ChineseRemainderTheoremTwo(int64_t mod1, int64_t mod2, int64_t remainder1, int64_t remainder2); // Solve for N: // remainders = N % mods - static int64_t ChineseRemainderTheorem(const std::vector& mods, const std::vector& remainders) - { - int64_t currentMod = mods.front(); - int64_t currentRem = remainders.front(); - for (int i = 1; i < mods.size(); i++) - { - int64_t result = ChineseRemainderTheoremTwo(currentMod, mods[i], currentRem, remainders[i]); - currentRem = result; - currentMod = currentMod * mods[i]; - } - return currentRem; - } + static int64_t ChineseRemainderTheorem(const std::vector& mods, const std::vector& remainders); // Solve for N: // remainders = (start + N) % mods static int64_t ChineseRemainderTheorem(const std::vector& mods, std::vector remainders, - const std::vector& starts) - { - for (int i = 0; i < mods.size(); i++) - { - remainders[i] = ((remainders[i] - starts[i]) % mods[i] + mods[i]) % mods[i]; - } - return ChineseRemainderTheorem(mods, remainders); - } + const std::vector& starts); - static uint64_t FastExponentiation(uint64_t start, uint64_t multiplication, uint64_t power, uint64_t mod) - { - while (power > 0) - { - if (power % 2 == 0) - { - multiplication = (multiplication * multiplication) % mod; - power /= 2; - } - else - { - start = (start * multiplication) % mod; - power--; - } - } - return start; - } + static uint64_t FastExponentiation(uint64_t start, uint64_t multiplication, uint64_t power, uint64_t mod); // Input - Puzzle input // Function - bool(int64_t); @@ -687,20 +491,11 @@ struct Helper return BinarySearch(input, min, i - 1, func); } - static int64_t ManhattanDistance(const Index2D& from, const Index2D& to) - { - return std::abs(from.x - to.x) + std::abs(from.y - to.y); - } + static int64_t ManhattanDistance(const Index2D& from, const Index2D& to); - static void DisableTraceErrors() - { - traceErrors = false; - } + static void DisableTraceErrors(); - static void ResetTraceErrors() - { - traceErrors = true; - } + static void ResetTraceErrors(); private: template @@ -763,8 +558,6 @@ public: static bool traceErrors; }; -inline bool Helper::traceErrors = true; - template static std::ostream& operator<<(std::ostream& stream, const std::vector& container) {