/
sonbka
/
game
Обзор
Документация
Войти
/
sonbka
/
game
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
server_new/server_new.cpp
186 строк
5 KB
sonbka
upload files
15 дек 2025, 23:08
15 дек 2025, 23:08
f238370
Код
Авторство
О чём код?
#include <winsock2.h> #include <ws2tcpip.h> #include <iostream> #include <cstdio> #include <cstring> #include <string> #pragma comment(lib, "ws2_32.lib") #define PORT 12345 #define FIELD 10 struct Player { int x = 0; // row int y = 0; // col }; static const int GOAL_X = FIELD - 1; // 9 static const int GOAL_Y = FIELD / 2; // 5 static bool isWin(const Player& p) { // ПОБЕДА ТОЛЬКО ВНУТРИ клетки цели return (p.x == GOAL_X && p.y == GOAL_Y); } static void applyMove(Player& p, char m) { int nx = p.x, ny = p.y; if (m == 'W') nx--; if (m == 'S') nx++; if (m == 'A') ny--; if (m == 'D') ny++; if (nx >= 0 && nx < FIELD && ny >= 0 && ny < FIELD) { p.x = nx; p.y = ny; } } static int sendAll(SOCKET s, const char* data, int len) { int sent = 0; while (sent < len) { int n = send(s, data + sent, len - sent, 0); if (n <= 0) return -1; sent += n; } return sent; } static bool sendState(SOCKET c1, SOCKET c2, const Player& p1, const Player& p2) { char out[128]; sprintf_s(out, "STATE %d %d %d %d\n", p1.x, p1.y, p2.x, p2.y); return sendAll(c1, out, (int)strlen(out)) > 0 && sendAll(c2, out, (int)strlen(out)) > 0; } static bool sendWin(SOCKET c1, SOCKET c2, int winner) { char out[128]; sprintf_s(out, "WIN Player %d\n", winner); return sendAll(c1, out, (int)strlen(out)) > 0 && sendAll(c2, out, (int)strlen(out)) > 0; } int main() { WSADATA wsa{}; if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) return 1; SOCKET listenSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (listenSock == INVALID_SOCKET) return 1; sockaddr_in addr{}; addr.sin_family = AF_INET; addr.sin_port = htons(PORT); addr.sin_addr.s_addr = INADDR_ANY; if (bind(listenSock, (sockaddr*)&addr, sizeof(addr)) != 0) return 1; if (listen(listenSock, 2) != 0) return 1; std::cout << "Server started on port " << PORT << "\n"; std::cout << "GOAL cell = (" << GOAL_X << "," << GOAL_Y << ")\n"; std::cout << "Waiting for 2 players...\n"; SOCKET c1 = accept(listenSock, nullptr, nullptr); SOCKET c2 = accept(listenSock, nullptr, nullptr); if (c1 == INVALID_SOCKET || c2 == INVALID_SOCKET) return 1; std::cout << "Both players connected!\n"; Player p1{ 0, 0 }; Player p2{ 0, 1 }; sendAll(c1, "START 1\n", 8); sendAll(c2, "START 2\n", 8); // начальное состояние sendState(c1, c2, p1, p2); bool gameOver = false; int winner = 0; fd_set rfds{}; char buf[512]{}; std::string acc1, acc2; auto handleLine = [&](int fromPlayer, const std::string& line) -> bool { char mv = 0; if (sscanf_s(line.c_str(), "MOVE %c", &mv, 1) != 1) return true; // если игра закончилась — не двигаем, но гарантированно шлём финал ещё раз if (gameOver) { sendState(c1, c2, p1, p2); sendWin(c1, c2, winner); return true; } if (fromPlayer == 1) applyMove(p1, mv); else applyMove(p2, mv); // всегда шлём состояние после хода if (!sendState(c1, c2, p1, p2)) return false; // проверяем победу строго "внутри" if (isWin(p1)) { gameOver = true; winner = 1; std::cout << "WIN: P1 at (" << p1.x << "," << p1.y << ")\n"; // продублируем финал, чтобы клиенты точно увидели sendState(c1, c2, p1, p2); sendWin(c1, c2, winner); } else if (isWin(p2)) { gameOver = true; winner = 2; std::cout << "WIN: P2 at (" << p2.x << "," << p2.y << ")\n"; sendState(c1, c2, p1, p2); sendWin(c1, c2, winner); } std::cout << "MOVE from P" << fromPlayer << ": " << mv << " | P1(" << p1.x << "," << p1.y << ")" << " P2(" << p2.x << "," << p2.y << ")\n"; return true; }; auto pump = [&](SOCKET c, std::string& acc, int playerNum) -> bool { int n = recv(c, buf, sizeof(buf) - 1, 0); if (n <= 0) return false; acc.append(buf, buf + n); while (true) { size_t pos = acc.find('\n'); if (pos == std::string::npos) break; std::string line = acc.substr(0, pos); acc.erase(0, pos + 1); if (!handleLine(playerNum, line)) return false; } return true; }; bool running = true; while (running) { FD_ZERO(&rfds); FD_SET(c1, &rfds); FD_SET(c2, &rfds); timeval tv{}; tv.tv_sec = 1; tv.tv_usec = 0; int r = select(0, &rfds, nullptr, nullptr, &tv); if (r == SOCKET_ERROR) break; if (FD_ISSET(c1, &rfds)) running = pump(c1, acc1, 1); if (running && FD_ISSET(c2, &rfds)) running = pump(c2, acc2, 2); } closesocket(c1); closesocket(c2); closesocket(listenSock); WSACleanup(); std::cout << "Server stopped.\n"; system("pause"); return 0; }