Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -----------------------------------------------------------------------
- common.h
- -----------------------------------------------------------------------
- #pragma once
- #include <sstream>
- #include <string>
- #include <string_view>
- struct Position {
- int row = 0;
- int col = 0;
- bool operator==(Position rhs) const;
- bool operator<(Position rhs) const;
- bool IsValid() const;
- std::string ToString() const;
- static Position FromString(std::string_view str);
- static const int MAX_ROWS = 16384;
- static const int MAX_COLS = 16384;
- static const Position NONE;
- };
- -----------------------------------------------------------------------
- structures.cpp
- -----------------------------------------------------------------------
- #include "common.h"
- #include <algorithm>
- #include <cctype>
- #include <sstream>
- const int LETTERS = 26;
- const int MAX_POSITION_LENGTH = 17;
- const int MAX_POS_LETTER_COUNT = 3;
- const Position Position::NONE = {-1, -1};
- bool Position::operator==(const Position rhs) const {return (row == rhs.row) && (col == rhs.col);}
- bool Position::operator<(const Position rhs) const {return std::make_tuple(row, col) < std::make_tuple(rhs.row, rhs.col);}
- bool Position::IsValid() const {return (row >= 0 && col >= 0) && (row < MAX_ROWS && col < MAX_COLS);}
- std::string Position::ToString() const {
- if (IsValid()) {
- std::string converted_string;
- int columns = col;
- while (columns >= 0) {
- converted_string.insert(converted_string.begin(), 'A' + columns % LETTERS);
- columns = columns / LETTERS - 1;
- }
- converted_string += std::to_string(row + 1);
- return converted_string;
- } else {
- return "";
- }
- }
- Position Position::FromString(std::string_view str) {
- auto it = std::find_if(str.begin(), str.end(), [](const char c) {
- return !(std::isalpha(c) && std::isupper(c));
- });
- auto letters = str.substr(0, it - str.begin());
- auto digits = str.substr(it - str.begin());
- if ((letters.empty() || digits.empty())
- || (letters.size() > MAX_POS_LETTER_COUNT)
- || (std::isdigit(digits[0]) == 0)) {
- return Position::NONE;
- }
- int row = 0;
- std::istringstream row_in{std::string{digits}};
- if (!(row_in >> row) || !row_in.eof()) {
- return Position::NONE;
- }
- int col = 0;
- for (char ch : letters) {
- col *= LETTERS;
- col += ch - 'A' + 1;
- }
- return {row - 1, col - 1};
- }
- -----------------------------------------------------------------------
- test_runner_p.h
- -----------------------------------------------------------------------
- #pragma once
- #include <iostream>
- #include <map>
- #include <set>
- #include <sstream>
- #include <stdexcept>
- #include <string>
- #include <unordered_map>
- #include <vector>
- namespace TestRunnerPrivate {
- template <typename K, typename V, template <typename, typename> class Map>
- std::ostream& PrintMap(std::ostream& os, const Map<K, V>& m) {
- os << "{";
- bool first = true;
- for (const auto& kv : m) {
- if (!first) {
- os << ", ";
- }
- first = false;
- os << kv.first << ": " << kv.second;
- }
- return os << "}";
- }
- }
- template <class T>
- std::ostream& operator<<(std::ostream& os, const std::vector<T>& s) {
- os << "{";
- bool first = true;
- for (const auto& x : s) {
- if (!first) {
- os << ", ";
- }
- first = false;
- os << x;
- }
- return os << "}";
- }
- template <class T>
- std::ostream& operator<<(std::ostream& os, const std::set<T>& s) {
- os << "{";
- bool first = true;
- for (const auto& x : s) {
- if (!first) {
- os << ", ";
- }
- first = false;
- os << x;
- }
- return os << "}";
- }
- template <class K, class V>
- std::ostream& operator<<(std::ostream& os, const std::map<K, V>& m) {
- return TestRunnerPrivate::PrintMap(os, m);
- }
- template <class K, class V>
- std::ostream& operator<<(std::ostream& os, const std::unordered_map<K, V>& m) {
- return TestRunnerPrivate::PrintMap(os, m);
- }
- template <class T, class U>
- void AssertEqual(const T& t, const U& u, const std::string& hint = {}) {
- if (!(t == u)) {
- std::ostringstream os;
- os << "Assertion failed: " << t << " != " << u;
- if (!hint.empty()) {
- os << " hint: " << hint;
- }
- throw std::runtime_error(os.str());
- }
- }
- inline void Assert(bool b, const std::string& hint) {
- AssertEqual(b, true, hint);
- }
- class TestRunner {
- public:
- template <class TestFunc>
- void RunTest(TestFunc func, const std::string& test_name) {
- try {
- func();
- std::cerr << test_name << " OK" << std::endl;
- } catch (std::exception& e) {
- ++fail_count;
- std::cerr << test_name << " fail: " << e.what() << std::endl;
- } catch (...) {
- ++fail_count;
- std::cerr << "Unknown exception caught" << std::endl;
- }
- }
- ~TestRunner() {
- std::cerr.flush();
- if (fail_count > 0) {
- std::cerr << fail_count << " unit tests failed. Terminate" << std::endl;
- exit(1);
- }
- }
- private:
- int fail_count = 0;
- };
- #ifndef FILE_NAME
- #define FILE_NAME __FILE__
- #endif
- #define ASSERT_EQUAL(x, y) \
- { \
- std::ostringstream __assert_equal_private_os; \
- __assert_equal_private_os << #x << " != " << #y << ", " << FILE_NAME \
- << ":" << __LINE__; \
- AssertEqual(x, y, __assert_equal_private_os.str()); \
- }
- #define ASSERT(x) \
- { \
- std::ostringstream __assert_private_os; \
- __assert_private_os << #x << " is false, " << FILE_NAME << ":" \
- << __LINE__; \
- Assert(x, __assert_private_os.str()); \
- }
- #define RUN_TEST(tr, func) tr.RunTest(func, #func)
- -----------------------------------------------------------------------
- main.cpp
- -----------------------------------------------------------------------
- #include "common.h"
- #include "test_runner_p.h"
- #include <iostream>
- #include <string>
- #include <string_view>
- inline std::ostream& operator<<(std::ostream& output, Position pos) {
- return output << "(" << pos.row << ", " << pos.col << ")";
- }
- inline Position operator"" _pos(const char* str, std::size_t) {
- return Position::FromString(str);
- }
- namespace {
- void TestPositionAndStringConversion() {
- auto test_single = [](Position pos, std::string_view str) {
- ASSERT_EQUAL(pos.ToString(), str);
- ASSERT_EQUAL(Position::FromString(str), pos);
- };
- for (int i = 0; i < 25; ++i) {
- test_single(Position{i, i}, char('A' + i) + std::to_string(i + 1));
- }
- test_single(Position{0, 0}, "A1");
- test_single(Position{0, 1}, "B1");
- test_single(Position{0, 25}, "Z1");
- test_single(Position{0, 26}, "AA1");
- test_single(Position{0, 27}, "AB1");
- test_single(Position{0, 51}, "AZ1");
- test_single(Position{0, 52}, "BA1");
- test_single(Position{0, 53}, "BB1");
- test_single(Position{0, 77}, "BZ1");
- test_single(Position{0, 78}, "CA1");
- test_single(Position{0, 701}, "ZZ1");
- test_single(Position{0, 702}, "AAA1");
- test_single(Position{136, 2}, "C137");
- test_single(Position{Position::MAX_ROWS - 1, Position::MAX_COLS - 1}, "XFD16384");
- }
- void TestPositionToStringInvalid() {
- ASSERT_EQUAL((Position::NONE).ToString(), "");
- ASSERT_EQUAL((Position{-10, 0}).ToString(), "");
- ASSERT_EQUAL((Position{1, -3}).ToString(), "");
- }
- void TestStringToPositionInvalid() {
- ASSERT(!Position::FromString("").IsValid());
- ASSERT(!Position::FromString("A").IsValid());
- ASSERT(!Position::FromString("1").IsValid());
- ASSERT(!Position::FromString("e2").IsValid());
- ASSERT(!Position::FromString("A0").IsValid());
- ASSERT(!Position::FromString("A-1").IsValid());
- ASSERT(!Position::FromString("A+1").IsValid());
- ASSERT(!Position::FromString("R2D2").IsValid());
- ASSERT(!Position::FromString("C3PO").IsValid());
- ASSERT(!Position::FromString("XFD16385").IsValid());
- ASSERT(!Position::FromString("XFE16384").IsValid());
- ASSERT(!Position::FromString("A1234567890123456789").IsValid());
- ASSERT(!Position::FromString("ABCDEFGHIJKLMNOPQRS8").IsValid());
- }
- }//end namespace
- int main() {
- TestRunner tr;
- RUN_TEST(tr, TestPositionAndStringConversion);
- RUN_TEST(tr, TestPositionToStringInvalid);
- RUN_TEST(tr, TestStringToPositionInvalid);
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment