game_server.c 14 KB

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