Initial commit
This commit is contained in:
79
src/client/client.cpp
Normal file
79
src/client/client.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
#include "client.hpp"
|
||||
|
||||
void print_instructions() {
|
||||
std::cout << "Доступные команды:\n";
|
||||
std::cout << " - вперёд\n";
|
||||
std::cout << " - направо\n";
|
||||
std::cout << " - налево\n";
|
||||
std::cout << " - назад\n";
|
||||
std::cout << " - сдаюсь\n";
|
||||
std::cout << "Введите команду для хода.\n";
|
||||
}
|
||||
|
||||
int Client::ping(struct sockaddr_in address){
|
||||
return connect(sock, (struct sockaddr*)&address, sizeof(address)) > 0;
|
||||
}
|
||||
|
||||
void Client::run() {
|
||||
struct sockaddr_in serv_addr;
|
||||
|
||||
// Создание сокета
|
||||
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
throw std::runtime_error("[Client::request] connect(2) call error");
|
||||
}
|
||||
|
||||
serv_addr.sin_family = AF_INET;
|
||||
serv_addr.sin_port = htons(PORT);
|
||||
|
||||
// Преобразование IP-адреса из текстового вида в бинарный
|
||||
if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
|
||||
throw std::runtime_error("[Client::request] connect(2) call error");
|
||||
}
|
||||
|
||||
// Подключение к серверу
|
||||
if (ping(serv_addr)) {
|
||||
throw std::runtime_error("Connection lost!");
|
||||
}
|
||||
|
||||
std::cout << "Подключено к серверу. Введите ваше имя: ";
|
||||
std::string player_name;
|
||||
std::getline(std::cin, player_name);
|
||||
|
||||
if (ping(serv_addr)) {
|
||||
throw std::runtime_error("Connection lost!");
|
||||
}
|
||||
// Отправка имени игрока на сервер
|
||||
send(sock, player_name.c_str(), player_name.size(), 0);
|
||||
std::cout << "Игра началась!\n";
|
||||
|
||||
print_instructions();
|
||||
|
||||
char buffer[1024] = {0};
|
||||
while (true) {
|
||||
std::cout << "Введите команду: ";
|
||||
std::string command;
|
||||
std::getline(std::cin, command);
|
||||
|
||||
// Отправка команды на сервер
|
||||
send(sock, command.c_str(), command.size(), 0);
|
||||
|
||||
// Получение ответа от сервера
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
int bytes_received = recv(sock, buffer, sizeof(buffer), 0);
|
||||
if (bytes_received <= 0) {
|
||||
throw std::runtime_error("Connection lost!");
|
||||
//break;
|
||||
}
|
||||
|
||||
std::string response(buffer);
|
||||
std::cout << "Ответ сервера: " << response;
|
||||
|
||||
// Проверка завершения игры
|
||||
if (response.find("вы выиграли") != std::string::npos ||
|
||||
response.find("вы проиграли") != std::string::npos) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
close(sock);
|
||||
}
|
||||
14
src/client/client_main.cpp
Normal file
14
src/client/client_main.cpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#include "client.hpp"
|
||||
|
||||
int main(){
|
||||
try {
|
||||
Client client;
|
||||
client.run();
|
||||
} catch (const std::runtime_error& e){
|
||||
std::cerr << "Client application error: " << e.what() << std::endl;
|
||||
return 1;
|
||||
} catch (...){
|
||||
std::cerr << "Unexpected error in client application" << std::endl;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
79
src/server/maze.cpp
Normal file
79
src/server/maze.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
#include "maze.hpp"
|
||||
#include <iostream>
|
||||
|
||||
Maze::Maze(bool _test_mode){
|
||||
std::vector<Edge> edges = {
|
||||
{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},
|
||||
{4, 0, 7, 2}, {5, 0, 8, 2}, {6, 1, 7, 3}, {7, 1, 8, 3}
|
||||
};
|
||||
test_mode = _test_mode;
|
||||
moves_left = test_mode ? INT_MAX : DEFAULT_MOVES;
|
||||
|
||||
for (int i = 0; i < MAZE_SIZE; ++i) {
|
||||
graph[i] = std::vector<bool>(DIRECTIONS, true);
|
||||
}
|
||||
|
||||
graph[6][0] = graph[7][0] = graph[8][0] = false;
|
||||
graph[0][2] = graph[1][2] = graph[2][2] = false;
|
||||
graph[0][3] = graph[3][3] = graph[6][3] = false;
|
||||
graph[2][1] = graph[5][1] = graph[8][1] = false;
|
||||
|
||||
std::mt19937 rng(time(nullptr));
|
||||
std::shuffle(edges.begin(), edges.end(), rng);
|
||||
int walls_to_add = std::uniform_int_distribution<int>(MIN_WALLS, MAX_WALLS)(rng);
|
||||
|
||||
for (int i = 0; i < walls_to_add && i < edges.size(); ++i) {
|
||||
const auto& edge = edges[i];
|
||||
graph[edge.node1][edge.dir1] = false;
|
||||
graph[edge.node2][edge.dir2] = false;
|
||||
if (!is_path_exists(0, 8)) {
|
||||
graph[edge.node1][edge.dir1] = true;
|
||||
graph[edge.node2][edge.dir2] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Maze::is_path_exists(int start, int end) {
|
||||
std::vector<bool> visited(MAZE_SIZE, false);
|
||||
std::vector<int> queue;
|
||||
queue.push_back(start);
|
||||
visited[start] = true;
|
||||
|
||||
while (!queue.empty()) {
|
||||
int node = queue.back();
|
||||
queue.pop_back();
|
||||
if (node == end) return true;
|
||||
|
||||
const auto& directions = graph.at(node);
|
||||
if (directions[0] && node + 3 < MAZE_SIZE && !visited[node + 3]) {
|
||||
queue.push_back(node + 3);
|
||||
visited[node + 3] = true;
|
||||
}
|
||||
if (directions[1] && (node % 3) < 2 && !visited[node + 1]) {
|
||||
queue.push_back(node + 1);
|
||||
visited[node + 1] = true;
|
||||
}
|
||||
if (directions[2] && node - 3 >= 0 && !visited[node - 3]) {
|
||||
queue.push_back(node - 3);
|
||||
visited[node - 3] = true;
|
||||
}
|
||||
if (directions[3] && (node % 3) > 0 && !visited[node - 1]) {
|
||||
queue.push_back(node - 1);
|
||||
visited[node - 1] = true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int Maze::get_moves_left() const{
|
||||
return moves_left;
|
||||
}
|
||||
|
||||
bool Maze::is_wall(int node, int direction) const {
|
||||
return !graph.at(node)[direction];
|
||||
}
|
||||
|
||||
void Maze::set_moves_left(int moves) {
|
||||
moves_left = moves;
|
||||
}
|
||||
148
src/server/server.cpp
Normal file
148
src/server/server.cpp
Normal file
@@ -0,0 +1,148 @@
|
||||
#include "server.hpp"
|
||||
|
||||
bool Server::check_status(Maze &maze) {
|
||||
return (!maze.test_mode && maze.get_moves_left() > 0);
|
||||
}
|
||||
|
||||
void Server::handle_client(int client_socket, bool mode) {
|
||||
Maze maze(mode); // Создаем экземпляр лабиринта для клиента
|
||||
int current_position = 0; // Начальная позиция игрока
|
||||
std::string player_name;
|
||||
|
||||
char buffer[1024] = {0};
|
||||
std::string response;
|
||||
|
||||
// Получение имени игрока
|
||||
int bytes_received = recv(client_socket, buffer, sizeof(buffer), 0);
|
||||
if (bytes_received <= 0) {
|
||||
std::cerr << "Ошибка получения имени игрока.\n";
|
||||
close(client_socket);
|
||||
return;
|
||||
}
|
||||
|
||||
player_name = std::string(buffer);
|
||||
std::cout << "Новый игрок: " << player_name << "\n";
|
||||
|
||||
while (true) {
|
||||
int moves_left = maze.get_moves_left();
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
bytes_received = recv(client_socket, buffer, sizeof(buffer), 0);
|
||||
|
||||
if (bytes_received <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
std::string command(buffer);
|
||||
std::cout << "Получена команда от игрока " << player_name << ": " << command << "\n";
|
||||
|
||||
int direction = -1;
|
||||
int new_position = current_position;
|
||||
|
||||
if (command == "вперёд") {
|
||||
direction = 0;
|
||||
new_position = current_position + 3;
|
||||
} else if (command == "направо") {
|
||||
direction = 1;
|
||||
new_position = current_position + 1;
|
||||
} else if (command == "налево") {
|
||||
direction = 3;
|
||||
new_position = current_position - 1;
|
||||
} else if (command == "назад") {
|
||||
direction = 2;
|
||||
new_position = current_position - 3;
|
||||
} else if (command == "сдаюсь") {
|
||||
break;
|
||||
} else {
|
||||
response = "Неверная команда. Попробуйте снова.\n";
|
||||
send(client_socket, response.c_str(), response.size(), 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Проверка выхода за границы
|
||||
if ((direction == 0 && new_position >= MAZE_SIZE) ||
|
||||
(direction == 1 && (current_position % 3 == 2)) ||
|
||||
(direction == 2 && new_position < 0) ||
|
||||
(direction == 3 && (current_position % 3 == 0)))
|
||||
{
|
||||
maze.set_moves_left(moves_left - 1);
|
||||
if (!check_status(maze))
|
||||
break;
|
||||
response = "там стена, осталось " + std::to_string(maze.get_moves_left()) + " ходов\n";
|
||||
send(client_socket, response.c_str(), response.size(), 0);
|
||||
continue;
|
||||
} else if (maze.is_wall(current_position, direction)) {
|
||||
maze.set_moves_left(moves_left - 1);
|
||||
if (!check_status(maze))
|
||||
break;
|
||||
response = "там стена, осталось " + std::to_string(maze.get_moves_left()) + " ходов\n";
|
||||
send(client_socket, response.c_str(), response.size(), 0);
|
||||
continue;
|
||||
} else {
|
||||
// Успешный ход
|
||||
current_position = new_position;
|
||||
if (current_position == 8) {
|
||||
response = "вы выиграли\n";
|
||||
send(client_socket, response.c_str(), response.size(), 0);
|
||||
break;
|
||||
}
|
||||
|
||||
int x = current_position % 3;
|
||||
int y = current_position / 3;
|
||||
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;
|
||||
send(client_socket, response.c_str(), response.size(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (current_position != 8) {
|
||||
response = "вы проиграли\n";
|
||||
send(client_socket, response.c_str(), response.size(), 0);
|
||||
}
|
||||
|
||||
close(client_socket);
|
||||
std::cout << "Игрок " << player_name << " отключился.\n";
|
||||
}
|
||||
|
||||
void Server::start() {
|
||||
int server_fd, new_socket;
|
||||
struct sockaddr_in address;
|
||||
int opt = 1;
|
||||
int addrlen = sizeof(address);
|
||||
|
||||
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
|
||||
perror("Ошибка создания сокета");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
|
||||
perror("Ошибка настройки сокета");
|
||||
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) {
|
||||
if ((new_socket = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen)) < 0) {
|
||||
perror("Ошибка принятия соединения");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
std::cout << "Новое соединение установлено.\n";
|
||||
std::thread(&Server::handle_client, this, new_socket, true).detach();
|
||||
}
|
||||
}
|
||||
9
src/server/server_main.cpp
Normal file
9
src/server/server_main.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
#include "server.hpp"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
Server server;
|
||||
server.start();
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user