Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdint.h>
- #include <unistd.h>
- #include <sys/socket.h>
- #include <sys/ioctl.h>
- #include <sys/types.h>
- #include <net/if.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <string.h>
- #include <netdb.h>
- #include <poll.h>
- #define TEXT_RED "\x1B[1;31m"
- #define TEXT_NORMAL "\x1B[m"
- #define TEXT_CLRSCRN "\x1B[1J"
- #define TEXT_RESETPOS "\x1B[1;1H"
- #define PKT_KEEPALIVE 0x00
- #define PKT_STARTGAME 0x01
- #define PKT_MAKEMOVE 0x02
- #define PKT_PLAYERQUIT 0x03
- #define PKT_GAMEOVER 0x04
- #define PKT_ERROR 0x05
- #define PKT_READY 0x06
- #define PKT_CREATEACCT 0x07
- #define PKT_RECORD 0x08
- #define GAME_WIN 0x00
- #define GAME_LOSS 0x01
- #define GAME_DRAW 0x02
- #define WIN_HORIZ 0x01
- #define WIN_VERT 0x02
- #define WIN_DIAGLR 0x03
- #define WIN_DIAGRL 0x04
- #define BOARD_SIZE 3
- #define PORT 32030
- #define ARRAYLEN(x) (sizeof(x)/sizeof((x)[0]))
- #pragma pack(1)
- struct _pkt_quit {
- unsigned char id;
- char reason[128];
- };
- struct _pkt_start {
- unsigned char id;
- char name[32];
- };
- struct _pkt_createacct {
- unsigned char id;
- uint32_t playerid;
- };
- struct _pkt_record_send {
- unsigned char id;
- uint32_t reqplayerid;
- };
- struct _pkt_record_recv {
- unsigned char id;
- unsigned char success;
- uint32_t wins;
- uint32_t losses;
- uint32_t ties;
- char namelist[32];
- };
- struct _pkt_startgame {
- unsigned char id;
- unsigned char turn;
- uint32_t otherid;
- };
- struct _pkt_ready {
- unsigned char id;
- uint32_t plid;
- };
- #pragma pack()
- void RedrawBoard();
- void DrawWinningBoard(int x, int y, int win);
- void GameHandleStart(char *buf);
- void GameMakeMove(int x, int y);
- void GameQuit(char *r);
- void GetServerAddr(int argc, char *argv[]);
- int ConnectToServer();
- void HandleWaitInput();
- void HandleStdinEvent();
- int HandleSocketEvent();
- void CreateNewAccount();
- void PrintRecord(struct _pkt_record_recv *t);
- char server_addr[64];
- unsigned short port = PORT;
- char your_name[32];
- char opponent_name[32];
- char local_mark;
- char opponent_mark;
- char board[BOARD_SIZE][BOARD_SIZE];
- int turn;
- int sck;
- int local_user_id;
- int remote_user_id;
- int requesting_own_record = 0;
- int requesting_opponent_record = 0;
- int requesting_a_break = 0;
- ///////////////////////////////////////////////////////////////////////////////
- int main(int argc, char *argv[]) {
- unsigned char buf[256];
- struct _pkt_record_send recpack;
- printf("TIC-TAC-TOE CLIENT\n");
- GetServerAddr(argc, argv);
- if (!ConnectToServer())
- return 1;
- do {
- printf("Enter 1 for existing user or 2 for new user: ");
- fgets((char *)buf, sizeof(buf), stdin);
- } while (*buf != '1' && *buf != '2');
- if (*buf == '1') {
- printf("Please enter a valid user id: \n");
- fgets((char *)buf, sizeof(buf), stdin);
- local_user_id = atoi((char *)buf);
- recpack.id = PKT_RECORD;
- recpack.reqplayerid = htonl(local_user_id);
- requesting_own_record = 1;
- send(sck, &recpack, sizeof(recpack), 0);
- } else {
- CreateNewAccount();
- }
- printf(TEXT_CLRSCRN);
- printf(TEXT_RESETPOS);
- memset(board, ' ', BOARD_SIZE * BOARD_SIZE);
- printf("Please wait...\n");
- HandleWaitInput();
- return 0;
- }
- void RedrawBoard() {
- printf(TEXT_CLRSCRN);
- printf(TEXT_RESETPOS);
- if (*opponent_name)
- printf("Playing against %s\n", opponent_name);
- else
- putchar('\n');
- printf("You are playing as %c. Your player ID is %d.\n"
- "It is currently %s turn.\n", local_mark, local_user_id,
- turn ? "your" : "the other player's");
- printf("\n %c|%c|%c\n -+-+-\n %c|%c|%c\n"
- " -+-+-\n %c|%c|%c\n\n\n",
- board[0][0], board[1][0], board[2][0],
- board[0][1], board[1][1], board[2][1],
- board[0][2], board[1][2], board[2][2]);
- }
- void DrawWinningBoard(int x, int y, int win) {
- int i, j;
- printf(TEXT_CLRSCRN);
- printf(TEXT_RESETPOS);
- for (j = 0; j != BOARD_SIZE; j++) {
- printf(" ");
- for (i = 0; i != BOARD_SIZE; i++) {
- switch (win) {
- case WIN_HORIZ:
- if (j == y)
- printf(TEXT_RED "%c" TEXT_NORMAL, board[i][j]);
- else
- putchar(board[i][j]);
- break;
- case WIN_VERT:
- if (i == x)
- printf(TEXT_RED "%c" TEXT_NORMAL, board[i][j]);
- else
- putchar(board[i][j]);
- break;
- case WIN_DIAGLR:
- if (i == j)
- printf(TEXT_RED "%c" TEXT_NORMAL, board[i][j]);
- else
- putchar(board[i][j]);
- break;
- case WIN_DIAGRL:
- if (i == BOARD_SIZE - 1 - j)
- printf(TEXT_RED "%c" TEXT_NORMAL, board[i][j]);
- else
- putchar(board[i][j]);
- break;
- }
- if (i != BOARD_SIZE - 1)
- putchar('|');
- }
- if (j != BOARD_SIZE - 1)
- printf("\n -+-+-\n");
- }
- printf("\n\n\n");
- }
- void HandleWaitInput() {
- unsigned long on;
- struct pollfd fds[2];
- int nready;
- on = 1;
- ioctl(fileno(stdin), FIONBIO, (u_long *)&on);
- on = 1;
- ioctl(sck, FIONBIO, (u_long *)&on);
- fds[0].fd = fileno(stdin);
- fds[0].events = POLLIN | POLLHUP;
- fds[0].revents = 0;
- fds[1].fd = sck;
- fds[1].events = POLLIN | POLLHUP;
- fds[1].revents = 0;
- while ((nready = poll(fds, ARRAYLEN(fds), -1)) > 0) {
- if (fds[0].revents) {
- if (fds[0].revents & POLLIN)
- HandleStdinEvent();
- } else if (fds[1].revents) {
- if (fds[1].revents & POLLHUP) {
- printf("socket HUP\n");
- return;
- } else if (fds[1].revents & POLLIN) {
- if (HandleSocketEvent())
- return;
- }
- }
- }
- }
- void HandleStdinEvent() {
- int x, y;
- char line[128], *sdfg = line;
- struct _pkt_ready ready;
- fgets(line, sizeof(line), stdin);
- if (requesting_a_break) {
- requesting_a_break = 0;
- printf("Please wait for the other player...\n");
- ready.id = PKT_READY;
- ready.plid = htonl(local_user_id);
- send(sck, &ready, sizeof(ready), 0);
- return;
- }
- if (*line == 'q' || *line == 'Q') {
- GameQuit(line + 2);
- }
- while (*sdfg != ' ' && *sdfg != '\t') {
- if (!*sdfg) {
- printf("Improper syntax! <x coordinate> <y coordinate>\n");
- return;
- }
- sdfg++;
- }
- *sdfg++ = 0;
- x = atoi(line);
- y = atoi(sdfg);
- GameMakeMove(x, y);
- }
- int HandleSocketEvent() {
- int rlen;
- char buf[256];
- unsigned char x;
- unsigned char y;
- char *lname;
- struct _pkt_createacct *createacct;
- struct _pkt_record_recv *record;
- struct _pkt_startgame *startgame;
- struct _pkt_record_send recreq;
- rlen = recv(sck, buf, sizeof(buf), 0);
- if (!rlen || rlen == -1) {
- printf("%s disconnection from server.\n",
- !rlen ? "Graceful" : "Forcible");
- close(sck);
- return 1;
- }
- switch (*buf) {
- case PKT_KEEPALIVE: //acknowledge packet as valid, but ignore it
- break;
- case PKT_STARTGAME:
- startgame = (struct _pkt_startgame *)buf;
- remote_user_id = ntohl(startgame->otherid);
- recreq.id = PKT_RECORD;
- recreq.reqplayerid = startgame->otherid;
- send(sck, &recreq, sizeof(recreq), 0);
- requesting_opponent_record = 1;
- GameHandleStart(buf);
- break;
- case PKT_MAKEMOVE:
- x = (unsigned char)buf[1];
- y = (unsigned char)buf[2];
- turn = 1;
- if (x < BOARD_SIZE && y < BOARD_SIZE) {
- board[x][y] = opponent_mark;
- RedrawBoard();
- }
- printf("Enter coordinates:\n");
- break;
- case PKT_PLAYERQUIT:
- printf("%s quit the game! Reason: %s\n", opponent_name, buf + 1);
- shutdown(sck, SHUT_RDWR);
- close(sck);
- return 1;
- case PKT_GAMEOVER:
- if (buf[1] == GAME_DRAW) {
- printf("The game has ended in a draw!\n");
- } else {
- DrawWinningBoard((int)buf[2], (int)buf[3], (int)buf[4]);
- printf("You have %s the game!\n",
- (buf[1] == GAME_WIN) ? "won" : "lost");
- }
- shutdown(sck, SHUT_RDWR);
- close(sck);
- return 1;
- case PKT_ERROR:
- printf("Oops! Sent errorneous 0x%02x packet!\n",
- (unsigned char)buf[1]);
- if (buf[1] == PKT_MAKEMOVE) {
- turn = 1;
- RedrawBoard();
- printf("Oops! Sent errorneous 0x%02x packet!\n",
- (unsigned char)buf[1]);
- printf("It's still your turn.\nRe-enter coordinates:\n");
- }
- break;
- case PKT_CREATEACCT:
- createacct = (struct _pkt_createacct *)buf;
- if (ntohl(createacct->playerid) != 0xFFFFFFFF) {
- local_user_id = ntohl(createacct->playerid);
- //shoot back this same packet as ready
- createacct->id = PKT_READY;
- send(sck, createacct, 5, 0);
- } else {
- printf("Server could not create new player.\n");
- exit(1);
- }
- break;
- case PKT_RECORD:
- record = (struct _pkt_record_recv *)buf;
- if (record->success) {
- if (requesting_own_record) {
- requesting_own_record = 0;
- PrintRecord(record);
- } else if (requesting_opponent_record) {
- requesting_opponent_record = 0;
- lname = record->namelist + strlen(record->namelist) + 1;
- sprintf(opponent_name, "%s %s", record->namelist, lname);
- RedrawBoard();
- }
- } else {
- printf("STOP: record lookup was not successful.\n");
- exit(1); //this may not be nessecary
- }
- break;
- default:
- printf("WARNING: received unhandled packet with ID 0x%02x\n",
- (unsigned char)buf[0]);
- }
- return 0;
- }
- void GameQuit(char *r) {
- struct _pkt_quit quitpacket;
- strncpy(quitpacket.reason, r, strlen(r) + 1);
- quitpacket.id = PKT_PLAYERQUIT;
- send(sck, &quitpacket, 2 + strlen(quitpacket.reason), 0);
- shutdown(sck, SHUT_RDWR);
- close(sck);
- exit(0);
- }
- void GameHandleStart(char *buf) {
- turn = buf[1];
- if (local_user_id < remote_user_id) {
- local_mark = 'X';
- opponent_mark = 'O';
- } else {
- local_mark = 'O';
- opponent_mark = 'X';
- }
- RedrawBoard();
- printf("Starting game! Your opponent is (id=%d) with mark %c."\
- "\n", buf[2],
- opponent_mark);
- printf(turn ? "Enter coordinates:\n" : "Waiting for other player's move...\n");
- }
- void GameMakeMove(int x, int y) {
- char buf[4];
- if (!turn) {
- printf("It's not your turn yet!\n");
- return;
- }
- if (x < 0 || y < 0 || x > BOARD_SIZE - 1 || y > BOARD_SIZE - 1) {
- printf("x and y must be between 0 and 2!\n");
- return;
- }
- if (board[x][y] != ' ') {
- printf("Cell (%d, %d) already marked!\n", x, y);
- return;
- }
- buf[0] = PKT_MAKEMOVE;
- buf[1] = x;
- buf[2] = y;
- send(sck, buf, 3, 0);
- board[x][y] = local_mark;
- turn = 0;
- RedrawBoard();
- printf("Waiting for other player's move...\n");
- }
- void GetServerAddr(int argc, char *argv[]) {
- char *tmp;
- int len;
- if (argc == 1) {
- printf("Please enter the server you wish to play on: ");
- fgets(server_addr, sizeof(server_addr), stdin);
- len = strlen(server_addr);
- if (server_addr[len - 1] == '\n')
- server_addr[len - 1] = 0;
- } else {
- strncpy(server_addr, argv[1], sizeof(server_addr));
- server_addr[sizeof(server_addr) - 1] = 0;
- }
- tmp = server_addr;
- while (*tmp && *tmp != ':')
- tmp++;
- if (*tmp == ':') {
- *tmp = 0;
- port = atoi(tmp + 1);
- }
- }
- int ConnectToServer() {
- struct hostent *he;
- struct sockaddr_in address;
- sck = socket(AF_INET, SOCK_STREAM, 0);
- if (sck == -1) {
- printf("could not get a socket.\n");
- return 0;
- }
- memset(&(address.sin_zero), 0, 8);
- address.sin_family = AF_INET;
- address.sin_port = htons(port);
- he = (struct hostent *)gethostbyname(server_addr);
- if (he == NULL) {
- printf("Couldn't resolve %s!\n", server_addr);
- return 0;
- }
- memcpy(&address.sin_addr, he->h_addr_list[0], he->h_length);
- if (connect(sck, (struct sockaddr *)&address,
- sizeof(struct sockaddr)) == -1) {
- printf("could not connect.\n");
- return 0;
- }
- return 1;
- }
- void CreateNewAccount() {
- int len;
- char buf[64], *s, *t;
- buf[0] = PKT_CREATEACCT;
- printf("FIRST NAME: ");
- fgets(buf + 1, 11, stdin);
- len = strlen(buf + 1);
- if (buf[len] == '\n')
- buf[len] = 0;
- printf("LAST NAME: ");
- fgets((buf + len + 1), 11, stdin);
- len += strlen(buf + len + 1);
- if (buf[len] == '\n')
- buf[len] = 0;
- s = buf + 1;
- t = s + strlen(s) + 1;
- sprintf(your_name, "%s %s", s, t);
- send(sck, buf, (1 + len), 0);
- }
- void PrintRecord(struct _pkt_record_recv *t) {
- char *lname;
- lname = t->namelist + strlen(t->namelist) + 1;
- printf("ID, Firstname, Lastname, Wins, Losses, Ties\n%d,%s,%s,%d,%d,%d\n",
- local_user_id, t->namelist, lname,
- ntohl(t->wins), ntohl(t->losses), ntohl(t->ties));
- sprintf(your_name, "%s %s", t->namelist, lname);
- printf("Press enter when ready...\n");
- requesting_a_break = 1;
- }
Add Comment
Please, Sign In to add comment