Guest User

Untitled

a guest
Apr 22nd, 2018
67
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 12.28 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <stdint.h>
  4. #include <unistd.h>
  5. #include <sys/socket.h>
  6. #include <sys/ioctl.h>
  7. #include <sys/types.h>
  8. #include <net/if.h>
  9. #include <netinet/in.h>
  10. #include <arpa/inet.h>
  11. #include <string.h>
  12. #include <netdb.h>
  13. #include <poll.h>
  14.  
  15. #define TEXT_RED      "\x1B[1;31m"
  16. #define TEXT_NORMAL   "\x1B[m"
  17. #define TEXT_CLRSCRN  "\x1B[1J"
  18. #define TEXT_RESETPOS "\x1B[1;1H"
  19.  
  20. #define PKT_KEEPALIVE  0x00
  21. #define PKT_STARTGAME  0x01
  22. #define PKT_MAKEMOVE   0x02
  23. #define PKT_PLAYERQUIT 0x03
  24. #define PKT_GAMEOVER   0x04
  25. #define PKT_ERROR      0x05
  26. #define PKT_READY      0x06
  27. #define PKT_CREATEACCT 0x07
  28. #define PKT_RECORD     0x08
  29.  
  30. #define GAME_WIN  0x00
  31. #define GAME_LOSS 0x01
  32. #define GAME_DRAW 0x02
  33.  
  34. #define WIN_HORIZ  0x01
  35. #define WIN_VERT   0x02
  36. #define WIN_DIAGLR 0x03
  37. #define WIN_DIAGRL 0x04
  38.  
  39. #define BOARD_SIZE 3
  40.  
  41. #define PORT 32030
  42.  
  43. #define ARRAYLEN(x) (sizeof(x)/sizeof((x)[0]))
  44.  
  45. #pragma pack(1)
  46. struct _pkt_quit {
  47.     unsigned char id;
  48.     char reason[128];
  49. };
  50.  
  51. struct _pkt_start {
  52.     unsigned char id;
  53.     char name[32];
  54. };
  55.  
  56. struct _pkt_createacct {
  57.     unsigned char id;
  58.     uint32_t playerid;
  59. };
  60.  
  61. struct _pkt_record_send {
  62.     unsigned char id;
  63.     uint32_t reqplayerid;
  64. };
  65.  
  66. struct _pkt_record_recv {
  67.     unsigned char id;
  68.     unsigned char success;
  69.     uint32_t wins;
  70.     uint32_t losses;
  71.     uint32_t ties;
  72.     char namelist[32];
  73. };
  74.  
  75. struct _pkt_startgame {
  76.     unsigned char id;
  77.     unsigned char turn;
  78.     uint32_t otherid;
  79. };
  80.  
  81. struct _pkt_ready {
  82.     unsigned char id;
  83.     uint32_t plid;
  84. };
  85. #pragma pack()
  86.  
  87. void RedrawBoard();
  88. void DrawWinningBoard(int x, int y, int win);
  89.  
  90. void GameHandleStart(char *buf);
  91. void GameMakeMove(int x, int y);
  92. void GameQuit(char *r);
  93.  
  94. void GetServerAddr(int argc, char *argv[]);
  95. int ConnectToServer();
  96.  
  97. void HandleWaitInput();
  98. void HandleStdinEvent();
  99. int HandleSocketEvent();
  100.  
  101. void CreateNewAccount();
  102. void PrintRecord(struct _pkt_record_recv *t);
  103.  
  104. char server_addr[64];
  105. unsigned short port = PORT;
  106. char your_name[32];
  107. char opponent_name[32];
  108. char local_mark;
  109. char opponent_mark;
  110. char board[BOARD_SIZE][BOARD_SIZE];
  111. int turn;
  112. int sck;
  113. int local_user_id;
  114. int remote_user_id;
  115. int requesting_own_record = 0;
  116. int requesting_opponent_record = 0;
  117. int requesting_a_break = 0;
  118.  
  119. ///////////////////////////////////////////////////////////////////////////////
  120.  
  121.  
  122. int main(int argc, char *argv[]) {
  123.     unsigned char buf[256];
  124.     struct _pkt_record_send recpack;
  125.  
  126.     printf("TIC-TAC-TOE CLIENT\n");
  127.  
  128.     GetServerAddr(argc, argv);
  129.  
  130.     if (!ConnectToServer())
  131.         return 1;
  132.    
  133.     do {
  134.         printf("Enter 1 for existing user or 2 for new user: ");
  135.         fgets((char *)buf, sizeof(buf), stdin);
  136.     } while (*buf != '1' && *buf != '2');
  137.    
  138.     if (*buf == '1') {
  139.         printf("Please enter a valid user id: \n");
  140.        
  141.         fgets((char *)buf, sizeof(buf), stdin);
  142.         local_user_id = atoi((char *)buf);
  143.        
  144.         recpack.id = PKT_RECORD;
  145.         recpack.reqplayerid = htonl(local_user_id);
  146.        
  147.         requesting_own_record = 1;
  148.        
  149.         send(sck, &recpack, sizeof(recpack), 0);
  150.     } else {
  151.         CreateNewAccount();
  152.     }
  153.  
  154.     printf(TEXT_CLRSCRN);
  155.     printf(TEXT_RESETPOS);
  156.     memset(board, ' ', BOARD_SIZE * BOARD_SIZE);
  157.  
  158.     printf("Please wait...\n");
  159.  
  160.     HandleWaitInput();
  161.    
  162.     return 0;
  163. }
  164.  
  165.  
  166. void RedrawBoard() {
  167.     printf(TEXT_CLRSCRN);
  168.     printf(TEXT_RESETPOS);
  169.    
  170.     if (*opponent_name)
  171.         printf("Playing against %s\n", opponent_name);
  172.     else
  173.         putchar('\n');
  174.     printf("You are playing as %c. Your player ID is %d.\n"
  175.         "It is currently %s turn.\n", local_mark, local_user_id,
  176.         turn ? "your" : "the other player's");
  177.  
  178.     printf("\n    %c|%c|%c\n    -+-+-\n    %c|%c|%c\n"
  179.         "    -+-+-\n    %c|%c|%c\n\n\n",
  180.         board[0][0], board[1][0], board[2][0],
  181.         board[0][1], board[1][1], board[2][1],
  182.         board[0][2], board[1][2], board[2][2]);
  183. }
  184.  
  185.  
  186. void DrawWinningBoard(int x, int y, int win) {
  187.     int i, j;
  188.  
  189.     printf(TEXT_CLRSCRN);
  190.     printf(TEXT_RESETPOS);
  191.  
  192.     for (j = 0; j != BOARD_SIZE; j++) {
  193.         printf("    ");
  194.         for (i = 0; i != BOARD_SIZE; i++) {
  195.             switch (win) {
  196.                 case WIN_HORIZ:
  197.                     if (j == y)
  198.                         printf(TEXT_RED "%c" TEXT_NORMAL, board[i][j]);
  199.                     else
  200.                         putchar(board[i][j]);
  201.                     break;
  202.                 case WIN_VERT:
  203.                     if (i == x)
  204.                         printf(TEXT_RED "%c" TEXT_NORMAL, board[i][j]);
  205.                     else
  206.                         putchar(board[i][j]);
  207.                     break;
  208.                 case WIN_DIAGLR:
  209.                     if (i == j)
  210.                         printf(TEXT_RED  "%c" TEXT_NORMAL, board[i][j]);
  211.                     else
  212.                         putchar(board[i][j]);
  213.                     break;
  214.                 case WIN_DIAGRL:
  215.                     if (i == BOARD_SIZE - 1 - j)
  216.                         printf(TEXT_RED "%c" TEXT_NORMAL, board[i][j]);
  217.                     else
  218.                         putchar(board[i][j]);
  219.                     break;
  220.             }
  221.             if (i != BOARD_SIZE - 1)
  222.                 putchar('|');
  223.         }
  224.         if (j != BOARD_SIZE - 1)
  225.             printf("\n    -+-+-\n");
  226.     }
  227.     printf("\n\n\n");
  228. }
  229.  
  230.  
  231. void HandleWaitInput() {
  232.     unsigned long on;
  233.     struct pollfd fds[2];
  234.     int nready;
  235.  
  236.     on = 1;
  237.     ioctl(fileno(stdin), FIONBIO, (u_long *)&on);
  238.     on = 1;
  239.     ioctl(sck, FIONBIO, (u_long *)&on);
  240.  
  241.     fds[0].fd      = fileno(stdin);
  242.     fds[0].events  = POLLIN | POLLHUP;
  243.     fds[0].revents = 0;
  244.  
  245.     fds[1].fd      = sck;
  246.     fds[1].events  = POLLIN | POLLHUP;
  247.     fds[1].revents = 0;
  248.  
  249.     while ((nready = poll(fds, ARRAYLEN(fds), -1)) > 0) {
  250.         if (fds[0].revents) {
  251.             if (fds[0].revents & POLLIN)
  252.                 HandleStdinEvent();
  253.         } else if (fds[1].revents) {
  254.             if (fds[1].revents & POLLHUP) {
  255.                 printf("socket HUP\n");
  256.                 return;
  257.             } else if (fds[1].revents & POLLIN) {
  258.                 if (HandleSocketEvent())
  259.                     return;
  260.             }
  261.         }
  262.     }
  263.  
  264. }
  265.  
  266.  
  267. void HandleStdinEvent() {
  268.     int x, y;
  269.     char line[128], *sdfg = line;
  270.     struct _pkt_ready ready;
  271.  
  272.     fgets(line, sizeof(line), stdin);
  273.  
  274.     if (requesting_a_break) {
  275.         requesting_a_break = 0;
  276.         printf("Please wait for the other player...\n");
  277.         ready.id = PKT_READY;
  278.         ready.plid = htonl(local_user_id);
  279.         send(sck, &ready, sizeof(ready), 0);
  280.         return;
  281.     }
  282.  
  283.     if (*line == 'q' || *line == 'Q') {
  284.         GameQuit(line + 2);
  285.     }
  286.  
  287.     while (*sdfg != ' ' && *sdfg != '\t') {
  288.         if (!*sdfg) {
  289.             printf("Improper syntax! <x coordinate> <y coordinate>\n");
  290.             return;
  291.         }
  292.         sdfg++;
  293.     }
  294.     *sdfg++ = 0;
  295.    
  296.     x = atoi(line);
  297.     y = atoi(sdfg);
  298.  
  299.     GameMakeMove(x, y);
  300. }
  301.  
  302.  
  303. int HandleSocketEvent() {
  304.     int rlen;
  305.     char buf[256];
  306.     unsigned char x;
  307.     unsigned char y;
  308.     char *lname;
  309.     struct _pkt_createacct *createacct;
  310.     struct _pkt_record_recv *record;
  311.     struct _pkt_startgame *startgame;
  312.     struct _pkt_record_send recreq;
  313.  
  314.     rlen = recv(sck, buf, sizeof(buf), 0);
  315.     if (!rlen || rlen == -1) {
  316.         printf("%s disconnection from server.\n",
  317.             !rlen ? "Graceful" : "Forcible");
  318.         close(sck);
  319.         return 1;
  320.     }
  321.     switch (*buf) {
  322.         case PKT_KEEPALIVE: //acknowledge packet as valid, but ignore it
  323.             break;
  324.         case PKT_STARTGAME:
  325.             startgame = (struct _pkt_startgame *)buf;
  326.             remote_user_id = ntohl(startgame->otherid);
  327.             recreq.id = PKT_RECORD;
  328.             recreq.reqplayerid = startgame->otherid;
  329.             send(sck, &recreq, sizeof(recreq), 0);
  330.             requesting_opponent_record = 1;
  331.             GameHandleStart(buf);
  332.             break;
  333.         case PKT_MAKEMOVE:
  334.             x = (unsigned char)buf[1];
  335.             y = (unsigned char)buf[2];
  336.            
  337.             turn = 1;
  338.             if (x < BOARD_SIZE && y < BOARD_SIZE) {
  339.                 board[x][y] = opponent_mark;
  340.                 RedrawBoard();
  341.             }
  342.             printf("Enter coordinates:\n");
  343.             break;
  344.         case PKT_PLAYERQUIT:
  345.             printf("%s quit the game! Reason: %s\n", opponent_name, buf + 1);
  346.             shutdown(sck, SHUT_RDWR);
  347.             close(sck);
  348.             return 1;
  349.         case PKT_GAMEOVER:
  350.             if (buf[1] == GAME_DRAW) {
  351.                 printf("The game has ended in a draw!\n");
  352.             } else {
  353.                 DrawWinningBoard((int)buf[2], (int)buf[3], (int)buf[4]);
  354.                 printf("You have %s the game!\n",
  355.                     (buf[1] == GAME_WIN) ? "won" : "lost");
  356.             }
  357.             shutdown(sck, SHUT_RDWR);
  358.             close(sck);
  359.             return 1;
  360.         case PKT_ERROR:
  361.             printf("Oops! Sent errorneous 0x%02x packet!\n",
  362.             (unsigned char)buf[1]);
  363.             if (buf[1] == PKT_MAKEMOVE) {
  364.                 turn = 1;
  365.                 RedrawBoard();
  366.                 printf("Oops! Sent errorneous 0x%02x packet!\n",
  367.                     (unsigned char)buf[1]);
  368.                 printf("It's still your turn.\nRe-enter coordinates:\n");
  369.             }
  370.             break;
  371.         case PKT_CREATEACCT:
  372.             createacct = (struct _pkt_createacct *)buf;
  373.             if (ntohl(createacct->playerid) != 0xFFFFFFFF) {
  374.                 local_user_id = ntohl(createacct->playerid);
  375.                
  376.                 //shoot back this same packet as ready
  377.                 createacct->id = PKT_READY;
  378.                 send(sck, createacct, 5, 0);
  379.             } else {
  380.                 printf("Server could not create new player.\n");
  381.                 exit(1);
  382.             }
  383.             break;
  384.         case PKT_RECORD:
  385.             record = (struct _pkt_record_recv *)buf;
  386.             if (record->success) {
  387.                 if (requesting_own_record) {
  388.                     requesting_own_record = 0;
  389.                     PrintRecord(record);
  390.                 } else if (requesting_opponent_record) {
  391.                     requesting_opponent_record = 0;
  392.                     lname = record->namelist + strlen(record->namelist) + 1;
  393.                     sprintf(opponent_name, "%s %s", record->namelist, lname);
  394.                     RedrawBoard();
  395.                 }
  396.             } else {
  397.                 printf("STOP: record lookup was not successful.\n");
  398.                 exit(1); //this may not be nessecary
  399.             }
  400.             break;
  401.         default:
  402.             printf("WARNING: received unhandled packet with ID 0x%02x\n",
  403.                 (unsigned char)buf[0]);
  404.     }
  405.     return 0;
  406. }
  407.  
  408.  
  409. void GameQuit(char *r) {
  410.     struct _pkt_quit quitpacket;
  411.  
  412.     strncpy(quitpacket.reason, r, strlen(r) + 1);
  413.    
  414.     quitpacket.id = PKT_PLAYERQUIT;
  415.     send(sck, &quitpacket, 2 + strlen(quitpacket.reason), 0);
  416.  
  417.     shutdown(sck, SHUT_RDWR);
  418.     close(sck);
  419.     exit(0);
  420. }
  421.  
  422.  
  423. void GameHandleStart(char *buf) {
  424.     turn = buf[1];
  425.  
  426.     if (local_user_id < remote_user_id) {
  427.         local_mark    = 'X';
  428.         opponent_mark = 'O';
  429.     } else {
  430.         local_mark    = 'O';
  431.         opponent_mark = 'X';
  432.     }
  433.    
  434.     RedrawBoard();
  435.  
  436.     printf("Starting game! Your opponent is (id=%d) with mark %c."\
  437.             "\n", buf[2],
  438.             opponent_mark);
  439.  
  440.     printf(turn ? "Enter coordinates:\n" : "Waiting for other player's move...\n");
  441. }
  442.  
  443.  
  444. void GameMakeMove(int x, int y) {
  445.     char buf[4];
  446.  
  447.     if (!turn) {
  448.         printf("It's not your turn yet!\n");
  449.         return;
  450.     }
  451.  
  452.     if (x < 0 || y < 0 || x > BOARD_SIZE - 1 || y > BOARD_SIZE - 1) {
  453.         printf("x and y must be between 0 and 2!\n");
  454.         return;
  455.     }
  456.        
  457.     if (board[x][y] != ' ') {
  458.         printf("Cell (%d, %d) already marked!\n", x, y);
  459.         return;
  460.     }
  461.  
  462.     buf[0] = PKT_MAKEMOVE;
  463.     buf[1] = x;
  464.     buf[2] = y;
  465.     send(sck, buf, 3, 0);
  466.  
  467.     board[x][y] = local_mark;
  468.  
  469.     turn = 0;
  470.     RedrawBoard();
  471.     printf("Waiting for other player's move...\n");
  472. }
  473.  
  474.  
  475. void GetServerAddr(int argc, char *argv[]) {
  476.     char *tmp;
  477.     int len;
  478.  
  479.     if (argc == 1) {
  480.         printf("Please enter the server you wish to play on: ");
  481.         fgets(server_addr, sizeof(server_addr), stdin);
  482.         len = strlen(server_addr);
  483.         if (server_addr[len - 1] == '\n')
  484.             server_addr[len - 1] = 0;
  485.     } else {
  486.         strncpy(server_addr, argv[1], sizeof(server_addr));
  487.         server_addr[sizeof(server_addr) - 1] = 0;
  488.     }
  489.     tmp = server_addr;
  490.     while (*tmp && *tmp != ':')
  491.         tmp++;
  492.  
  493.     if (*tmp == ':') {
  494.         *tmp = 0;
  495.         port = atoi(tmp + 1);
  496.     }
  497. }
  498.  
  499.  
  500. int ConnectToServer() {
  501.     struct hostent *he;
  502.     struct sockaddr_in address;
  503.  
  504.     sck = socket(AF_INET, SOCK_STREAM, 0);
  505.     if (sck == -1) {
  506.         printf("could not get a socket.\n");
  507.         return 0;
  508.     }
  509.  
  510.     memset(&(address.sin_zero), 0, 8);
  511.     address.sin_family = AF_INET;
  512.     address.sin_port   = htons(port);
  513.  
  514.     he = (struct hostent *)gethostbyname(server_addr);
  515.     if (he == NULL) {
  516.         printf("Couldn't resolve %s!\n", server_addr);
  517.         return 0;
  518.     }
  519.  
  520.     memcpy(&address.sin_addr, he->h_addr_list[0], he->h_length);
  521.  
  522.     if (connect(sck, (struct sockaddr *)&address,
  523.         sizeof(struct sockaddr)) == -1) {
  524.         printf("could not connect.\n");
  525.         return 0;
  526.     }
  527.  
  528.     return 1;
  529. }
  530.  
  531.  
  532. void CreateNewAccount() {
  533.     int len;
  534.     char buf[64], *s, *t;
  535.    
  536.     buf[0] = PKT_CREATEACCT;
  537.    
  538.     printf("FIRST NAME: ");
  539.     fgets(buf + 1, 11, stdin);
  540.     len = strlen(buf + 1);
  541.     if (buf[len] == '\n')
  542.         buf[len] = 0;
  543.    
  544.     printf("LAST NAME: ");
  545.     fgets((buf + len + 1), 11, stdin);
  546.    
  547.     len += strlen(buf + len + 1);
  548.     if (buf[len] == '\n')
  549.         buf[len] = 0;
  550.        
  551.     s = buf + 1;
  552.     t = s + strlen(s) + 1;
  553.    
  554.     sprintf(your_name, "%s %s", s, t);
  555.    
  556.     send(sck, buf, (1 + len), 0);
  557. }
  558.  
  559.  
  560. void PrintRecord(struct _pkt_record_recv *t) {
  561.     char *lname;
  562.    
  563.     lname = t->namelist + strlen(t->namelist) + 1;
  564.     printf("ID, Firstname, Lastname, Wins, Losses, Ties\n%d,%s,%s,%d,%d,%d\n",
  565.         local_user_id, t->namelist, lname,
  566.         ntohl(t->wins), ntohl(t->losses), ntohl(t->ties));
  567.        
  568.     sprintf(your_name, "%s %s", t->namelist, lname);
  569.    
  570.     printf("Press enter when ready...\n");
  571.     requesting_a_break = 1;
  572. }
Add Comment
Please, Sign In to add comment