/** * @file client.c * @author Tobias Eidelpes * @date 2018-03-21 * * @brief Client for OSUE exercise 1B `Battleship'. */ #include "common.h" static const char *port = DEFAULT_PORT; static struct addrinfo *ai = NULL; static char *hostname = NULL; static int sockfd = -1; static char* pname; static int field[MAP_SIZE][MAP_SIZE]; static uint8_t x; static uint8_t y; volatile sig_atomic_t quit = 0; static void handle_signal(int signal) { quit = 1; } static void usage(void) { fprintf(stderr, "[%s] Usage:\n\tSYNOPSIS\n\t\t [-h HOSTNAME] [-p PORT]\n\tEXAMPLE\n\tclient -h localhost -p 1280\n", pname); exit(EXIT_FAILURE); } static uint16_t setParity(uint16_t msg) { uint16_t v = msg; v &= 0x7FF; uint8_t parity = 0; while (v) { parity = !parity; v = v & (v - 1); } if (parity) msg += 0x8000; return msg; } static void parse(int argc, char *argv[]) { if (argc == 1) { hostname = NULL; port = "1280"; } else { int opt_index = 0; while ((opt_index = getopt(argc, argv, "h:p:")) != -1) { switch (opt_index) { case 'h': hostname = optarg; break; case 'p': port = optarg; break; case '?': usage(); default: assert(0); } } } } static void cleanup(void) { close(sockfd); free(ai); } static void markSunk(void) { // check north for (int i = y; i >= 0; i--) { if (field[x][i] == 2) field[x][i] = 3; else break; } // check south for (int i = y; i < MAP_SIZE; i++) { if (field[x][i] == 2) field[x][i] = 3; else break; } // check east for (int i = x; i >= 0; i--) { if (field[i][y] == 2) field[i][y] = 3; else break; } // check west for (int i = x; i < MAP_SIZE; i++) { if (field[i][y] == 2) field[i][y] = 3; else break; } } static int checkNorth(void) { int j = y - 1; for (; j >= 0; --j) { if (field[x][j] == 0) { y = j; return 1; } else { return 0; } } return 0; } static int checkSouth(void) { int j = y + 1; for (; j < MAP_SIZE; ++j) { if (field[x][j] == 0) { y = j; return 1; } else { return 0; } } return 0; } static int checkEast(void) { int i = x - 1; for (; i >= 0; --i) { if (field[i][y] == 0) { x = i; return 1; } else { return 0; } } return 0; } static int checkWest(void) { int i = x + 1; for (; i < MAP_SIZE; ++i) { if (field[i][y] == 0) { x = i; return 1; } else { return 0; } } return 0; } static void searchHit(void) { for (int j = 0; j < MAP_SIZE; j++) { for (int i = 0; i < MAP_SIZE; i++) { if (field[i][j] == 2) { x = i; y = j; if (checkNorth()) { return; } if (checkSouth()) { return; } if (checkEast()) { return; } if (checkWest()) { return; } } } } x = rand() % 10; y = rand() % 10; while(field[x][y] != 0) { x = rand() % 10; y = rand() % 10; } } static void makeHit(void) { uint8_t buffer[1]; uint8_t status; uint8_t hit; uint16_t msg; msg = x; msg <<= 6; msg += y; msg = setParity(msg); uint16_t v = msg; v &= 0x00FF; buffer[0] = v; send(sockfd, buffer, 1, 0); v = msg; v &= 0xFF00; v >>= 8; buffer[0] = v; send(sockfd, buffer, 1, 0); recv(sockfd, buffer, 1, 0); status = buffer[0]; status &= 0x0C; hit = buffer[0]; hit &= 0x03; switch (status) { case 2: fprintf(stderr, "[%s] Parity error\n", pname); cleanup(); exit(2); case 3: fprintf(stderr, "[%s] Invalid coordinate\n", pname); cleanup(); exit(3); default: break; } if (status == 1 && (hit == 0 || hit == 1 || hit == 2)) { fprintf(stdout, "[%s] Game lost\n", pname); cleanup(); exit(EXIT_SUCCESS); } else if (status == 1 && hit == 3) { fprintf(stdout, "[%s] I win :)\n", pname); cleanup(); exit(EXIT_SUCCESS); } if (hit == 0) field[x][y] = 1; if (hit == 1) field[x][y] = 2; if (hit == 2) markSunk(); } int main(int argc, char *argv[]) { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = handle_signal; sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); pname = argv[0]; parse(argc, argv); struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; int res = getaddrinfo(hostname, port, &hints, &ai); if (res < 0) { fprintf(stderr, "[%s] ERROR: Failed to get address info: %s\n", pname, gai_strerror(res)); exit(EXIT_FAILURE); } sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (sockfd < 0) { perror(pname); exit(EXIT_FAILURE); } if (connect(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) { close(sockfd); perror(pname); exit(EXIT_FAILURE); } srand(time(NULL)); while(quit == 0) { searchHit(); makeHit(); // printMap(); } cleanup(); exit(EXIT_SUCCESS); }