game_server.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. #define _GNU_SOURCE
  2. #include <ctype.h>
  3. #include <unistd.h>
  4. #include <sys/types.h>
  5. #include <unistd.h>
  6. #include <sys/time.h>
  7. #include <limits.h>
  8. #include <stdio.h>
  9. #include "game_server.h"
  10. Player *player_list = NULL;
  11. Client *client_list = NULL;
  12. short port = -1;
  13. char board[4][4];
  14. char dice[16][6] = {
  15. {'R', 'I', 'F', 'O', 'B', 'X'},
  16. {'I', 'F', 'E', 'H', 'E', 'Y'},
  17. {'D', 'E', 'N', 'O', 'W', 'S'},
  18. {'U', 'T', 'O', 'K', 'N', 'D'},
  19. {'H', 'M', 'S', 'R', 'A', 'O'},
  20. {'L', 'U', 'P', 'E', 'T', 'S'},
  21. {'A', 'C', 'I', 'T', 'O', 'A'},
  22. {'Y', 'L', 'G', 'K', 'U', 'E'},
  23. {'Q', 'B', 'M', 'J', 'O', 'A'},
  24. {'E', 'H', 'I', 'S', 'P', 'N'},
  25. {'V', 'E', 'T', 'I', 'G', 'N'},
  26. {'B', 'A', 'L', 'I', 'Y', 'T'},
  27. {'E', 'Z', 'A', 'V', 'N', 'D'},
  28. {'R', 'A', 'L', 'E', 'S', 'C'},
  29. {'U', 'W', 'I', 'L', 'R', 'G'},
  30. {'P', 'A', 'C', 'E', 'M', 'D'}
  31. };
  32. //word checker
  33. int exists = 0;
  34. void isaword_helper(int ** passed, int i, int j, char * str, char * goal){
  35. //printf("strlength: %d\n", (int)strlen(str));
  36. passed[i][j] = 1;
  37. str[strlen(str)] = board[i][j];
  38. //printf("strlength: %d\n", (int)strlen(str));
  39. //printf("here: %s\n", str);
  40. if(strcmp(str, goal) == 0){
  41. // printf("exists!\n");
  42. exists = 1;
  43. return;
  44. }
  45. for (int r = i-1; r <= i+1 && r < 4; r++)
  46. for (int c = j-1; c <= j+1 && c < 4; c++)
  47. if (r >=0 && c >=0 && !passed[r][c])
  48. if(goal[strlen(str)] == board[r][c]){
  49. // printf("indside!\n");
  50. // printf("strlength: %d\n", (int)strlen(str));
  51. isaword_helper(passed, r, c, str, goal);
  52. }
  53. str[strlen(str) - 1] = '\0';
  54. passed[i][j] = 0;
  55. }
  56. int isaword(char * goal){
  57. // printf("the word is: %s\n", goal);
  58. int ** temp = malloc(sizeof(int*) * 4);
  59. for(int i = 0; i < 4; i ++)
  60. temp[i] = malloc(sizeof(int) * 4);
  61. for(int x = 0; x < 4; x++)
  62. for(int y = 0; y < 4; y++)
  63. temp[x][y] = 0;
  64. char * string = calloc(1, 1024);
  65. for(int i = 0; i < 4; i++)
  66. for(int j = 0; j < 4; j++)
  67. isaword_helper(temp, i, j, string, goal);
  68. for(int i = 0; i < 4; i++)
  69. free(temp[i]);
  70. free(temp);
  71. free(string);
  72. return exists;
  73. }
  74. void capitalize(char* s){
  75. int i = 0;
  76. while(s[i]) {
  77. unsigned char c = (unsigned char ) s[i];
  78. s[i] = toupper(c);
  79. i++;
  80. }
  81. }
  82. int wordval(char * s){
  83. if(strlen(s) == 3)
  84. return 1;
  85. if(strlen(s) == 4)
  86. return 1;
  87. if(strlen(s) == 5)
  88. return 2;
  89. if(strlen(s) == 6)
  90. return 3;
  91. if(strlen(s) == 7)
  92. return 5;
  93. if(strlen(s) >= 8)
  94. return 11;
  95. return 0;
  96. }
  97. //sets values in char board
  98. void generate_board(){
  99. srand(time(0));
  100. int filled[16];
  101. for(int i = 0; i < 16; i++)
  102. filled[i] = 0;
  103. for(int i = 0; i < 4; i++)
  104. for(int j = 0; j < 4; j++){
  105. int dicenumber = rand() % 16;
  106. while(filled[dicenumber] == 1)
  107. dicenumber = rand() % 16;
  108. board[i][j] = dice[dicenumber][rand() % 6];
  109. filled[dicenumber] = 1;
  110. }
  111. }
  112. int main(int argc, char* argv[]) {
  113. struct client *p;
  114. if (argc > 1)
  115. port = (short)(atoi(argv[1]));
  116. else
  117. port = PORT;
  118. //get listen file descriptor
  119. int listenfd = setup();
  120. //TODO install timer signal handler
  121. struct sigaction signal_handler;
  122. signal_handler.sa_handler = timer_handler;
  123. sigemptyset(&signal_handler.sa_mask);
  124. signal_handler.sa_flags = 0;
  125. sigaction(SIGALRM, &signal_handler, NULL);
  126. //timeval for timeout
  127. struct timeval tv;
  128. tv.tv_sec = TIMER_TICK - 1;
  129. //struct timeval t
  130. tv.tv_usec = 0;
  131. //start timer
  132. alarm(TIMER_TICK);
  133. int maxfd;
  134. //Client * curr;
  135. fd_set fdlist;
  136. generate_board();
  137. int rv;
  138. //TODO: implement select()
  139. while (1) {
  140. //fd_set fdlist;
  141. //maxfd = serv_fd;
  142. //maxfd = listenfd;
  143. FD_ZERO(&fdlist);
  144. FD_SET(listenfd, &fdlist);
  145. maxfd = listenfd + 1;
  146. p = client_list;
  147. while (p != NULL){
  148. FD_SET(p->fd, &fdlist);
  149. if (p->fd+ 1 > maxfd)
  150. maxfd = p->fd + 1;
  151. p = p->next;
  152. }
  153. if ((rv = select(maxfd + 1, &fdlist, NULL, NULL, &tv)) < 0) {
  154. perror("select");
  155. }
  156. else if (rv == 0) { //timeout
  157. fprintf(stderr, "Select() Timed Out\n");
  158. }
  159. else {
  160. p = client_list;
  161. while(p){
  162. if (FD_ISSET(p->fd, &fdlist)){ //iterate through clients
  163. break;
  164. }
  165. p= p->next;
  166. }
  167. if (p){ //after loop breaks
  168. Client * temp = p;
  169. receiveclient(temp);
  170. }
  171. if (FD_ISSET(listenfd, &fdlist))
  172. new_connection(listenfd);
  173. }
  174. tv.tv_sec = TIMER_TICK;
  175. //struct timeval tv2
  176. tv.tv_usec = 0;
  177. }
  178. return 0;
  179. }
  180. /*
  181. * Sets up server socket: bind and listen
  182. * Returns a file descriptor for listening and accepting new connections
  183. */
  184. int setup (void) {
  185. int on = 1, status;
  186. struct sockaddr_in self;
  187. int listenfd;
  188. if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
  189. perror("socket");
  190. exit(1);
  191. }
  192. status = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR,
  193. (const char *) &on, sizeof(on));
  194. if(status == -1) {
  195. perror("setsockopt -- REUSEADDR");
  196. }
  197. memset(&self, '\0', sizeof(self));
  198. self.sin_family = AF_INET;
  199. self.sin_addr.s_addr = INADDR_ANY;
  200. self.sin_port = htons(port);
  201. printf("Listening on %d\n", port);
  202. if (bind(listenfd, (struct sockaddr *)&self, sizeof(self)) == -1) {
  203. perror("bind"); // probably means port is in use
  204. exit(1);
  205. }
  206. if (listen(listenfd, 5) == -1) {
  207. perror("listen");
  208. exit(1);
  209. }
  210. return listenfd;
  211. }
  212. /* timer signal handler */
  213. void timer_handler(int sig) {
  214. //broadcast current game end to all connected clients
  215. Client *curr;
  216. for (curr = client_list; curr!=NULL; curr = curr->next) {
  217. sendclient(curr, "Game over\r\n");
  218. }
  219. //TODO - generate new game board
  220. generate_board();
  221. //reset the timer so we get called again in 120 seconds
  222. alarm(TIMER_TICK);
  223. }
  224. /* accepts new connection and adds a client-specific fd */
  225. void new_connection (int listenfd) {
  226. int fd;
  227. struct sockaddr_in r;
  228. socklen_t socklen = sizeof(r);
  229. if ((fd = accept(listenfd, (struct sockaddr *)&r, &socklen)) < 0) {
  230. printf("here\n");
  231. perror("accept");
  232. return;
  233. }
  234. printf("connection from %s\n", inet_ntoa(r.sin_addr));
  235. add_client(fd, r.sin_addr);
  236. }
  237. /* creates a new client struct and
  238. TODO - adds it to the list of clients */
  239. void add_client(int fd, struct in_addr addr){
  240. struct client *p = malloc(sizeof(struct client)); //new client created
  241. if (!p) {
  242. perror("malloc failure");
  243. exit(1);
  244. }
  245. printf("Adding client %s\n", inet_ntoa(addr));
  246. fflush(stdout);
  247. p->fd = fd;
  248. p->state = NAME; //needs yet to identify new client by name
  249. p->inbuf = 0;
  250. //TODO - add it to the list of clients
  251. if(client_list == NULL){ //first client added to list
  252. client_list = p;
  253. }
  254. else {
  255. Client * temp = client_list; //clients other than first
  256. while(client_list->next)
  257. temp = client_list->next;
  258. temp->next = p;
  259. }
  260. sendclient(p, "What is your player name?\n");
  261. }
  262. void remove_client(int fd){
  263. if(client_list == NULL) //empty list
  264. return;
  265. Client * curr = client_list;
  266. //fprintf(stderr, "%s is being removed...\n", (*p)->name);
  267. if(curr->fd == fd){ //iterates through. first client removed here
  268. if(!curr->next){
  269. client_list = NULL;
  270. sendclient(curr, "thank you for playing. goodbye!\r\n");
  271. //free(curr);
  272. if(close(fd) != 0)
  273. perror("close");
  274. else
  275. fprintf(stderr, "%s is being removed...\n", curr->name);
  276. free(curr);
  277. return;
  278. }
  279. else{
  280. client_list = curr->next;
  281. sendclient(curr, "thank you for playing. goodbye!\r\n");
  282. free(curr);
  283. if(close(fd) != 0)
  284. perror("close");
  285. return;
  286. }
  287. }
  288. Client * temp = client_list;
  289. while(curr){
  290. if(curr->fd == fd && curr->next){
  291. temp->next = curr->next;
  292. break;
  293. }
  294. else if(curr->fd == fd){
  295. temp->next = NULL;
  296. // curr = curr->next;
  297. break;
  298. }
  299. temp = curr;
  300. curr = curr->next;
  301. }
  302. sendclient(curr, "thank you for playing. goodbye!\r\n");
  303. free(curr);
  304. if(close(fd) != 0)
  305. perror("close");
  306. /*else
  307. fprintf(stderr, "%s has been removed...\n", ->name);
  308. *struct client **p;
  309. for(p = &client_list; *p && (*p)->fd != fd; p = &(*p)->next);
  310. if(*p){
  311. struct client *t = (*p)->next;
  312. fprintf(stderr, "%s is being removed...\n", (*p)->name);
  313. fflush(stdout);
  314. free(*p);
  315. if(close(fd) != 0){
  316. perror("closing fd");
  317. exit(1);
  318. }
  319. *p = t;
  320. }else{
  321. fprintf(stderr, "Attempting to remove fd %d\n", fd);
  322. fflush(stderr);
  323. }*/
  324. }
  325. void receiveclient(struct client *p) {
  326. char *after = p->buf + p->inbuf;
  327. int room = BUFFER_SIZE - p->inbuf;
  328. int nbytes;
  329. if ((nbytes = read(p->fd, after, room)) > 0) {
  330. p->inbuf += nbytes;
  331. int where = find_network_newline(p->buf, p->inbuf);
  332. if (where >= 0) {
  333. p->buf[where] = '\0';
  334. p->buf[where+1] = '\0';
  335. interpret_message(p);
  336. where+=2; // skip over \r\n
  337. p->inbuf -= where;
  338. memmove(p->buf, p->buf + where, p->inbuf);
  339. }
  340. room = sizeof(p->buf) - p->inbuf;
  341. after = p->buf + p->inbuf;
  342. } else {
  343. remove_client(p->fd);
  344. }
  345. }
  346. /*
  347. * Acts according to the client state
  348. */
  349. void interpret_message(Client *p) {
  350. char *buf;
  351. if (p->state == NAME) {
  352. strcpy(p->name, p->buf);
  353. switch (create_player(p->name, &player_list)) {
  354. case 1:
  355. sendclient(p, "Welcome back.\r\n");
  356. break;
  357. case 2:
  358. asprintf(&buf, "Username too long, truncated to %d chars.\r\n", (MAX_NAME-1));
  359. sendclient(p, buf);
  360. break;
  361. case 0:
  362. sendclient(p, "Welcome, new player\r\n");
  363. break;
  364. }
  365. printf("Added %s to the client list\n",p->name);
  366. p->state = COMMAND;
  367. sendclient(p, "Go ahead and enter player commands>\r\n");
  368. } else if (!strcmp(p->buf, "q")) {
  369. remove_client(p->fd);
  370. } else {
  371. parse_line(p);
  372. }
  373. }
  374. int parse_line(Client *p) {
  375. char * input = p->buf;
  376. // cmd_argv will held arguments to individual commands passed to sub-procedure
  377. char *cmd_argv[INPUT_ARG_MAX_NUM];
  378. int cmd_argc;
  379. // tokenize arguments
  380. char *next_token = strtok(input, DELIM);
  381. cmd_argc = 0;
  382. while (next_token != NULL) {
  383. cmd_argv[cmd_argc] = next_token;
  384. cmd_argc++;
  385. next_token = strtok(NULL, DELIM);
  386. }
  387. return (cmd_argc > 0 && do_command(p, cmd_argc, cmd_argv));
  388. }
  389. void bubbleSort(){ //for top 3 list
  390. Player * temp1;
  391. Player * temp2;
  392. char name[10];
  393. int ms, ts, tg;
  394. if(!player_list)
  395. return;
  396. if(!player_list->next){
  397. //printf("only one usuer\n");
  398. return;
  399. }
  400. for(temp1 = player_list; temp1->next != NULL; temp1 =temp1->next) //iterates through players, swaps so higher scores "bubble"
  401. for(temp2 = temp1->next; temp2 != NULL; temp2 = temp2->next)
  402. if(temp1->max_score < temp2->max_score){
  403. //swap name
  404. strncpy(name, temp1->name, MAX_NAME);
  405. strncpy(temp1->name, temp2->name, MAX_NAME);
  406. strncpy(temp2->name, name, MAX_NAME);
  407. // printf("successfully swapped names\n");
  408. //swap max score
  409. ms = temp1->max_score;
  410. temp1->max_score = temp2->max_score;
  411. temp2->max_score = ms;
  412. //swap total games
  413. tg = temp1->total_games;
  414. temp1->total_games = temp2->total_games;
  415. temp2->total_games = tg;
  416. //swap total score
  417. ts = temp1->total_score;
  418. temp1->total_score = temp2->total_score;
  419. temp2->total_score = ts;
  420. }
  421. // printf("bubble sort done\n");
  422. }
  423. /*
  424. * Process player commands
  425. * Return: -1 for quit command
  426. * 0 otherwise
  427. */
  428. int do_command(struct client * p, int cmd_argc, char **cmd_argv) {
  429. if (cmd_argc <= 0) {
  430. return 0;
  431. } else if (strcmp(cmd_argv[0], "q") == 0 && cmd_argc == 1) {
  432. return -1;
  433. } else if (strcmp(cmd_argv[0], "all_players") == 0 && cmd_argc == 1) {
  434. //TODO produce list of all players and their stats in nice text format and sendclient
  435. Player * curr = player_list;
  436. while(curr){
  437. char str[BUFFER_SIZE - 10];
  438. sprintf(str, "%s \t \t total score: %d max score: %d\r\n", curr->name, curr->total_score, curr->max_score);
  439. sendclient(p, str);
  440. curr = curr->next;
  441. }
  442. } else if (strcmp(cmd_argv[0], "top_3") == 0 && cmd_argc == 1) {
  443. //TODO produce list of top 3 players with their total score and sentclient as a text
  444. bubbleSort(); //implements sort method above
  445. printf("sort success\n");
  446. Player * curr = player_list;
  447. int index = 0;
  448. while(curr && index < 3){
  449. char str[BUFFER_SIZE - 10];
  450. sprintf(str, "%s \t \t total score: %d\r\n", curr->name, curr->total_score); //prints top players
  451. sendclient(p, str);
  452. curr = curr->next;
  453. index++;
  454. }
  455. } else if (strcmp(cmd_argv[0], "add_score") == 0 && cmd_argc == 2) {
  456. char str [BUFFER_SIZE - 10];
  457. int score =atoi(cmd_argv[1]);
  458. Player *player = find_player(p->name, player_list);
  459. player->total_score+=score;
  460. if (score > player->max_score)
  461. player->max_score = score;
  462. sprintf (str, "added score %d for player %s\r\n", score, p->name);
  463. sendclient(p, str);
  464. } else if (strcmp(cmd_argv[0], "new_game") == 0 && cmd_argc == 1) {
  465. //TODO -- transmit current board to be presented as a 2D array of chars
  466. sendclient(p, "\r\n");
  467. for (int i = 0; i < 4; i++) {
  468. for (int j = 0; j < 4; j++) {
  469. char str[3];
  470. sprintf(str, "%c ", board[i][j]);
  471. sendclient(p, str);
  472. }
  473. sendclient(p, "\r\n");
  474. Player* curr = find_player(p->name, player_list);
  475. curr->total_games = curr->total_games + 1;
  476. }
  477. }else {
  478. char * word = cmd_argv[0]; //word and dictionary checker
  479. capitalize(word);
  480. if(isaword(word)){
  481. if(isInDictionary(word)){
  482. Player *player = find_player(p->name, player_list);
  483. char str [BUFFER_SIZE - 10];
  484. capitalize(word);
  485. int score = wordval(word);
  486. player->total_score+=score;
  487. if (score > player->max_score)
  488. player->max_score = score;
  489. sprintf (str, "added score %d for player %s\r\n", score, p->name);
  490. sendclient(p, str);
  491. }
  492. else
  493. sendclient(p, "Word is not in dictionary");
  494. }
  495. else{
  496. sendclient(p, "Word is not in board\r\n");
  497. }
  498. // sendclient(p, "Invalid syntax\r\n");
  499. }
  500. //sendclient(p, "thank you for playing. goodbye!\n");
  501. return 0;
  502. }
  503. void sendclient(struct client *p, char *msg) {
  504. write(p->fd, msg, strlen(msg));
  505. }
  506. /*
  507. * Search the first inbuf characters of buf for a network newline.
  508. * Return the location of the '\r' if the network newline is found, or -1 otherwise.
  509. */
  510. int find_network_newline(char *buf, int inbuf) {
  511. int i;
  512. for (i = 0; i < inbuf - 1; i++)
  513. if ((buf[i] == '\r') && (buf[i + 1] == '\n'))
  514. return i;
  515. return -1;
  516. }