<http://lib.cnfolio.com/Mastermind>
Introduction to Algorithms and Programming

Coursework Project – Mastermind Game



During the academic year 2007/8, students were assigned the task of developing a client to play the Mastermind game. The game was written in C and operated on a client server basis with each player playing (making guesses) head to head with the server (setting the color puzzles) over a TCP/IP network.

Students were provided with the file client.c at the start of the project to have networking functionalities so the client can communicate with the server to send guesses. The project required implementation of the puzzle guessing logic. More explanation of the game is available at Wikipedia.


client.c

  1. /*
  2. * client.c : Common Project Assignment functions for Mastermind game.
  3. *
  4. * University of Portsmouth, UK
  5. * Introduction to Algorithms and Programming
  6. * Lecturer: C Nguyen
  7. *
  8. * Updated 14 Mar 2008
  9. *
  10. */
  11.  
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <unistd.h>
  16. #include <netdb.h>
  17. #include <netinet/in.h>
  18. #include <sys/socket.h>
  19. #include <sys/types.h>
  20.  
  21. /* Name of player must be equal to or less than 50 characters in length */
  22. #define MAX_NAME_LENGTH 50
  23.  
  24. /* Integer values of colors when sending a code guess to the server */
  25. #define COLOR_EMPTY  0
  26. #define COLOR_RED    1
  27. #define COLOR_BLUE   2
  28. #define COLOR_YELLOW 3
  29. #define COLOR_GREEN  4
  30. #define COLOR_WHITE  5
  31. #define COLOR_ORANGE 6
  32.  
  33. /* Possible return values from the send_code function */
  34. #define SEND_STATUS_SUCCESS             0
  35. #define SEND_STATUS_ERROR_NULL_USER     1
  36. #define SEND_STATUS_ERROR_NULL_REQUEST  2
  37. #define SEND_STATUS_ERROR_NULL_RESPONSE 3
  38. #define SEND_STATUS_ERROR_LONG_USER     4
  39. #define SEND_STATUS_ERROR_HOST_DNS      5
  40. #define SEND_STATUS_ERROR_SOCKET_OPEN   6
  41. #define SEND_STATUS_ERROR_NO_SERVER     7
  42. #define SEND_STATUS_ERROR_SEND          8
  43. #define SEND_STATUS_ERROR_RECEIVE       9
  44.  
  45. /* Server information */
  46. #define GAME_SERVER_HOST     "cnfolio.com"
  47. #define GAME_SERVER_PORT     80
  48. #define GAME_SERVER_COMMAND  "GET /Mastermind?A=%d&B=%d&C=%d&D=%d&E=%s HTTP/1.0\r\nHost: %s\r\n\r\n"
  49. #define GAME_SERVER_API      ":API:"
  50.  
  51. /*
  52.  
  53. user     :   Array of characters that contain the name of the player.
  54.               Must contain only alphanumeric characters.
  55.               Must be 50 or less characters in length.
  56. request  :   Array of 4 integers that contain the colors of the guess code.
  57.               The first array element is the leftmost peg of the row.
  58. response :   Array of 4 integers for storing the response from the server.
  59.               The first array element is the leftmost peg of the row.
  60. session  :   Address of an integer variable to toggle between 1 and 0 when a new game starts.
  61.  
  62. The function returns an integer value that indicates success or type of error.
  63.  
  64. */
  65. int send_code( char* user, int* request, int* response, int* session )
  66. {
  67.   int sock_fail = -1;
  68.   int cmd_success = sock_fail + 1;
  69.   int cmd_fail = cmd_success + 1;
  70.   char cmd[ 512 ] = { '\0' };
  71.   int cmdsize = 512;
  72.   char buffer[ 768 ] = { '\0' };
  73.   int bufsize = 767;
  74.   struct hostent *server_info = NULL;
  75.   struct sockaddr_in server_addr;
  76.   int sock_id, sock_stat, counter;
  77.   char *api_data = NULL;
  78.  
  79.   /* Reject NULL parameters */
  80.   if ( user == NULL ) return cmd_fail;
  81.   if ( request == NULL ) return ( cmd_fail + 1 );
  82.   if ( response == NULL ) return ( cmd_fail + 2 );
  83.  
  84.   /* Reject user names longer than 50 in length */
  85.   if ( strlen( user ) > MAX_NAME_LENGTH ) return ( cmd_fail + 3 );
  86.  
  87.   /* Replace non alphanumeric characters in user name */
  88.   for ( counter = 0; counter < strlen( user ); counter++ )
  89.     if ( ! isalnum( user[ counter ] ) ) user[ counter ] = '_';
  90.  
  91.   /* DNS resolution of site name */
  92.   server_info = gethostbyname( GAME_SERVER_HOST );
  93.   if ( server_info == NULL ) return ( cmd_fail + 4 );
  94.  
  95.   /* Open network socket */
  96.   sock_id = socket( AF_INET, SOCK_STREAM, 0 );
  97.   if ( sock_id == sock_fail ) return ( cmd_fail + 5 );
  98.  
  99.   /* Open connection to remote host */
  100.   memset( &server_addr, 0, sizeof( server_addr ) );
  101.   server_addr.sin_family = AF_INET;
  102.   server_addr.sin_port = htons( GAME_SERVER_PORT );
  103.   server_addr.sin_addr = *(struct in_addr *) server_info->h_addr;
  104.   sock_stat = connect( sock_id, (void *) &server_addr, sizeof( server_addr ) );
  105.   if ( sock_stat == sock_fail )
  106.   {
  107.     close( sock_id );
  108.     return ( cmd_fail + 6 );
  109.   }
  110.  
  111.   /* Send request to remote host */
  112.   snprintf( cmd, cmdsize, GAME_SERVER_COMMAND, request[0], request[1], request[2], request[3], user, GAME_SERVER_HOST );
  113.   sock_stat = send( sock_id, (void*) cmd, strlen( cmd ), 0 );
  114.   if ( sock_stat == sock_fail )
  115.   {
  116.     close( sock_id );
  117.     return ( cmd_fail + 7 );
  118.   }
  119.  
  120.   /* Initialize response to zero */
  121.   response[ 0 ] = response[ 1 ] = response[ 2 ] = response[ 3 ] = 0;
  122.  
  123.   /* Wait for response from remote host and save data to buffer */
  124.   while ( ( sock_stat != sock_fail ) && ( sock_stat != 0 ) )
  125.   {
  126.     sock_stat = recv( sock_id, (void*) buffer, bufsize, 0 );
  127.     buffer[ sock_stat ] = '\0';
  128.  
  129.     /* Extract response from buffer */
  130.     api_data = strstr( buffer, ":API:" );
  131.     if ( api_data != NULL )
  132.     {
  133.       if ( strlen( api_data ) >= 9 )
  134.       {
  135.         for ( counter = 0; counter < 4; counter++ )
  136.         {
  137.           sprintf( cmd, "%c", api_data[ counter + 5 ] );
  138.           response[ counter ] = atoi( cmd );
  139.         }
  140.  
  141.         /* Game session toggle is last */
  142.         if ( session != NULL )
  143.         {
  144.           sprintf( cmd, "%c", api_data[ counter + 5 ] );
  145.           *session = atoi( cmd );
  146.         }
  147.  
  148.         /* Success */
  149.         close( sock_id );
  150.         return cmd_success;
  151.       }
  152.       else
  153.         break;
  154.     }
  155.   }
  156.  
  157.   /* Could not find API response */
  158.   close( sock_id );
  159.   return ( cmd_fail + 8 );
  160. }