---
# System prepended metadata

title: CS50 nuggets

---

# CS50 nuggets

## Implementation Spec

## Detailed pseudo code for each of the objects/components/functions,
 
### server.c 
#### main: 
```c
parseArgs()
if (port != 0) {
    message_loop(NULL, 0, NULL, handleInput, handleMessage);
  }
 exit(0)
```
#### parseArgs:
```c
check correct arguements
    exit if wrong
open map file
    exit if file can not be opened
close file
if seed is provided 
    set seed variable
    if seed is invalid or positibe, exit 
else
    set seed to -1(will be set later)

```
#### Initialize game:
Intializes game struct and variables inside. Then intializes map and places gold in the map. 
```c
game_t game = mem_malloc(sizeof(game_t))
call intializeMap(map textName)
    inside intializeMap(): 
        calculate a random amount of gold piles between Max and Min
        create grid_t* map and load map in from txtfile using grid_loadgrid(maptext);
        set game->NR = grid_getNR(map)
        set game->NC = grid_getNR(map)
        set game->game = map 
        set game->spectator = NULL
        allocate memory for game->playersArray 
        if memory allocation fails
            return false
call game_placegold(int number of game piles)
    inside game_placegold():
        set int disperse to random number between 1 and 7 which will be how far apart we disperse
        for(int i = disperse;  i + disperse < indices && piles > 0; i += disperse)
            if(map[i])=='.'
                map[i] = '*';       // set it equal to a gold piece
                subtract from number of piles 
            
```
#### handleMessages:
handles incoming messages from clients, changes the game accordingly, and broadcasts the changes to all connected clients
```c
if(single char input){
    call handleSingleChar():
        if(char=='h') move left if possible
        else if(char=='H') sprint left if possible
        else if(char=='l') move left if possible
        else if(char=='L') sprint right if possible
        else if(char=='j') move down if possible
        else if(char=='J') sprint down if possible
        else if(char=='k') move up if possible
        else if(char=='K') sprint up if possible
        else if(char=='y') move diagonal up left if possible
        else if(char=='Y') sprint diagonal up left if possible
        else if(char=='u') move diagonal up right if possible
        else if(char=='U') sprint diagonal up right if possible
        else if(char=='b') move diagonal down left if possible
        else if(char=='B') sprint diagonal down left if possible
        else if(char=='n') move diagonal down right if possible
        else if(char=='N') sprint diagonal down right if possible
        else if(char=="Q")
            if client is spectator
                remove spectator from game struct
            else
                remove player from grid
                send quit message to client 
        else 
            send message to client message is unreadabele
        if any movement occured
            check if any gold was collected
            if gold was collected 
                update game struct
                if gold collected is game ending move
                    handle endGame()
                    return false; 
}else{
    Split first word from rest of String
        call handleFirstWord():
            if first word is "PLAY"
                if player number exceeds limit
                    send client message game is full
                else
                    create player
                    assign symbol to player
                    put player into game struct
                    send grid, gold, and display messages to client 
            else if first word is "SPECTATE"
                If game has a current spectator
				Send message to current spectator to quit
				Forgot current spectator
			    Create a new Spectator Struct for the new spectator.
            else 
                send message to client it is unreadable error message   
   
broadcast to all clients updated display. 
return true 
}
```

#### is_visible:
Calculates what will be visible for a player 
```c
bool is_visible(const double pc, const doube pr, const double c, const double r);

find the difference in y and x
calculate the slope and constant

if line is either vertical or horizontal
    set the equation of the line appropriately

loop over the columns from pc  to c (non-inclusive)
    if is grid point
        if not room spot
            return false
    else 
        check the floor and ceil
        if neither point is room spot
            return false

loop over pr to c (non-inclusive)
     if is grid point
        if not room spot
            return false
    else 
        check the floor and ceil
        if neither point is room spot
            return false

return true
```
#### endGame:
handles end of game sequence. 
```c
    broadcast to all clients quit message with gameover summary
    print GameOver summary. 
    free all allocated memory 
    return false 
```

### Player.c
#### main:
```c
parseArgs()
if set_address(hostname, port, &serverAddress) succeeds
    if playername exists 
        send "PLAY playername" message to server
    else send "Spectate" message to srver 
else set_address failed
    print error message 
message_loop(NULL, 0, NULL, handleInput, handleMessage);
free allocated memory.
```
#### parseArgs:
```c
if incorrect number of arguements
    print error message 
copy host name, playername, and port from input 

```
#### handleStdin:
```c
while(line=file_readline(stdin)!=NULL)
    send stdin string as message to server
```
#### handleMessages:
handles incoming messages from server, changing info and display accordingly. 
```c
initialize player or spectator struct from arg
create array of tokenized message words
store client's window/display coordinates

if GRID message
    if not valid message
        print error malformed message        
    while window not large enough
        inform client
        update coordinates
        
if QUIT message
    if not a valid message
        print error malformed message
    exit curses
    print quit explanation
    free allocated memory
    exit
    
if GOLD message
    if not valid message
        print error malformed message
    initialize nugsGrabbed
    initialize purseTotal
    initialize nugsRemaining
    if client is a spectator
        Print spectator display message
    if client is a player
        Print player display message
        if nugsGrabbed > 0
            Print gold update

if DISPLAY message
    print the display message to display

refresh display
free all words in messageArray
free messageArray

```
### Grid.c
#### grid_loadgrid(char* mapTextName):
loads the map file into a a char* map inside the grid_t struct.
```c
Allocate memory to grid_t* grid
if grid or MapTextName are null
    return null
Open file mapTextName
if failed to open
    return null
set number of rows to file_numLines(fptr)
set number of Cols to find_NC(textfile)
open file using mapTextName
allocate memory to string char* map
set int idx =0 to be used to traverse through map string
while(can read lines from file)
    for(int i = 0; i<number of Cols; i++)
        if i>= the length of the line
            set map[idx]=' '
        else
            set map[idx]=[i]
        idx++
set grid->NC to number of columns
set gird->NR to number of rows
set grid->map to map string 
return grid
```    
#### grid_findNC:
finds the number of columns in a map given the map file.
```c
declare int maxlen, currlen, linenum
while(can readline from file)
    if at first line
        currlen = strlen(line)
        maxlen=currlen
        change linenum tracker so you are no longer at first line
    else 
        currlen=strlen(line)
        if currlen>maxlen
            maxlen=currlen; 
close the file
return maxlen
```


## Definition of detailed APIs, interfaces, function prototypes and their parameters
### Function Prototypes
server.c: 
```c
static bool game_initializemap(char* maptext,int seedin);     
static bool game_placegold(int numpiles,int seedin);          
static bool game_calculategoldvalues(int seedin);        
static void parseArgs(const int argc, char* argv[], char** map, int* seed);
bool handleTimeout(void* arg);
bool handleInput(void* arg);
bool handleMessage(void* arg, const addr_t from, const char* message);
void broadcast(char* message);
player_t* getPlayer(player_t** playerArray, char playerSymbol);
bool move(player_t* player, int newX, int newY);
bool handlePlayerMovement(char key, player_t* player);
```
player.c:
```c
static void parseArgs(const int argc, char* argv[], char** hostname,
                      char** port, char** playername);
bool handleTimeout(void* arg);
bool handleInput(void* arg);
bool handleMessage(void* arg, const addr_t from, const char* message);
```
 
## Data structures (e.g., struct names and members)
 
### Game Struct - Server
This game structure holds a `grid_t` pointer, an array of player pointers, and the variables hold the number of gold total, the minimum number of gold piles, the maximum number of gold piles, and the other variables defined in the requirement specs. We also hold a pointer to a spectator object. This game struct is in the server file and allows us to pass around these variables as one global variable of a game struct. 
 
### Array of Player Pointers - Server
In our server file, we use an array of pointers to player objects to keep track of the players in our game. This array of player pointers is held inside of the game struct object that is the global variable in our server.c

### Player Struct - Server
We created a player structure that will hold the player’s name as a string, their address held in an `addr_t` object, their symbol character(A-Z), and the number of gold that they currently have. This player object also holds their own grid object that has that player’s version of the map based on their current visibility. This structure will only be present in the server file. 


### Spectator Struct - Server
We created a spectator structure that holds an integer  `r` which represents the amount of gold left in the game, a grid pointer that holds the most updated version of the game’s ‘all seeing map’, and `addr_t` object that holds this spectator’s address for the game to use to send messages, and two integers, one to hold number of columns and the other to hold the number of rows.  This structure is only present in the server file.


### Grid Struct - Server & Client
This data structure that we created deals with modifying the characters of the map, which is a string representation of the Map textfile passed as an argument to `server.c`. The server file is going to have the map that has all the characters at their correct locations and the current gold piles left, this grid will be held in the game structure object. Each player is going to have their own grid object too in the client file that the server can access and modify. Each spectator is going to have their own grid object holding the same map as the server in its own respective client file. Each grid object is also going to hold two integers, one for the number of columns in the map and one for the number of rows in the map. So the grid structure will appear both in the client and server files. 
## Other Modules
Detailed descriptions of each function's interface is provided as a paragraph comment prior to each function's declaration in player.h, spectator.h, and grid.h and is not repeated here.

### Player Module
```c
// getters
grid_t* player_getGrid(player_t* player);
char* player_getHostName(player_t* player);
char* player_getPort(player_t* player);
char* player_getName(player_t* player);
int player_getX(player_t* player);
int player_getY(player_t* player);
char player_getPlayerSymbol(player_t* player);
char player_getJustStepped(player_t* player);
addr_t player_getAddress(player_t* player); 

// setter
grid_t* player_setGrid(player_t* player, grid_t* grid);
char* player_setHostName(player_t* player, char* hostName);
char* player_setPort(player_t* player, char* name);
char* player_setName(player_t* player, char* name);
int player_setX(player_t* player, const int x);
int player_setY(player_t* player, const int y);
char player_setPlayerSymbol(player_t* player, char playerSymbol);
char player_setJustStepped(player_t* player, char justStepped);
```

### Spectator Module
```c
spectator_t* spectator_new(addr_t addressIn, int NC, int NR);
void spectator_delete(spectator_t* spectator);
Void spectator_setr(spectator_t* spectator, int rin);
int spectator_getr(spectator_t* spectator);
void spectator_displaygrid(spectator_t* spectator, char* mainmap);
```


### Grid Module
```c
grid_t* grid_loadgrid(char* txtfile);
int grid_getNC(grid_t* grid);
int grid_getNR(grid_t* grid);
char grid_getchar(grid_t* grid, int x, int y);
bool grid_setchar(grid_t* grid, char c, int x, int y);
void grid_display(grid_t* grid);
void grid_delete(grid_t* grid);
```
 
 
## Error Handling and Recovery
 
All the command-line parameters are rigorously checked before any data structures are allocated or work begins; problems result in a message printed to stderr and a non-zero exit status.
 
Out-of-memory errors are handled by variants of the `mem_assert` functions, which result in a message printed to stderr and a non-zero exit status. 
 
The code utilizes defensive programming practices to ensure functions are not being given bad variables.  Many functions return booleans, which allow the program to ensure a function was successful (returned true) before moving on with the game. This approach to defensive programming allows the game to continue safely and not use any bad variables, but does not trigger a fatal error that would end the game. 
 
Additionally, most variables and data structures are null checked before continuing, to ensure data was initialized correctly. 
 

 
## Testing plan

Our group first created our grid module and created a c program that 
tested to make sure that the grid loaded properly from the map textfile. This c program also made sure that our grid module calculated the number of collumns and number of rows correctly for each of the map textfiles provided in the maps directory. This test also made sure that our grid functions getchar and putchar could either put a character or get a characters at a certain x and y coordinate on the map. We then created a testing script to run though each of these map textfiles to test the functions in the grid module and print their output to testing.out file.

Our next test was testing our static functions in the server.c file that place random gold piles on room spots in the game's map. We created a c program to test this and a corresponding testing script to run through the different map textfiles and make sure that the correct amount of gold piles are being placed in the valid room spots on each map.

To test our message handling, we made sure that the messages were being sent correctly between the client in server by printing out the parsed message after we handled it. We also make sure that when we pressed a key, that our program was responded correctly by moving the player to the right spot on the map.

To test our spectator, we made sure that the spectator would receive its 
gold message correctly and that it would display the same version of the map as the map held in the server. We did this by running a basic server.c program and a player.c program that only created a spectator and had it display its map after the server.c sent its DISPLAY message.





## To-Do list / Division of Work
1. Visability function - `Zhoucai Ni`
2. ParseArgs (client & server) - `Devon Parker`
3. Message/input Handlers (client) - `Devon Parker & Victoria Shaw`
4. Message/input Handlers (server)- `Victoria Shaw` 
5. Handle Player Movement - `Devon Parker`
6. Game Struct  - `Tanner Rosa`
7. Player Struct - `Zhoucai Ni`
8. Spectator Struct - `Tanner Rosa`
9. Grid struct - `Tanner Rosa`
10. Debugging - `Everyone`
11. Mem leaks - `Victoria Shaw & Zhoucai Ni`
12. Testing/Test files - `Victoria Shaw & Zhoucai Ni`






