diff --git a/tasks/cow/cow_string.h b/tasks/cow/cow_string.h index 18527cf..05d60d4 100755 --- a/tasks/cow/cow_string.h +++ b/tasks/cow/cow_string.h @@ -1,4 +1,4 @@ #pragma once class CowString { -}; +}; \ No newline at end of file diff --git a/tasks/robot/checkers_topology.cpp b/tasks/robot/checkers_topology.cpp index fc62994..b142b43 100755 --- a/tasks/robot/checkers_topology.cpp +++ b/tasks/robot/checkers_topology.cpp @@ -1 +1,47 @@ #include "checkers_topology.h" +CheckersTopology::CheckersTopology(const std::vector>& field) : Topology(field) { +} +void CheckersTopology::Dfs(const Point& point, std::unordered_set& visited) const { + if (visited.contains(point)) { + return; + } + visited.insert(point); + + for (int dx = -1; dx <= 1; dx += 2) { + for (int dy = -1; dy <= 1; dy += 2) { + int ix = static_cast(point.x); + int iy = static_cast(point.y); + if (!IsInField(ix + dx, iy + dy)) { + continue; + } + Point cur_point = MovedPoint(point, dx, dy); + ix = static_cast(cur_point.x); + iy = static_cast(cur_point.y); + if (IsAvailable(cur_point)) { + continue; + } + if (!IsInField(ix + dx, iy + dy) || !IsAvailable(MovedPoint(cur_point, dx, dy))) { + continue; + } + Dfs(MovedPoint(cur_point, dx, dy), visited); + } + } +} +std::vector CheckersTopology::GetAllNeighbours(const Point& point) const { + std::unordered_set visited; + int ix = static_cast(point.x); + int iy = static_cast(point.y); + + Dfs(point, visited); + for (int dx = -1; dx <= 1; dx += 2) { + for (int dy = -1; dy <= 1; dy += 2) { + if (!IsInField(ix + dx, iy + dy)) { + continue; + } + visited.insert(MovedPoint(point, dx, dy)); + } + } + visited.erase(point); + + return std::vector(visited.begin(), visited.end()); +} \ No newline at end of file diff --git a/tasks/robot/checkers_topology.h b/tasks/robot/checkers_topology.h index 2f4a7d1..89dd898 100755 --- a/tasks/robot/checkers_topology.h +++ b/tasks/robot/checkers_topology.h @@ -1,5 +1,14 @@ #pragma once #include "topology.h" +#include -class CheckersTopology : public Topology {}; +class CheckersTopology : public Topology { +public: + explicit CheckersTopology(const std::vector>& field); + + std::vector GetAllNeighbours(const Point& point) const override; + +private: + void Dfs(const Point& point, std::unordered_set& visited) const; +}; \ No newline at end of file diff --git a/tasks/robot/knight_topology.cpp b/tasks/robot/knight_topology.cpp index aff8a65..4103051 100755 --- a/tasks/robot/knight_topology.cpp +++ b/tasks/robot/knight_topology.cpp @@ -1 +1,21 @@ #include "knight_topology.h" +KnightTopology::KnightTopology(const std::vector>& field) : Topology(field) { +} +std::vector KnightTopology::GetAllNeighbours(const Point& point) const { + std::vector result; + int ix = static_cast(point.x); + int iy = static_cast(point.y); + + for (int dx = -2; dx <= 2; dx++) { + for (int dy = -2; dy <= 2; dy++) { + if (abs(dx * dy) != 2) { + continue; + } + if (!IsInField(ix + dx, iy + dy)) { + continue; + } + result.emplace_back(MovedPoint(point, dx, dy)); + } + } + return result; +} \ No newline at end of file diff --git a/tasks/robot/knight_topology.h b/tasks/robot/knight_topology.h index f03d2a2..22305c8 100755 --- a/tasks/robot/knight_topology.h +++ b/tasks/robot/knight_topology.h @@ -2,4 +2,9 @@ #include "topology.h" -class KnightTopology : public Topology {}; +class KnightTopology : public Topology { +public: + explicit KnightTopology(const std::vector>& field); + + std::vector GetAllNeighbours(const Point& point) const override; +}; \ No newline at end of file diff --git a/tasks/robot/overflow_topology.cpp b/tasks/robot/overflow_topology.cpp index 2e80f0d..e438653 100755 --- a/tasks/robot/overflow_topology.cpp +++ b/tasks/robot/overflow_topology.cpp @@ -1 +1,26 @@ #include "overflow_topology.h" +OverflowTopology::OverflowTopology(const std::vector>& field) : Topology(field) { +} +std::vector OverflowTopology::GetAllNeighbours(const Point& point) const { + std::vector result; + int ix = static_cast(point.x); + int iy = static_cast(point.y); + + for (auto [dx, dy] : dd_) { + Point cur_point(point); + if (ix + dx < 0) { + cur_point.x = GetFieldWidth() - 1u; + } else if (ix + dx >= GetFieldWidth()) { + cur_point.x = 0u; + } + + if (iy + dy < 0) { + cur_point.y = GetFieldHigh() - 1u; + } else if (iy + dy >= GetFieldHigh()) { + cur_point.y = 0u; + } + result.emplace_back(cur_point); + } + + return result; +} \ No newline at end of file diff --git a/tasks/robot/overflow_topology.h b/tasks/robot/overflow_topology.h index aaeafaa..34a1569 100755 --- a/tasks/robot/overflow_topology.h +++ b/tasks/robot/overflow_topology.h @@ -2,4 +2,12 @@ #include "topology.h" -class OverflowTopology : public Topology {}; +class OverflowTopology : public Topology { +public: + explicit OverflowTopology(const std::vector>& field); + + std::vector GetAllNeighbours(const Point& point) const override; + +private: + const int dd_[4][2] = {{0, 1}, {-1, 0}, {0, -1}, {1, 0}}; +}; \ No newline at end of file diff --git a/tasks/robot/planar_topology.cpp b/tasks/robot/planar_topology.cpp index 6ba272c..13d6fae 100755 --- a/tasks/robot/planar_topology.cpp +++ b/tasks/robot/planar_topology.cpp @@ -1 +1,17 @@ #include "planar_topology.h" +PlanarTopology::PlanarTopology(const std::vector>& field) : Topology(field) { +} +std::vector PlanarTopology::GetAllNeighbours(const Point& point) const { + std::vector result; + int ix = static_cast(point.x); + int iy = static_cast(point.y); + + for (auto [dx, dy] : dd_) { + if (!IsInField(ix + dx, iy + dy)) { + continue; + } + result.emplace_back(MovedPoint(point, dx, dy)); + } + + return result; +} \ No newline at end of file diff --git a/tasks/robot/planar_topology.h b/tasks/robot/planar_topology.h index b46f883..8d8c1d5 100755 --- a/tasks/robot/planar_topology.h +++ b/tasks/robot/planar_topology.h @@ -2,4 +2,12 @@ #include "topology.h" -class PlanarTopology : public Topology {}; +class PlanarTopology : public Topology { +public: + explicit PlanarTopology(const std::vector>& field); + + std::vector GetAllNeighbours(const Point& point) const override; + +private: + const int dd_[4][2] = {{0, 1}, {-1, 0}, {0, -1}, {1, 0}}; +}; \ No newline at end of file diff --git a/tasks/robot/point.h b/tasks/robot/point.h index b85fe6a..a6f726a 100755 --- a/tasks/robot/point.h +++ b/tasks/robot/point.h @@ -1,8 +1,20 @@ #pragma once #include +#include struct Point { size_t x = 0; size_t y = 0; + + bool operator==(const Point& other) const { + return x == other.x && y == other.y; + } }; + +template <> +struct std::hash { + std::size_t operator()(const Point& point) const { + return (point.x + point.y * 132487) % 23489371; + } +}; \ No newline at end of file diff --git a/tasks/robot/robot.cpp b/tasks/robot/robot.cpp index 29ccf69..9dd0526 100755 --- a/tasks/robot/robot.cpp +++ b/tasks/robot/robot.cpp @@ -1 +1,35 @@ +#include #include "robot.h" + +namespace robot { + +Path FindPath(World& world) { + Path result; + Point cur_point = world.GetStart(); + Point end_point = world.GetEnd(); + + result.emplace_back(cur_point); + + while (cur_point != end_point) { + Point best_next = cur_point; + Topology::Distance min_dist(0); + for (const auto& [next, dist_to_end] : world.Lookup()) { + if (dist_to_end == Topology::UNREACHABLE) { + continue; + } + if (best_next == cur_point || dist_to_end < min_dist) { + best_next = next; + min_dist = dist_to_end; + } + } + if (cur_point == best_next) { + result.clear(); + break; + } + cur_point = best_next; + world.Move(cur_point); + result.emplace_back(cur_point); + } + return result; +} +} // namespace robot \ No newline at end of file diff --git a/tasks/robot/robot.h b/tasks/robot/robot.h index 5f1295c..d54228d 100755 --- a/tasks/robot/robot.h +++ b/tasks/robot/robot.h @@ -8,4 +8,4 @@ using Path = std::vector; Path FindPath(World& world); -} +} // namespace robot \ No newline at end of file diff --git a/tasks/robot/topology.cpp b/tasks/robot/topology.cpp index 7771476..02c39f7 100755 --- a/tasks/robot/topology.cpp +++ b/tasks/robot/topology.cpp @@ -1 +1,56 @@ +#include #include "topology.h" +Field::Field(const std::vector>& field) : field_(field) { +} +bool Field::IsAvailable(const Point& point) const { + return !field_[point.y][point.x]; +} +size_t Field::GetFieldWidth() const { + return field_.empty() ? 0 : field_[0].size(); +} +size_t Field::GetFieldHigh() const { + return field_.size(); +} +bool Field::IsInField(int x, int y) const { + return x >= 0 && x < GetFieldWidth() && y >= 0 && y < GetFieldHigh(); +} +std::vector Topology::GetNeighbours(const Point& point) const { + std::vector result; + for (const Point& next : GetAllNeighbours(point)) { + if (IsAvailable(next)) { + result.emplace_back(next); + } + } + return result; +} +Topology::Distance Topology::MeasureDistance(const Point& from, const Point& to) const { + std::unordered_map dist; + + std::queue q; + q.push(from); + dist[from] = 0; + while (!q.empty()) { + Point cur_point = q.front(); + q.pop(); + if (cur_point == to) { + return dist[cur_point]; + } + for (const Point& next : GetNeighbours(cur_point)) { + if (dist.contains(next)) { + continue; + } + dist[next] = dist[cur_point] + 1; + q.push(next); + } + } + return UNREACHABLE; +} +Topology::Topology(const std::vector>& field) : Field(field) { +} +Point Topology::MovedPoint(const Point& point, int dx, int dy) const { + return Point{static_cast(static_cast(point.x) + dx), + static_cast(static_cast(point.y) + dy)}; +} +std::vector Topology::GetAllNeighbours(const Point& point) const { + return std::vector(); +} \ No newline at end of file diff --git a/tasks/robot/topology.h b/tasks/robot/topology.h index e0a63f2..1c40f6d 100755 --- a/tasks/robot/topology.h +++ b/tasks/robot/topology.h @@ -4,12 +4,32 @@ #include -class Topology { +class Field { +protected: + explicit Field(const std::vector>& field); + + bool IsAvailable(const Point& point) const; + + size_t GetFieldWidth() const; + size_t GetFieldHigh() const; + + bool IsInField(int x, int y) const; + + std::vector> field_; +}; + +class Topology : public Field { public: using Distance = ssize_t; + explicit Topology(const std::vector>& field); + std::vector GetNeighbours(const Point& point) const; Distance MeasureDistance(const Point& from, const Point& to) const; - static const Distance UNREACHABLE = -1; -}; + Point MovedPoint(const Point& point, int dx, int dy) const; + + virtual std::vector GetAllNeighbours(const Point& point) const; + + inline static const Distance UNREACHABLE = -1; +}; \ No newline at end of file diff --git a/tasks/robot/world.cpp b/tasks/robot/world.cpp index ea50eca..4e5de61 100755 --- a/tasks/robot/world.cpp +++ b/tasks/robot/world.cpp @@ -1 +1,25 @@ #include "world.h" +World::World(const Topology& topology, Point start, Point end) : start_(start), end_(end), topology_(topology) { +} +std::unordered_map World::Lookup() const { + std::unordered_map result; + for (const Point& next : topology_.GetNeighbours(current_point_)) { + result[next] = topology_.MeasureDistance(next, end_); + } + return result; +} +const Point& World::GetStart() const { + return start_; +} +const Point& World::GetEnd() const { + return end_; +} +const Point& World::GetCurrentPosition() const { + return current_point_; +} +void World::Move(const Point& to) { + if (topology_.MeasureDistance(current_point_, to) != 1) { + throw IllegalMoveException(); + } + current_point_ = to; +} \ No newline at end of file diff --git a/tasks/robot/world.h b/tasks/robot/world.h index e5a025d..a583368 100755 --- a/tasks/robot/world.h +++ b/tasks/robot/world.h @@ -19,4 +19,11 @@ class World { const Point& GetCurrentPosition() const; void Move(const Point& to); -}; + +private: + Point start_; + Point end_; + + Point current_point_; + const Topology& topology_; +}; \ No newline at end of file