diff --git a/4kyu/shortest_knight_path/solution.cpp b/4kyu/shortest_knight_path/solution.cpp new file mode 100644 index 0000000..db5ee8d --- /dev/null +++ b/4kyu/shortest_knight_path/solution.cpp @@ -0,0 +1,141 @@ +#include +#include +#include +#include +#include + +namespace { + +int convert_column(char x) { return x - 'a'; } +int convert_row(char y) { return y - '1'; } + +template bool in_range(const T &x, const T &min, const T &max) { + return min <= x && x < max; +} + +template using table_t = std::vector>; + +static const std::vector> dpos{ + {-2, 1}, {-2, -1}, {-1, 2}, {-1, -2}, {1, 2}, {1, -2}, {2, 1}, {2, -1}}; +static const int dpos_size = static_cast(dpos.size()); + +class position_t; +std::ostream &operator<<(std::ostream &stream, const position_t &pos); + +class position_t { + int _x, _y; + +public: + position_t(int x, int y) : _x(x), _y(y) {} + position_t(const std::pair &coords) + : _x(coords.first), _y(coords.second) {} + position_t(const std::string &position) + : _x(convert_column(position[0])), _y(convert_row(position[1])) {} + + int x() const { return _x; } + int y() const { return _y; } + bool in_bounds() const { return in_range(_x, 0, 8) && in_range(_y, 0, 8); } + + template T &in(table_t &table) const { return table[_y][_x]; } + + bool operator==(const position_t &other) const { + return _x == other._x && _y == other._y; + } + bool operator!=(const position_t &other) const { + return _x != other._x || _y != other._y; + } + position_t operator+(const position_t &other) const { + return {_x + other._x, _y + other._y}; + } +}; + +std::ostream &operator<<(std::ostream &stream, const position_t &pos) { + stream << static_cast('a' + pos.x()) + << static_cast('1' + pos.y()); + return stream; +} + +class adjacent_iterator { + const position_t pos; + int i; + + position_t position() const { return pos + position_t(dpos[i]); } + + adjacent_iterator &next() { + do { + i++; + } while (i < dpos_size && !position().in_bounds()); + return *this; + } + +public: + adjacent_iterator(position_t pos) : pos(pos), i(-1) { next(); } + adjacent_iterator(position_t pos, int i) : pos(pos), i(i) {} + + bool operator!=(const adjacent_iterator &other) const { + return pos != other.pos || i != other.i; + } + adjacent_iterator &operator++() { return next(); } + position_t operator*() const { return position(); } +}; + +class adjacent { + const position_t &pos; + +public: + adjacent(const position_t &pos) : pos(pos) {} + + adjacent_iterator begin() const { return {pos}; } + adjacent_iterator end() const { return {pos, dpos_size}; } +}; + +} // namespace + +int knight(std::string start, std::string finish) { + position_t src(start); + position_t dst(finish); + + // construct table + table_t distances(8, std::vector(8, -1)); + src.in(distances) = 0; + + // run BFS and break once ‹finish› is found + std::deque queue{src}; + while (!queue.empty()) { + position_t pos = queue.front(); + queue.pop_front(); + + int current_distance = pos.in(distances); + for (const auto &next_pos : adjacent(pos)) { + next_pos.in(distances) = current_distance + 1; + queue.push_back(next_pos); + + if (next_pos == dst) { + // We have just set distance to the seeked position + queue.clear(); + break; + } + } + } + + // return the distance to ‹finish› + return dst.in(distances); +} + +int main() { + // position_t p("b8"); + // std::cout << "Constructed from string: " << p << "\n"; + + // std::cout << "===adjacent===\n"; + // for (auto pos : adjacent(p)) { + // std::cout << pos << "\n"; + // } + + assert(knight("a1", "c1") == 2); + assert(knight("a1", "f1") == 3); + assert(knight("a1", "f3") == 3); + assert(knight("a1", "f4") == 4); + assert(knight("a1", "f7") == 5); + + return 0; +} diff --git a/README.md b/README.md index 510ff54..4637ab9 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,7 @@ - [Matrix Determinant](https://www.codewars.com/kata/52a382ee44408cea2500074c) - [solution](4kyu/matrix_determinant) - [Infix to Postfix Converter](https://www.codewars.com/kata/52e864d1ffb6ac25db00017f) - [solution](4kyu/infix_to_postfix_converter) - [Range Extraction](https://www.codewars.com/kata/51ba717bb08c1cd60f00002f) - [solution](4kyu/range_extraction) +- [Shortest Knight Path](https://www.codewars.com/kata/549ee8b47111a81214000941) - [solution](4kyu/shortest_knight_path) ### JS @@ -87,6 +88,7 @@ - [int32 to IPv4](https://www.codewars.com/kata/52e88b39ffb6ac53a400022e) - [solution](5kyu/i32_to_ipv4) - [Convert A Hex String To RGB](https://www.codewars.com/kata/5282b48bb70058e4c4000fa7) - [solution](5kyu/convert_a_hex_string_to_rgb) +- [ISBN-10 Validation](https://www.codewars.com/kata/51fc12de24a9d8cb0e000001) - [solution](5kyu/isbn10_validation) ### C++ @@ -94,7 +96,6 @@ - [Greed is Good](https://www.codewars.com/kata/5270d0d18625160ada0000e4) - [solution](5kyu/greed_is_good) - [Snakes and Ladders](https://www.codewars.com/kata/587136ba2eefcb92a9000027) - [solution](5kyu/snakes_and_ladders) - [The Clockwise Spiral](https://www.codewars.com/kata/536a155256eb459b8700077e) - [solution](5kyu/the_clockwise_spiral) -- [ISBN-10 Validation](https://www.codewars.com/kata/51fc12de24a9d8cb0e000001) - [solution](5kyu/isbn10_validation) ### Python