1
0
Fork 0
mirror of https://gitlab.com/mfocko/CodeWars.git synced 2024-09-16 20:56:57 +02:00
CodeWars/4kyu/shortest_knight_path/solution.cpp
Matej Focko fd3b272a35
4kyu: add „Shortest Knight Path“
• also move ISBN10 validation to correct language section

Signed-off-by: Matej Focko <mfocko@redhat.com>
2022-08-11 19:50:35 +02:00

141 lines
3.6 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <cassert>
#include <deque>
#include <iostream>
#include <string>
#include <vector>
namespace {
int convert_column(char x) { return x - 'a'; }
int convert_row(char y) { return y - '1'; }
template <typename T> bool in_range(const T &x, const T &min, const T &max) {
return min <= x && x < max;
}
template <typename T> using table_t = std::vector<std::vector<T>>;
static const std::vector<std::pair<int, int>> dpos{
{-2, 1}, {-2, -1}, {-1, 2}, {-1, -2}, {1, 2}, {1, -2}, {2, 1}, {2, -1}};
static const int dpos_size = static_cast<int>(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<int, int> &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 <typename T> T &in(table_t<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<char>('a' + pos.x())
<< static_cast<char>('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<int> distances(8, std::vector<int>(8, -1));
src.in(distances) = 0;
// run BFS and break once finish is found
std::deque<position_t> 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;
}