Merge pull request 'experimental' (#1) from experimental into main
Reviewed-on: https://git.tjoyspotifylastfm.tech/ParkSuMin/Maze/pulls/1
This commit is contained in:
@@ -3,7 +3,7 @@ project(maze LANGUAGES CXX)
|
|||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 23)
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++23")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++23 -Wall")
|
||||||
|
|
||||||
include_directories(
|
include_directories(
|
||||||
include
|
include
|
||||||
|
|||||||
@@ -1,20 +1,22 @@
|
|||||||
#ifndef CLIENT
|
#ifndef CLIENT_HPP
|
||||||
#define CLIENT
|
#define CLIENT_HPP
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <netdb.h>
|
||||||
const int PORT = 8080;
|
|
||||||
|
|
||||||
class Client{
|
class Client{
|
||||||
private:
|
private:
|
||||||
int sock;
|
int sock;
|
||||||
public:
|
public:
|
||||||
Client() : sock(0){};
|
Client();
|
||||||
void run();
|
|
||||||
|
void run(const std::string&, const unsigned short);
|
||||||
|
void game();
|
||||||
|
|
||||||
int ping(struct sockaddr_in);
|
int ping(struct sockaddr_in);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -11,28 +11,24 @@ const int MAZE_SIZE = 9;
|
|||||||
const int DIRECTIONS = 4;
|
const int DIRECTIONS = 4;
|
||||||
const int MIN_WALLS = 3;
|
const int MIN_WALLS = 3;
|
||||||
const int MAX_WALLS = 5;
|
const int MAX_WALLS = 5;
|
||||||
const int DEFAULT_MOVES = 10;
|
|
||||||
|
|
||||||
class Maze{
|
class Maze{
|
||||||
private:
|
private:
|
||||||
std::unordered_map<int, std::vector<bool>> graph;
|
std::unordered_map<int, std::vector<bool>> graph;
|
||||||
int moves_left;
|
int moves_left;
|
||||||
bool is_path_exists(int, int);
|
bool is_path_exists(int start, int end);
|
||||||
|
|
||||||
struct Edge {
|
struct Edge {
|
||||||
int node1, dir1;
|
int node1, dir1;
|
||||||
int node2, dir2;
|
int node2, dir2;
|
||||||
};
|
};
|
||||||
public:
|
public:
|
||||||
Maze(bool);
|
bool test_mode;
|
||||||
bool test_mode;
|
|
||||||
int get_moves_left() const;
|
|
||||||
bool is_wall(int, int) const;
|
|
||||||
|
|
||||||
void set_moves_left(int);
|
Maze(bool flag, int steps);
|
||||||
|
int get_moves_left() const;
|
||||||
//void generate_maze();
|
bool is_wall(int node, int direction) const;
|
||||||
//void print_maze_info();
|
|
||||||
//void play_game();
|
void set_moves_left(int _steps);
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -7,20 +7,23 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
#include <netdb.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
const int PORT = 8080;
|
const int MAX_CLIENTS = 512;
|
||||||
const int MAX_CLIENTS = 100;
|
const int BUFFER_SIZE = 1024;
|
||||||
|
|
||||||
class Server {
|
class Server {
|
||||||
private:
|
private:
|
||||||
bool service_mode;
|
bool service_mode;
|
||||||
void handle_client(int client_socket, bool _mode); // Принимает клиентский сокет
|
int server_socket;
|
||||||
|
|
||||||
|
void handle_client(int socket, bool flag, int steps);
|
||||||
bool check_status(Maze& maze);
|
bool check_status(Maze& maze);
|
||||||
public:
|
public:
|
||||||
Server() : service_mode(false){};
|
Server(const std::string& host, const unsigned short port, bool service_flag);
|
||||||
void start(); // Запуск сервера
|
void start(int steps = 10);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,52 +1,60 @@
|
|||||||
#include "client.hpp"
|
#include "client.hpp"
|
||||||
|
|
||||||
void print_instructions() {
|
// void print_instructions() {
|
||||||
std::cout << "Доступные команды:\n";
|
// std::cout << "Доступные команды:" << std::endl;
|
||||||
std::cout << " - вперёд\n";
|
// std::cout << " - вперёд" << std::endl;
|
||||||
std::cout << " - направо\n";
|
// std::cout << " - направо" << std::endl;
|
||||||
std::cout << " - налево\n";
|
// std::cout << " - налево" << std::endl;
|
||||||
std::cout << " - назад\n";
|
// std::cout << " - назад" << std::endl;
|
||||||
std::cout << " - сдаюсь\n";
|
// std::cout << " - сдаюсь" << std::endl;
|
||||||
std::cout << "Введите команду для хода.\n";
|
// std::cout << "Введите команду для хода" << std::endl;
|
||||||
}
|
// }
|
||||||
|
|
||||||
int Client::ping(struct sockaddr_in address){
|
int Client::ping(struct sockaddr_in address){
|
||||||
return connect(sock, (struct sockaddr*)&address, sizeof(address)) > 0;
|
return connect(sock, (struct sockaddr*)&address, sizeof(address)) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::run() {
|
Client::Client(){
|
||||||
struct sockaddr_in serv_addr;
|
|
||||||
|
|
||||||
// Создание сокета
|
// Создание сокета
|
||||||
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||||
throw std::runtime_error("[Client::request] connect(2) call error");
|
throw std::runtime_error("Error in socket create");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::run(const std::string& h, const unsigned short p) {
|
||||||
|
struct sockaddr_in serv_addr;
|
||||||
|
|
||||||
serv_addr.sin_family = AF_INET;
|
serv_addr.sin_family = AF_INET;
|
||||||
serv_addr.sin_port = htons(PORT);
|
|
||||||
|
|
||||||
// Преобразование IP-адреса из текстового вида в бинарный
|
hostent* host_name;
|
||||||
if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
|
host_name = gethostbyname(h.c_str()); // Преобразование названия хоста в IP-адрес.
|
||||||
throw std::runtime_error("[Client::request] connect(2) call error");
|
if (host_name == nullptr) {
|
||||||
|
throw std::runtime_error("Error in get hostname");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
serv_addr.sin_port = htons(p);
|
||||||
|
memcpy(&serv_addr.sin_addr.s_addr, host_name->h_addr, host_name->h_length);
|
||||||
|
|
||||||
// Подключение к серверу
|
// Подключение к серверу
|
||||||
if (ping(serv_addr)) {
|
if (ping(serv_addr)) {
|
||||||
throw std::runtime_error("Connection lost!");
|
throw std::runtime_error("Invalid hostname:port");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "Подключено к серверу. Введите ваше имя: ";
|
std::cout << "Подключено к серверу. Введите ваше имя: ";
|
||||||
std::string player_name;
|
std::string player_name;
|
||||||
std::getline(std::cin, player_name);
|
std::getline(std::cin, player_name);
|
||||||
|
|
||||||
if (ping(serv_addr)) {
|
if (!ping(serv_addr)) {
|
||||||
throw std::runtime_error("Connection lost!");
|
throw std::runtime_error("Connection lost!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Отправка имени игрока на сервер
|
// Отправка имени игрока на сервер
|
||||||
send(sock, player_name.c_str(), player_name.size(), 0);
|
send(sock, player_name.c_str(), player_name.size(), 0);
|
||||||
std::cout << "Игра началась!\n";
|
}
|
||||||
|
|
||||||
print_instructions();
|
void Client::game(){
|
||||||
|
std::cout << "Игра началась!" << std::endl;
|
||||||
|
//print_instructions();
|
||||||
|
|
||||||
char buffer[1024] = {0};
|
char buffer[1024] = {0};
|
||||||
while (true) {
|
while (true) {
|
||||||
@@ -74,6 +82,5 @@ void Client::run() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
close(sock);
|
close(sock);
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,27 @@
|
|||||||
#include "client.hpp"
|
#include "client.hpp"
|
||||||
|
|
||||||
int main(){
|
int main(int argc, char** argv){
|
||||||
|
int opt;
|
||||||
|
std::string host = "localhost";
|
||||||
|
short unsigned port = 1024u;
|
||||||
|
|
||||||
|
while ((opt = getopt(argc, argv, "h:p:")) != -1) {
|
||||||
|
switch (opt) {
|
||||||
|
case 'h':
|
||||||
|
host = optarg;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
port = static_cast<unsigned short>(atoi(optarg));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Client client;
|
Client client;
|
||||||
client.run();
|
client.run(host, port);
|
||||||
|
client.game();
|
||||||
} catch (const std::runtime_error& e){
|
} catch (const std::runtime_error& e){
|
||||||
std::cerr << "Client application error: " << e.what() << std::endl;
|
std::cerr << "Client application error: " << e.what() << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
#include "maze.hpp"
|
#include "maze.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
Maze::Maze(bool _test_mode){
|
Maze::Maze(bool _test_mode, int _steps){
|
||||||
std::vector<Edge> edges = {
|
std::vector<Edge> edges = {
|
||||||
{0, 1, 1, 3}, {0, 0, 3, 2}, {1, 1, 2, 3}, {1, 0, 4, 2},
|
{0, 1, 1, 3}, {0, 0, 3, 2}, {1, 1, 2, 3}, {1, 0, 4, 2},
|
||||||
{2, 0, 5, 2}, {3, 1, 4, 3}, {3, 0, 6, 2}, {4, 1, 5, 3},
|
{2, 0, 5, 2}, {3, 1, 4, 3}, {3, 0, 6, 2}, {4, 1, 5, 3},
|
||||||
{4, 0, 7, 2}, {5, 0, 8, 2}, {6, 1, 7, 3}, {7, 1, 8, 3}
|
{4, 0, 7, 2}, {5, 0, 8, 2}, {6, 1, 7, 3}, {7, 1, 8, 3}
|
||||||
};
|
};
|
||||||
test_mode = _test_mode;
|
test_mode = _test_mode;
|
||||||
moves_left = test_mode ? INT_MAX : DEFAULT_MOVES;
|
moves_left = test_mode ? INT_MAX : _steps;
|
||||||
|
|
||||||
for (int i = 0; i < MAZE_SIZE; ++i) {
|
for (int i = 0; i < MAZE_SIZE; ++i) {
|
||||||
graph[i] = std::vector<bool>(DIRECTIONS, true);
|
graph[i] = std::vector<bool>(DIRECTIONS, true);
|
||||||
|
|||||||
@@ -4,24 +4,51 @@ bool Server::check_status(Maze &maze) {
|
|||||||
return (!maze.test_mode && maze.get_moves_left() > 0);
|
return (!maze.test_mode && maze.get_moves_left() > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::handle_client(int client_socket, bool mode) {
|
Server::Server(const std::string& h, const unsigned short p, bool _service){
|
||||||
Maze maze(mode); // Создаем экземпляр лабиринта для клиента
|
service_mode = _service;
|
||||||
int current_position = 0; // Начальная позиция игрока
|
if (service_mode) {
|
||||||
|
std::cout << "Service mode is ON" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
sockaddr_in server_address;
|
||||||
|
|
||||||
|
if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||||
|
throw std::runtime_error("Error in create socket");
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(reinterpret_cast<char*>(&server_address), '\0', sizeof(server_address));
|
||||||
|
server_address.sin_family = AF_INET;
|
||||||
|
hostent* host_name;
|
||||||
|
host_name = gethostbyname(h.c_str()); // Преобразование названия хоста в IP-адрес.
|
||||||
|
if (host_name == nullptr) {
|
||||||
|
throw std::runtime_error("Error in getting hostname");
|
||||||
|
}
|
||||||
|
|
||||||
|
server_address.sin_port = htons(p);
|
||||||
|
memcpy(&server_address.sin_addr.s_addr, host_name->h_addr, host_name->h_length);
|
||||||
|
if (bind(server_socket, reinterpret_cast<const sockaddr*>(&server_address), sizeof(server_address)) != 0) {
|
||||||
|
throw std::runtime_error("Error in bind part");
|
||||||
|
}
|
||||||
|
std::cout << "Сервер запущен на хосте " << h << " на порту " << p << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::handle_client(int client_socket, bool mode, int steps) {
|
||||||
|
Maze maze(mode, steps);
|
||||||
|
int current_position = 0;
|
||||||
std::string player_name;
|
std::string player_name;
|
||||||
|
|
||||||
char buffer[1024] = {0};
|
char buffer[BUFFER_SIZE] = {0};
|
||||||
std::string response;
|
std::string response;
|
||||||
|
|
||||||
// Получение имени игрока
|
|
||||||
int bytes_received = recv(client_socket, buffer, sizeof(buffer), 0);
|
int bytes_received = recv(client_socket, buffer, sizeof(buffer), 0);
|
||||||
if (bytes_received <= 0) {
|
if (bytes_received <= 0) {
|
||||||
std::cerr << "Ошибка получения имени игрока.\n";
|
std::cout << "Error in getting player name";
|
||||||
close(client_socket);
|
close(client_socket);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
player_name = std::string(buffer);
|
player_name = std::string(buffer);
|
||||||
std::cout << "Новый игрок: " << player_name << "\n";
|
std::cout << "Новый игрок: " << player_name << std::endl;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
int moves_left = maze.get_moves_left();
|
int moves_left = maze.get_moves_left();
|
||||||
@@ -33,7 +60,7 @@ void Server::handle_client(int client_socket, bool mode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string command(buffer);
|
std::string command(buffer);
|
||||||
std::cout << "Получена команда от игрока " << player_name << ": " << command << "\n";
|
std::cout << "Получена команда от игрока " << player_name << ": " << command << std::endl;
|
||||||
|
|
||||||
int direction = -1;
|
int direction = -1;
|
||||||
int new_position = current_position;
|
int new_position = current_position;
|
||||||
@@ -86,10 +113,13 @@ void Server::handle_client(int client_socket, bool mode) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
maze.set_moves_left(moves_left - 1);
|
||||||
|
if (!check_status(maze))
|
||||||
|
break;
|
||||||
|
|
||||||
int x = current_position % 3;
|
int x = current_position % 3;
|
||||||
int y = current_position / 3;
|
int y = current_position / 3;
|
||||||
std::string text("(" + std::to_string(x) + ", " + std::to_string(y) + ")\n");
|
std::string text("(" + std::to_string(x) + ", " + std::to_string(y) + ")\n");
|
||||||
maze.set_moves_left(moves_left - 1);
|
|
||||||
response = "успешно, осталось " + std::to_string(maze.get_moves_left()) + " ходов. Вы находитесь в " + text;
|
response = "успешно, осталось " + std::to_string(maze.get_moves_left()) + " ходов. Вы находитесь в " + text;
|
||||||
send(client_socket, response.c_str(), response.size(), 0);
|
send(client_socket, response.c_str(), response.size(), 0);
|
||||||
}
|
}
|
||||||
@@ -101,48 +131,24 @@ void Server::handle_client(int client_socket, bool mode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
close(client_socket);
|
close(client_socket);
|
||||||
std::cout << "Игрок " << player_name << " отключился.\n";
|
std::cout << "Игрок " << player_name << " отключился" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::start() {
|
void Server::start(int steps) {
|
||||||
int server_fd, new_socket;
|
int new_socket;
|
||||||
struct sockaddr_in address;
|
|
||||||
int opt = 1;
|
|
||||||
int addrlen = sizeof(address);
|
|
||||||
|
|
||||||
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
|
if (listen(server_socket, MAX_CLIENTS) < 0) {
|
||||||
perror("Ошибка создания сокета");
|
throw std::runtime_error("Error in listen");
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
|
sockaddr address;
|
||||||
perror("Ошибка настройки сокета");
|
socklen_t address_size = sizeof(address);
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
address.sin_family = AF_INET;
|
|
||||||
address.sin_addr.s_addr = INADDR_ANY;
|
|
||||||
address.sin_port = htons(PORT);
|
|
||||||
|
|
||||||
if (bind(server_fd, (struct sockaddr*)&address, sizeof(address)) < 0) {
|
|
||||||
perror("Ошибка привязки сокета");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (listen(server_fd, MAX_CLIENTS) < 0) {
|
|
||||||
perror("Ошибка прослушивания");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "Сервер запущен на порту " << PORT << "\n";
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if ((new_socket = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen)) < 0) {
|
if ((new_socket = accept(server_socket, (struct sockaddr*)&address, &address_size)) < 0) {
|
||||||
perror("Ошибка принятия соединения");
|
throw std::runtime_error("Error in accept");
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "Новое соединение установлено.\n";
|
std::cout << "Новое соединение установлено" << std::endl;
|
||||||
std::thread(&Server::handle_client, this, new_socket, true).detach();
|
std::thread(&Server::handle_client, this, new_socket, service_mode, steps).detach();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,46 @@
|
|||||||
#include "server.hpp"
|
#include "server.hpp"
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
|
int opt;
|
||||||
Server server;
|
std::string host = "localhost";
|
||||||
server.start();
|
int steps = 10;
|
||||||
|
bool service_mode = false;
|
||||||
|
short unsigned port = 1024u;
|
||||||
|
|
||||||
|
while ((opt = getopt(argc, argv, "h:p:sn:")) != -1) {
|
||||||
|
switch (opt) {
|
||||||
|
case 'h':
|
||||||
|
host = optarg;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
port = static_cast<unsigned short>(atoi(optarg));
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
steps = atoi(optarg);
|
||||||
|
if(steps <= 0) {
|
||||||
|
std::cerr << "Invalid steps" << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
service_mode = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Server server(host, port, service_mode);
|
||||||
|
server.start(steps);
|
||||||
|
} catch (const std::runtime_error& e){
|
||||||
|
std::cerr << "Server application error: " << e.what() << std::endl;
|
||||||
|
return 1;
|
||||||
|
} catch (...){
|
||||||
|
std::cerr << "Unexpected error in client application" << std::endl;
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Server application finished" << std::endl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user