diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d93c5e..25ef12d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,6 @@ include(GNUInstallDirs) include(Format) # keep PUBLIC dependencies in sync with cmake/config.cmake.in -#find_package(foo REQUIRED) +find_package(Boost REQUIRED) add_subdirectory(src) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fd5c956..c46b0dd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,7 @@ add_executable(${PROJECT_NAME} main.cc) target_link_libraries(${PROJECT_NAME} PRIVATE + Boost::headers ) target_include_directories(${PROJECT_NAME} PUBLIC diff --git a/src/main.cc b/src/main.cc index 4cce7f6..38ccaa2 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1,3 +1,135 @@ -int main() { +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace asio = boost::asio; + +asio::awaitable AsyncMain(asio::any_io_executor executor, + std::string_view name, std::string_view pass) { + asio::ip::tcp::resolver resolver{executor}; + asio::ip::tcp::resolver::query query{"94.45.241.27", "4000"}; + asio::ip::tcp::socket socket{executor}; + + co_await asio::async_connect( + socket, co_await resolver.async_resolve(query, asio::use_awaitable), + asio::use_awaitable); + + std::random_device generator; + int goal_x, goal_y; + int x, y; + while (true) { + boost::asio::streambuf ibuf, obuf; + ibuf.commit(co_await asio::async_read_until(socket, ibuf, '\n', + asio::use_awaitable)); + std::istream is{&ibuf}; + std::ostream os{&obuf}; + std::string field; + char dummy; + std::getline(is, field, '|'); + if (field == "motd") { + std::getline(is, field); + std::cout << "-> MotD: " << field << std::endl; + os << "join|" << name << '|' << pass << std::endl; + co_await async_write(socket, obuf.data(), asio::use_awaitable); + std::cout << "<- Join as " << name << std::endl; + } else if (field == "error") { + std::getline(is, field); + std::cout << "-> Error: " << field << std::endl; + co_return; + } else if (field == "goal") { + is >> goal_x >> dummy >> goal_y; + std::cout << "-> Goal is at (" << goal_x << ", " << goal_y << ")" + << std::endl; + } else if (field == "pos") { + bool up, right, down, left; + is >> x >> dummy >> y >> dummy >> up >> dummy >> right >> dummy >> down >> + dummy >> left; + std::cout << "-> Position at (" << x << ", " << y << ")" << std::endl; +#define X(b) (b ? #b ", " : "") + std::cout << " Walls are " << X(up) << X(right) << X(down) << X(left) + << std::endl; +#undef X +#define X(cond, dir) \ + if ((cond) && !dir) { \ + os << "move|" #dir << std::endl; \ + co_await async_write(socket, obuf.data(), asio::use_awaitable); \ + std::cout << "<- Go " #dir << std::endl; \ + continue; \ + } + X(x > goal_x, left); + X(y > goal_y, up); + X(x < goal_x, right); + X(y < goal_y, down); +#undef X + std::uniform_int_distribution direction{0, 3}; + switch (direction(generator)) { +#define X(n, dir) \ + case n: \ + if (!dir) { \ + os << "move|" #dir << std::endl; \ + co_await async_write(socket, obuf.data(), asio::use_awaitable); \ + std::cout << "<- Go " #dir << std::endl; \ + continue; \ + } + X(0, left); + [[fallthrough]]; + X(1, up); + [[fallthrough]]; + X(2, right); + [[fallthrough]]; + X(3, down); +#undef X +#define X(dir) \ + if (!dir) { \ + os << "move|" #dir << std::endl; \ + co_await async_write(socket, obuf.data(), asio::use_awaitable); \ + std::cout << "<- Go " #dir << std::endl; \ + continue; \ + } + X(left); + X(up); + X(right); + X(down); +#undef X + } + } else if (field == "win" || field == "lose") { + int win, lose; + is >> win >> dummy >> lose; + std::cout << "-> You " << field << '!' << std::endl; + std::cout << " Score: " << win << '/' << lose << std::endl; + } else { + std::cout << "unhandled message: " << field << '|'; + std::getline(is, field); + std::cout << field << std::endl; + } + } + co_return; +} + +int main(int argc, char **argv) { + asio::io_context context; + + if (argc < 3) { + std::cerr << "usage: " << argv[0] << " " << std::endl; + return 1; + } + + asio::co_spawn( + context, std::bind(&AsyncMain, context.get_executor(), argv[1], argv[2]), + asio::detached); + context.run(); return 0; }