From bb0074ac1ceca0140372b132258d64b148f8b52d Mon Sep 17 00:00:00 2001 From: ninya9k <> Date: Tue, 14 Nov 2023 09:39:41 +0000 Subject: [PATCH] --help text. send decoration only when host (WIP). --- uttt.c | 214 +++++++++++++++++++++++++++++++++------------------------ 1 file changed, 123 insertions(+), 91 deletions(-) diff --git a/uttt.c b/uttt.c index 3051610..8aae010 100644 --- a/uttt.c +++ b/uttt.c @@ -21,14 +21,25 @@ struct ut_state char boards[3][3]; int playBoard; char player; + char host_player; }; const struct ut_state ut_initial = { .boards = {0}, .tiles = {0}, .playBoard = -1, - .player = 'X' + .player = 'X', + .host_player = '\0', }; +const char *HELP_TEXT = "\ +Usage: uttt (--local | --host | --join)\n\ +\n\ + --local play non-network game\n\ + --host host game at 127.0.0.1:6669\n\ + --join join game at 127.0.0.1:6669\n\ +"; + +const char *arg_local = "--local"; const char *arg_host = "--host"; const char *arg_join = "--join"; @@ -42,6 +53,13 @@ char ut_turn(char player) } } +int ut_random_player(char *player) { + int random = open("/dev/urandom", O_RDONLY); + if (read(random, player, 1) < 0) {return errno;} + *player = *player % 2 == 0 ? 'X' : 'O'; + return 0; +} + #define T(r, c) (tiles[offset + stride * r + c]) char ut_winner(const char *tiles, int offset, int stride) { @@ -304,7 +322,7 @@ int ut_cursprintf(const char *restrict format, ...) void ut_show(const struct ut_state *state, int fd, bool as_comment) { #define tiles state->tiles - ut_dprintf(fd, "%sTurn: %c\nPlay board: %d\n", as_comment ? "| " : "", (int)state->player, state->playBoard); + ut_dprintf(fd, "%sTurn: %c\n%sPlay board: %d\n", as_comment ? "| " : "", (int)state->player, as_comment ? "| " : "", state->playBoard); int play_board_row = -1; int play_board_col = -1; if (state->playBoard != -1) { @@ -383,65 +401,61 @@ bool getpos(const struct ut_state *state, int *x, int *y) { return true; } -void getpos_net(const struct ut_state *state, int conn, int *x, int *y) { // TODO +void getpos_net(const struct ut_state *state, int sock, int *x, int *y) { // TODO const int MAX_LINE_LEN = 120; char byte; int n; while (true) { - n = recv(conn, &byte, 1, 0); + n = recv(sock, &byte, 1, 0); if (n == 0) {goto conn_closed;} if (byte == '|') { // ignore this line for (int i = 0; i < MAX_LINE_LEN; i++) { - n = recv(conn, &byte, 1, 0); + n = recv(sock, &byte, 1, 0); if (n == 0) {goto conn_closed;} if (byte == '\n') {break;} } if (byte != '\n') { printf("Partner sent too much data in one comment line - exiting\n"); - close(conn); + close(sock); exit(1); } } else { if (byte == '\n') { printf("Partner ended line before coords were complete - retrying\n"); - ut_dprintf(conn_file, "| Invalid coordinates. Try again: "); - fflush(conn_file); + ut_dprintf(sock, "| Invalid coordinates. Try again: "); continue; } *x = byte - 0x30; - n = recv(conn, &byte, 1, 0); + n = recv(sock, &byte, 1, 0); if (n == 0) {goto conn_closed;} if (byte == '\n') { printf("Partner ended line before coords were complete - retrying\n"); - ut_dprintf(conn_file, "| Invalid coordinates. Try again: "); - fflush(conn_file); + ut_dprintf(sock, "| Invalid coordinates. Try again: "); continue; } - n = recv(conn, &byte, 1, 0); + n = recv(sock, &byte, 1, 0); if (n == 0) {goto conn_closed;} if (byte == '\n') { printf("Partner ended line before coords were complete - retrying\n"); - ut_dprintf(conn_file, "| Invalid coordinates. Try again: "); - fflush(conn_file); + ut_dprintf(sock, "| Invalid coordinates. Try again: "); continue; } *y = byte - 0x30; - n = recv(conn, &byte, 1, 0); + n = recv(sock, &byte, 1, 0); if (n == 0) {goto conn_closed;} if (byte != '\n') { printf("Partner sent extra data after coords were complete - ignoring and retrying\n"); - ut_dprintf(conn_file, "| Invalid coordinates. Try again: "); - fflush(conn_file); + ut_dprintf(sock, "| Invalid coordinates. Try again: "); // ignore the rest of this line for (int i = 0; i < MAX_LINE_LEN; i++) { - n = recv(conn, &byte, 1, 0); + n = recv(sock, &byte, 1, 0); if (n == 0) {goto conn_closed;} if (byte == '\n') {break;} } if (byte != '\n') { printf("Partner sent too much extra data - exiting\n"); - close(conn); + close(sock); exit(1); } continue; @@ -506,10 +520,10 @@ void finish(int sig) return 0; }*/ -void ut_local_game(struct ut_state *state) { // TODO replace with from ncurses main +int ut_local_game(struct ut_state *state) { // TODO replace with from ncurses main int x, y; while (true) { - ut_show(state, stdout, false); + ut_show(state, 1, false); ut_show_boards(state); bool ok = getpos(state, &x, &y); if (!ok) {continue;} @@ -526,32 +540,36 @@ void ut_local_game(struct ut_state *state) { // TODO replace with from ncurses m { printf("\n%c wins!\n", (int)w); } + break; } } + return 0; } -void ut_network_game(struct ut_state *state, int conn, FILE* conn_file, char player) { // TODO +int ut_network_game(struct ut_state *state, int sock, char player) { // TODO int x, y; + bool host = player == state->host_player; printf("You play as %c.\n", player); while (true) { - ut_show(state, stdout, false); + ut_show(state, 1, false); ut_show_boards(state); - ut_show(state, conn_file, true); + ut_show(state, sock, true); if (state->player == player) { - ut_dprintf(conn_file, "| Waiting for game partner ...\n"); - fflush(conn_file); + if (host) {ut_dprintf(sock, "| Waiting for game partner ...\n");} bool ok = getpos(state, &x, &y); if (!ok) {continue;} - ut_dprintf(conn_file, "%d,%d\n", x, y); + ut_dprintf(sock, "%d,%d\n", x, y); } else { printf("Waiting for game partner ...\n"); - ut_dprintf(conn_file, "| Place token %c in position x,y: ", ut_turn(player)); - fflush(conn_file); - getpos_net(state, conn, conn_file, &x, &y); + if (host) { + ut_dprintf(sock, "|\n"); // aligns game board each turn + ut_dprintf(sock, "| Place token %c in position x,y: ", ut_turn(player)); + } + getpos_net(state, sock, &x, &y); } int err = ut_move(state, state, y, x); if (err) {continue;} - ut_dprintf(conn_file, "|\n"); + ut_dprintf(sock, "|\n"); char w = ut_winner((char *)state->boards, 0, 3); if(w) { @@ -567,71 +585,85 @@ void ut_network_game(struct ut_state *state, int conn, FILE* conn_file, char pla } } +int ut_host_game(struct ut_state *state) { + int sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock == -1) { + int errsv = errno; + printf("error %d\n", errsv); + return 1; + } + const struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_port = htons(6669), + .sin_addr = { .s_addr = htonl(0x7f000001) }, + }; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)); + if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) { + int errsv = errno; + printf("error %d\n", errsv); + return 1; + } + if (listen(sock, 128) == -1) { + int errsv = errno; + printf("error %d\n", errsv); + return 1; + } + printf("Waiting for game partner at 127.0.0.1:6669 ...\n"); + int conn = accept(sock, NULL, NULL); + if (conn == -1) { + int errsv = errno; + printf("error %d\n", errsv); + return 1; + } + + // decide X or O + if (ut_random_player(&state->host_player) != 0) {return 1;} + + // tell partner X or O + ut_dprintf(conn, "%c\n", ut_turn(state->host_player)); // TODO + + return ut_network_game(state, conn, state->host_player); +} + +int ut_join_game(struct ut_state *state) { + int sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock == -1) { + int errsv = errno; + printf("error %d\n", errsv); + return 1; + } + const struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_port = htons(6666), + .sin_addr = { .s_addr = htonl(0x7f000001) }, + }; + printf("Connecting to game host at 127.0.0.1:6669 ...\n"); + connect(sock, (struct sockaddr*)&addr, sizeof(addr)); + + // host decides X or O + char player; + int r = ut_readfill(sock, &player, 1); + if (r == 2) {printf("Connection closed.\n");} + if (r != 0) {return 1;} + state->host_player = ut_turn(player); + + return ut_network_game(state, sock, player); +} + int main(int argc, char **argv) { signal(SIGINT, finish); struct ut_state state = ut_initial; - if (argc < 2) { - ut_local_game(&state); + if (argc != 2) { + printf(HELP_TEXT); + return 1; + } else if (strncmp(argv[1], arg_local, strlen(arg_local)) == 0) { + return ut_local_game(&state); } else if (strncmp(argv[1], arg_host, strlen(arg_host)) == 0) { - int sock = socket(AF_INET, SOCK_STREAM, 0); - if (sock == -1) { - int errsv = errno; - printf("error %d\n", errsv); - return 1; - } - const struct sockaddr_in addr = { - .sin_family = AF_INET, - .sin_port = htons(6669), - .sin_addr = { .s_addr = htonl(0x7f000001) }, - }; - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)); - if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) { - int errsv = errno; - printf("error %d\n", errsv); - return 1; - } - if (listen(sock, 128) == -1) { - int errsv = errno; - printf("error %d\n", errsv); - return 1; - } - printf("Waiting for game partner at 127.0.0.1:6669 ...\n"); - int conn = accept(sock, NULL, NULL); - if (conn == -1) { - int errsv = errno; - printf("error %d\n", errsv); - return 1; - } - FILE* conn_file = fdopen(conn, "w"); // TODO - // decide X or O - int random = open("/dev/urandom", O_RDONLY); - int byte; - read(random, &byte, 1); - char player = byte % 2 == 0 ? 'X' : 'O'; - // tell partner X or O - ut_dprintf(conn_file, "%c\n", ut_turn(player)); // TODO - ut_network_game(&state, conn, conn_file, player); + return ut_host_game(&state); } else if (strncmp(argv[1], arg_join, strlen(arg_join)) == 0) { - int sock = socket(AF_INET, SOCK_STREAM, 0); - if (sock == -1) { - int errsv = errno; - printf("error %d\n", errsv); - return 1; - } - const struct sockaddr_in addr = { - .sin_family = AF_INET, - .sin_port = htons(6669), - .sin_addr = { .s_addr = htonl(0x7f000001) }, - }; - printf("Connecting to game host at 127.0.0.1:6669 ...\n"); - connect(sock, (struct sockaddr*)&addr, sizeof(addr)); - FILE* sock_file = fdopen(sock, "w"); - char player_buf[2]; - if (recv(sock, &player_buf, 2, 0) != 2) {return 1;} - ut_network_game(&state, sock, sock_file, player_buf[0]); + return ut_join_game(&state); } else { - printf("%s\n", argv[1]); + printf(HELP_TEXT, argv[1]); + return 1; } - return 0; - }