---
# System prepended metadata

title: NUGGETS SERVER IMPLEMENTATION

---

# NUGGETS SERVER IMPLEMENTATION 
## SERVER IMPLEMENTATION SPEC

In this document we reference the [Requirements Specification](REQUIREMENTS.md) and [Design Specification](DESIGN.md) and focus on the implementation-specific decisions.

The spec will contain the following conditions:

-  Data structures
-  Control flow: pseudo code for overall flow, and for each of the functions
-  Detailed function prototypes and their parameters
-  Error handling and recovery
-  Testing plan

### Data Structures
- Grid
    - char map[][]
    - int nc
    - int nr
- Game
    - grid_t* full
    - int remainingGold
    - int remainingGoldPiles
    - int numPlayers
    - set of players
    - bool currSpectator
- Player
    - int purse
    - grid_t* visible
    - int currentx
    - int currenty
    - bool active
    - char oldSpot
    
### Control flow
The server is implemented in one file ```server.c```, with the following functions:

#### main
The main function simply calls other modules, initializes the port (to listen to client input) and other functions. Pseudo code:
```
calls parseArgs
call game_grid with grid associated with the inputted file with random number of gold and random number of gold piles
initialize addr_t data structure
call log_init on stderr
call message_init on stderr and intialize it to ourPort
if failure to initialize port, return non-zero
initialize set of players (key = id(alphabet), item = name)
initialize a set of clients (struct of addr_t; key = same id as the players set, item = client address)
initialize the spectator client
call update_grid
call update_players
call message_done
```

#### parseArgs
Given arguments from the command line, extract them into function parameters; return only if successful.
- for ```map text file```, check if the file is readable 
- if optional parameter ```seed``` provided then call ```srand``` on the seed
- if optional parameter ```seed``` not provided then call ```srand(getpid())```
- if any trouble is found, print an error to stderr and exit non-zero.


#### update_grid

Updates the grid according to the information received from the clients and monitors if all gold nuggets have been acquired. Pseudo code:

```
call message_loop with NULL handleTimer and NULL handleInput and handleMessage
call set_iterate() to iterate over every client in the clients set
call message_send on spectator client (DISPLAY\n string (game_grid))
```

#### update_players

Updates the players according to the information received from the clients. Pseudo code:
```
call message_loop with actionMessage and NULL handleInput and NULL handleTimer
call set_iterate() to iterate over every client in the clients set
call message_send on spectator client (DISPLAY\n string (game_grid))
```

#### helper functions:
- ```handleMessage```
Used in message_loop called by ```update_players``` and ```update_grid```. Pseudo code:
``` 
if client is NULL
    log this error
    return true
if there is still gold left to be collected
    initialize client to 'from' (the second parameter of the function)
    call parseMessage
    if first word of message is PLAY
        add the client to the set of clients
        if game already has maximum number of players 
            call message_send on current client (QUIT Game is full, no more players can join)
        else if no name provided
            call message_send on current client (QUIT Sorry - you must provide player's name)
        else 
            add the name and the next alphabet to the set of players (id starting at 'A')
            call message_send on current client (OK (alphabet associated with the name in the set of players))
            if new player
                call game_newPlayer on the alphabet (id)
            call message_send on current client (GRID nrows(grid_nr) ncols(grid_nc))
            call message_send on current client (GOLD n(game_playerPurse) p(game_playerPurse) r(game_gold))
    else if first word of message is SPECTATE
        if there is a spectator already
            call message_send on current spectator (QUIT You have been replaced by a new spectator)
        initialize spectator to new client
        call message_send on current client (GRID nrows(grid_nr) ncols(grid_nc))
        call message_send on current client (GOLD n(0) p(0) r(game_gold))
    else 
        call message_send on current client (ERROR explanation)
    return false
else if all gold nuggets collected
    call set_iterate on the clients set using quitfunc as helper method
    call message_send on spectator client(QUIT Game Over: tabular data)
```

- ```actionMessage```

```
if client is NULL
    log this error
    return true
initialize client to from
call parseMessage
if first word is KEY
    if client is not spectator
        call game_update() on the game with the second word of the message
    else if client is spectator
        if second word is 'Q'
            call message_send on spectator client (QUIT Thanks for watching)
        else
            call message_send on spectator client (ERROR explanation)
else
    call message_send on client (ERROR Explanation)
return true
```

- ```itemfunc```

helper function for set_iterate used in update_grid and update_players. Pseudo code:
```
if key exists and item exists
    get the player from the players set using the key
    call message_send on the client (DISPLAY\n game_playerGrid())
```

- ```parseMessage```

helper function used in handleMessage and actionMessage. Pseudo code:
```
read the string message
when encountered first space, replace it with a null character
add both words to another array of strings
take the second word and if for a char in this string isgraph and isblank are both false, replace it with underscore
truncate this word to MaxNumLength characters and add it to the original array of strings
```
- ```quitfunc```

helper function called in handleMessage
``` 
for every key in client
    call message_send on each client (QUIT Game Over: tabular data)
```    

### Other modules
#### libcs50
We leverage the `set.c` module from libcs50. See that directory for module interfaces. 

#### support
We will leverage the support module for `message.c` to handle all the message compilation and distribution processes of the information coming to and from the client among Internet hosts. Messages are limited to UDP packet size, may be lost, and may be reordered, but require no connection setup or teardown. We will also use `log.c` to handle logging messages to a file and `file.c` to support reading input from a word, line, or entire file.

#### Grid
The grid data structure will primarily be a 2D array of characters. The grid module will implement the following functions:

- grid_new
    
        create a new grid struct 'grid' 
        count number of lines: this is grid->nr
        create a char** map and malloc nr x sizeof(char*)
        use file_readLine to store first line as a char*
        find length of that line: this is grid->nc
        for each row in NR, malloc nc x sizeof(char)
        Loop over every element of the inputted file
            Copy said element into the 2D array of characters
        set the map to grid.map
        return  grid or NULL for memory allocation errors
        
- grid_empty
        
        malloc a grid_t instance
        malloc a 2D array of charaters of size NR times length of char*
        for each row: 
            malloc space for a nc chars
        for each gridpoint add an empty character ' '
        return the grid struct with the char array or NULL if there were any memory allocation errors

- grid_get
    
        return the character at the given x and y coordinates in the 2D char array of mentioned grid_t struct
        
- grid_set
    
        set the grid value at given x and y coordinates in the 2D char arry to the given char

- grid_isVisible

        given a full grid, and 2 points (i.e 2 pairs of x and y values - (currx, curry) and (otherx, othery))
        Calculate the line properties - slope and intercept, using the 2 points
        Go over evry viable point in the line between the 2 points:
            If the point is not a '.' or '*' or '@' or between 'A' - 'Z':
                return False
        Return true
        
- grid_visible
        
        Iterate through all the points in the older visible grid
            If the value of the point is '@':
                set the point to player's oldSpot
            Else If the point has value '*':
                Set the value in the new grid to a '.'
            If the point is the current location:
                set the grid value to '@'
            If the point is visible from the current location (using grid_isVisible)
                Set the point to its real value

- grid_nc

        return the number of column

- grid_nr

        return the number of rows of 2D char array

- grid_valid
        
        get the character using grid_get
        if the character is a '.' a '*' or a '#':
            return true
        return false
        
- grid_getString
    
        Allocate memory for a string of size nr*nc+1 chars
        Go over every line in the 2D array:
            Go over every character in the line:
                Calculate the proper index in the string 
                Add the character to the string
            Add a '\n'
        return the char array
    

#### Game
The game data structure will contain details about the game like its grid, the total gold, the number of players currently playing the game, a set of players, and a boolean indicating if the game has a spectator or not. The game module will implement the following functions:

- game_new 

        Allocate memory for a new game_t
        Set the full grid struct to the result of calling grid_new on inputted file pointer
        Set the remaining gold equal to the inputted total gold
        Set remaining gold piles equal to inputted total gold piles
        For each gold pile:
            Get a random x between 0 and grid_nc()
            Get a random y between 0 and grid_nr()
            while (randx, randy) != '.':
                Get a random x between 0 and nc
                Get a random y between 0 and nr 
            Set the point in the grid to a '*'           
        set numPlayers to 0
        set currSpectator to false
        Intitialize a new set using set_new() in order to store the players
        

        
- game_grid 
    
        If the grid associated with inputted game_t* is not NULL
            Get the grid in string form by using grid_getString
            Return the string associated with inputted game_t* struct
        else
            Return NULL
- game_update
    
        Get a pointer to the player_t struct using the playerKey from set of players
        Get the current x and y values for player
        If the action is 'u' (up):
            Decrease the y value of the player by 1
        Else If the action is 'd' (down):
            Increase the y value of the player by 1
        Else If the action is 'l' (left):
            Decrease the x value of the player by 1
        Else If the action is 'r' (right):
            Increase the x value of the player by 1
        If the new position (with updated x, y) is valid 
            Keep track of the player's old x and y values
            set the new position of the player using player_setPoints
            If the new position already has a player on it
                Get that player's playerKey (the character on the grid at said point)
                Use player_setPoints to change that player's points to the old points of current player
                Update the grid to account for the new position of this player
            else if the new position has gold:
                Calculate the random gold value at that point
                Subtract the gold value at point from total gold in the game and add it to the player's purse (player_updatePurse)
                Decrement remainingGoldPiles
            get the visible grid of the player
            get the old spot value of the player
            Update the visible grid of the player to account for the new changes by passing it to grid_visible
            set the old spot of the player to the value of the grid at the new location of player
            Update the grid to account for the new position of player
                
        
- game_newPlayer

        set randx to random number inbetween 0 and NC
        set randy to random number inbetween 0 and NR
        while grid_get(randx, randy) != '.':
            set randx to random number inbetween 0 and NC
            set randy to random number inbetween 0 and NR
        call player_new(NC, NR, randx, randy, full) to create a player struct 
        add that player_t* to the set of player_t* with provided char playerKey as key
        increment numPlayers
        use grid_set to add the player to the game's grid
        return
        
 - game_playerPurse
     
         Get the pointer to the player struct associated with given playerKey
         return the purse of said player struct by calling player_purse
         
- game_gold
    
        Returns the gold remaining in game (that is not part of players' individual purses)
        
- game_randomGold

        if remaining gold piles == 1
            return remaining gold
        else 
            int proportional = (remaining gold)/(remaining gold piles)
            return proportional + random number in between -proportional/3 and proportional/3

- game_spectator
    
        Return the bool currSpectator
    
- game_numPlayers 

        Return the int numPlayers
        
- game_removePlayer 

        use set_find to get the player_t* for given key
        call player_quit to remove player
        decrement numPlayers
        
- game_nc

        return the nc from grid
         
- game_nr

        return the nr from the game's grid by using grid_nr()       
         
- game_delete

        delete the game's grid using grid_delete
        delete each of the players in the set using set_delete with player_delete as a helper function
        free the game struct
        

#### Player 
The player data structure tracks an individual's game information: purse, current position, and visited locations.
The player module will implement the following functions:

- player_new

        create a new player_t* 
        set int purse to 0

        set bool active to True
        set currx to given randx
        set curry to given randy
        set the old spot value to the value in the full grid at the current position of player
        use grid_visible to create visible grid from starting point and a new grid

        return pointer to this player_t*

        
- player_purse

        return the current int purse of the inputted player struct
    
- player_addToPurse

        set the purse value of the inputted player_t struct pointer to the sum of the existing purse value and the inputted int value
            
- player_visible

        return the grid_t* which contains the points in the map which given player has ever been able to see
        
- player_setPoint

        change currx to newx
        change curry to newy
        
- player_currx

        return the current x coordinate of the player
        
- player_curry
   
        return the current y coordinate of the player

- player_getOldSpot

        return the character beneath the player's previous location
        
- player_setOldSpot

        set given char to the value of player's old spot 

- player_delete
        
        free the memory allocated for the player's visible grid using grid_delete
        free the memory allocated for given player struct

- player_quit

        set player's active indicator to false
        
### Function prototypes

#### server.c
```c
void parseArgs(const int argc, char* argv[], char** filename, int seed);
void update_grid();
void update_players();
int main(const int argc, char* argv[]);
static bool handleMessage(void* arg, const addr_t from, const char* message);
static bool actionMessage(void* arg, const addr_t from, const char* message);
static void itemfunc(void* arg, const char* key, void* item)
static char** parseMessage(const char* message);
```

#### Grid

```c
grid_t* grid_new(FILE* fp);
grid_t* grid_empty(int nc, int nr)
void grid_visible(grid_t* full, int currx, int curry, grid_t* visible, char oldSpot);
bool grid_isVisible(grid_t* full, int currx, intcurry, int otherx, int othery);
char grid_get(grid_t* grid, int x, int y);
void grid_set(grid_t* grid, int x, int y, char newChar);
int grid_nc(grid_t* grid);
int grid_nr(grid_t* grid);
bool grid_valid(grid_t* grid, int x, int y);
char* grid_getString(grid_t* grid);
void grid_delete(grid_t* grid);
```
    
#### Game
    
```c
game_t* game_new(FILE* fp, int totalGold, int numGoldPiles);
char* game_grid(game_t* game);
void game_update(game_t* game, char playerKey, char action);
void game_newPlayer(game_t* game, char playerKey);
void game_removePlayer(game_t* game, char playerKey);
int game_playerPurse(game_t* game, char playerKey);
int game_gold(game_t* game);
int game_randomGold(game_t* game);
bool game_spectator(game_t* game);
int game_numPlayers(game_t* game);
int game_nc(game_t* game);
int game_nr(game_t* game);
void game_delete(game_t* game);
```


#### Player 

```c 
player_t* player_new(int NC, int NR, int x, int y, grid_t* full);
int player_purse(player_t* player);
void player_addToPurse(player_t* player, int value);
grid_t* player_visible(player_t* player);
void player_setPoint(player_t* player, int newx, int newy);
int player_currx(player_t* player);
int player_curry(player_t* player);
char player_getOldSpot(player_t* player);
void player_setOldSpot(player_t* player, char oldSpot);
void player_delete(void* arg);
void player_quit(player_t* player);
```

### Error handling and recovery

### Testing plan
#### Unit testing
We propose to first test for the command-line with various forms of incorrect command-line arguments to ensure that the command-line parsing and validation of those parameters, works correctly. The plan will test the following arguments:

1. No arguments
2. One argument
3. Three or more arguments
4. Invalid map file
5. Invalid seed

#### Integration/system testing
We also plan to have individual testing files for each of the data structure modules in order to test our functionality on a case-by-case basis as opposed to a combined test of the different modules. We anticipate this will make it easier and more effective to spot bugs in the data structures side of our code. As such, we anticipate the following additional testing files:

1. `gridtest.c`
2. `playertest.c`
3. `gametest.c`

Also, similar to the client test, we plan to test the implementation of the message module and the server's ability to communicate with the client. This will essentially be a test of the overall functionality of the nuggets game (ie. playing the game).  
