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/use_awaitable.hpp>
|
||||||
#include <boost/asio/write.hpp>
|
#include <boost/asio/write.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
#include <random>
|
#include <random>
|
||||||
|
#include <set>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
@ -19,11 +21,11 @@
|
||||||
|
|
||||||
namespace asio = boost::asio;
|
namespace asio = boost::asio;
|
||||||
|
|
||||||
enum class Direction : int {
|
enum class Direction : unsigned {
|
||||||
UP,
|
UP = 1,
|
||||||
RIGHT,
|
RIGHT = 2,
|
||||||
DOWN,
|
DOWN = 4,
|
||||||
LEFT,
|
LEFT = 8,
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string_view DirectionToString(Direction direction) {
|
std::string_view DirectionToString(Direction direction) {
|
||||||
|
@ -50,11 +52,12 @@ class Bot {
|
||||||
int goal_x, goal_y;
|
int goal_x, goal_y;
|
||||||
int x, y;
|
int x, y;
|
||||||
bool up, right, down, left;
|
bool up, right, down, left;
|
||||||
Direction heading;
|
std::map<std::pair<int, int>, unsigned> known_map;
|
||||||
|
|
||||||
asio::awaitable<void> Protocol();
|
asio::awaitable<void> Protocol();
|
||||||
asio::awaitable<void> Join();
|
asio::awaitable<void> Join();
|
||||||
asio::awaitable<bool> Move(Direction dir);
|
asio::awaitable<bool> Move(Direction dir);
|
||||||
|
unsigned ShortestPath(int x, int y);
|
||||||
asio::awaitable<void> ChooseMove();
|
asio::awaitable<void> ChooseMove();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -68,8 +71,7 @@ Bot::Bot(asio::any_io_executor executor, std::string_view name,
|
||||||
timer{executor},
|
timer{executor},
|
||||||
socket{executor},
|
socket{executor},
|
||||||
name{name},
|
name{name},
|
||||||
pass{pass},
|
pass{pass} {
|
||||||
heading{Direction::LEFT} {
|
|
||||||
asio::co_spawn(executor, std::bind(&Bot::Protocol, this), asio::detached);
|
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;
|
iss >> goal_x >> dummy >> goal_y;
|
||||||
std::cout << "-> Goal is at (" << goal_x << ", " << goal_y << ")"
|
std::cout << "-> Goal is at (" << goal_x << ", " << goal_y << ")"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
known_map.clear();
|
||||||
} else if (field == "pos") {
|
} else if (field == "pos") {
|
||||||
iss >> x >> dummy >> y >> dummy >> up >> dummy >> right >> dummy >>
|
iss >> x >> dummy >> y >> dummy >> up >> dummy >> right >> dummy >>
|
||||||
down >> dummy >> left;
|
down >> dummy >> left;
|
||||||
|
@ -171,12 +174,94 @@ asio::awaitable<bool> Bot::Move(Direction direction) {
|
||||||
co_return true;
|
co_return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
asio::awaitable<void> Bot::ChooseMove() {
|
unsigned Bot::ShortestPath(int x, int y) {
|
||||||
// follow right wall
|
// Djikstra
|
||||||
while (!co_await Move(heading)) {
|
std::set<std::pair<int, int>> visited;
|
||||||
heading = Direction{(static_cast<int>(heading) + 3) % 4};
|
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;
|
co_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue