optimal play
This commit is contained in:
parent
374402299d
commit
7e64cf85e0
111
src/main.cc
111
src/main.cc
|
@ -11,7 +11,9 @@
|
|||
#include <boost/asio/use_awaitable.hpp>
|
||||
#include <boost/asio/write.hpp>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <random>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
@ -19,11 +21,11 @@
|
|||
|
||||
namespace asio = boost::asio;
|
||||
|
||||
enum class Direction : int {
|
||||
UP,
|
||||
RIGHT,
|
||||
DOWN,
|
||||
LEFT,
|
||||
enum class Direction : unsigned {
|
||||
UP = 1,
|
||||
RIGHT = 2,
|
||||
DOWN = 4,
|
||||
LEFT = 8,
|
||||
};
|
||||
|
||||
std::string_view DirectionToString(Direction direction) {
|
||||
|
@ -50,11 +52,12 @@ class Bot {
|
|||
int goal_x, goal_y;
|
||||
int x, y;
|
||||
bool up, right, down, left;
|
||||
Direction heading;
|
||||
std::map<std::pair<int, int>, unsigned> known_map;
|
||||
|
||||
asio::awaitable<void> Protocol();
|
||||
asio::awaitable<void> Join();
|
||||
asio::awaitable<bool> Move(Direction dir);
|
||||
unsigned ShortestPath(int x, int y);
|
||||
asio::awaitable<void> ChooseMove();
|
||||
|
||||
public:
|
||||
|
@ -68,8 +71,7 @@ Bot::Bot(asio::any_io_executor executor, std::string_view name,
|
|||
timer{executor},
|
||||
socket{executor},
|
||||
name{name},
|
||||
pass{pass},
|
||||
heading{Direction::LEFT} {
|
||||
pass{pass} {
|
||||
asio::co_spawn(executor, std::bind(&Bot::Protocol, this), asio::detached);
|
||||
}
|
||||
|
||||
|
@ -112,6 +114,7 @@ asio::awaitable<void> Bot::Protocol() {
|
|||
iss >> goal_x >> dummy >> goal_y;
|
||||
std::cout << "-> Goal is at (" << goal_x << ", " << goal_y << ")"
|
||||
<< std::endl;
|
||||
known_map.clear();
|
||||
} else if (field == "pos") {
|
||||
iss >> x >> dummy >> y >> dummy >> up >> dummy >> right >> dummy >>
|
||||
down >> dummy >> left;
|
||||
|
@ -171,12 +174,94 @@ asio::awaitable<bool> Bot::Move(Direction direction) {
|
|||
co_return true;
|
||||
}
|
||||
|
||||
asio::awaitable<void> Bot::ChooseMove() {
|
||||
// follow right wall
|
||||
while (!co_await Move(heading)) {
|
||||
heading = Direction{(static_cast<int>(heading) + 3) % 4};
|
||||
unsigned Bot::ShortestPath(int x, int y) {
|
||||
// Djikstra
|
||||
std::set<std::pair<int, int>> visited;
|
||||
std::multimap<unsigned, std::pair<int, int>> queue;
|
||||
auto goal = std::make_pair(goal_x, goal_y);
|
||||
|
||||
queue.emplace(0, std::make_pair(x, y));
|
||||
while (queue.begin() != queue.end()) {
|
||||
auto it = queue.begin();
|
||||
auto distance = it->first;
|
||||
auto position = it->second;
|
||||
queue.erase(it);
|
||||
if (position == goal) {
|
||||
return distance;
|
||||
}
|
||||
heading = Direction{(static_cast<int>(heading) + 1) % 4};
|
||||
if (visited.count(position)) {
|
||||
continue;
|
||||
}
|
||||
if (!(known_map[position] & static_cast<unsigned>(Direction::LEFT))) {
|
||||
queue.emplace(distance + 1,
|
||||
std::make_pair(position.first - 1, position.second));
|
||||
}
|
||||
if (!(known_map[position] & static_cast<unsigned>(Direction::RIGHT))) {
|
||||
queue.emplace(distance + 1,
|
||||
std::make_pair(position.first + 1, position.second));
|
||||
}
|
||||
if (!(known_map[position] & static_cast<unsigned>(Direction::UP))) {
|
||||
queue.emplace(distance + 1,
|
||||
std::make_pair(position.first, position.second - 1));
|
||||
}
|
||||
if (!(known_map[position] & static_cast<unsigned>(Direction::DOWN))) {
|
||||
queue.emplace(distance + 1,
|
||||
std::make_pair(position.first, position.second + 1));
|
||||
}
|
||||
visited.emplace(position);
|
||||
}
|
||||
// should never happen
|
||||
return -1;
|
||||
}
|
||||
|
||||
asio::awaitable<void> Bot::ChooseMove() {
|
||||
// update map
|
||||
known_map[std::make_pair(x, y)] =
|
||||
(up ? static_cast<unsigned>(Direction::UP) : 0) |
|
||||
(right ? static_cast<unsigned>(Direction::RIGHT) : 0) |
|
||||
(down ? static_cast<unsigned>(Direction::DOWN) : 0) |
|
||||
(left ? static_cast<unsigned>(Direction::LEFT) : 0);
|
||||
known_map[std::make_pair(x - 1, y)] |=
|
||||
(left ? static_cast<unsigned>(Direction::RIGHT) : 0);
|
||||
known_map[std::make_pair(x + 1, y)] |=
|
||||
(right ? static_cast<unsigned>(Direction::LEFT) : 0);
|
||||
known_map[std::make_pair(x, y - 1)] |=
|
||||
(up ? static_cast<unsigned>(Direction::DOWN) : 0);
|
||||
known_map[std::make_pair(x, y + 1)] |=
|
||||
(down ? static_cast<unsigned>(Direction::UP) : 0);
|
||||
|
||||
// find best move
|
||||
Direction best;
|
||||
unsigned best_estimate = -1;
|
||||
if (!left) {
|
||||
unsigned estimate = ShortestPath(x - 1, y);
|
||||
if (estimate < best_estimate) {
|
||||
best = Direction::LEFT;
|
||||
best_estimate = estimate;
|
||||
}
|
||||
}
|
||||
if (!right) {
|
||||
unsigned estimate = ShortestPath(x + 1, y);
|
||||
if (estimate < best_estimate) {
|
||||
best = Direction::RIGHT;
|
||||
best_estimate = estimate;
|
||||
}
|
||||
}
|
||||
if (!up) {
|
||||
unsigned estimate = ShortestPath(x, y - 1);
|
||||
if (estimate < best_estimate) {
|
||||
best = Direction::UP;
|
||||
best_estimate = estimate;
|
||||
}
|
||||
}
|
||||
if (!down) {
|
||||
unsigned estimate = ShortestPath(x, y + 1);
|
||||
if (estimate < best_estimate) {
|
||||
best = Direction::DOWN;
|
||||
best_estimate = estimate;
|
||||
}
|
||||
}
|
||||
co_await Move(best);
|
||||
co_return;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue