# 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`