# CS50 Nuggets
## Design Spec
### Team XVI, Spring 2024
According to the [Requirements Spec](REQUIREMENTS.md), the Nuggets game requires two standalone programs: a client and a server.
Our design also includes map and visability modules.
We describe each program and module separately.
We do not describe the `support` library nor the modules that enable features that go beyond the spec.
We avoid repeating information that is provided in the requirements spec.
Division of labor:
Michael: Client-server interaction
Zach: Client
Dylan: Map
Will: Visibility
## Client
The *client* acts in one of two modes:
1. *spectator*, the passive spectator mode described in the requirements spec.
2. *player*, the interactive game-playing mode described in the requirements spec.
### User interface
See the requirements spec for both the command-line and interactive UI.
The client will recieve their variation of a map in a string.
They process only messages recieved to the server, and do no calculations on their own.
Each player shall have their own map module, which stores visibility of both the rooms, and gold/players.
```
one player might receive a map string that shows such:
+----------+
|....@...*.|
|..*.......###############
|.....*....|
+---------#+
#
# +-----------+
####...........#####
|...........|
+-----------+
while another player might receive such:
+---------+
############.........|
+-----#---+
#
#
# +-----------+ #
####....*......##############
|.*......@..|
+-----------+
```
The game can be joined through usage roughly as such:
```
$ ./client hostname port [playername]
```
specifying the program, the game, and the port.
### Inputs and outputs
The client recieves a single string containing their variation of the map. Its job is to parse the string and output to `stdout`. We output solely `keystrokes`, which must read instantaneously to the server. The client shall not display any visuals that have not been sent from the server.
### Functional decomposition into modules
We expect 4 primary functions in a server feedback loop:
* _validating arguments_
* confirm user parameters are valid
* _initializing client_
* check if server address is valid
* send initial play or spectate messages to server
* _handle input_
* send a message `KEY k` to server
* _handle message_
* a function which parses the message string recieved from server
* utilize a suitable visualization library to refresh and display information
### Pseudo code for logic/algorithmic flow
validate user parameters
initialize a client-server connection
distinguish between player and spectator
try and communicate with server
recieve an initial level of visibility from server
get the resolution of the window to display the map
hold until proper resolution is met
continually check for keystrokes
synchronous
continually recieve strings from server
synchronous
display to stdout
free and cleanup
### Major data structures
The client may benefit from a data structure to hold information of the _user_. Values such as `player name`, `gold status`, `representative letter`, etc. will be stored in the struct and passed between handling input and message. The client also recieves a string of characters derived from a data structure of a _2D_ `array`. More information on cells in map module.
### Testing Plan
The client will largely handle the most preliminary edge cases, and the highest level "almost complete" testing. Ensuring users input the right seed, cannot join if there are too many players, etc. should all be tested first.
When the game is nearing a finished state, fuzz testing of random players with random inputs, joining and leaving mid game, etc. should all be tested last.
---
## Server (Michael)
### User interface
See the requirements spec for the command-line interface.
There is no interaction with the user.
### Inputs and outputs
Inputs and outputs are handled through messages sent through a message module, which handles networking.
Optional logs can be written to `stdout` or a file.
### Functional decomposition into modules
We isolate map logic into the map module.
The server asks the map module to do map things
like trying to move players and building
map strings for specific players.
The server knows which players are associated with
which addresses; the map module doesn't know anything about addresses.
### Pseudo code for logic/algorithmic flow
The server will run as follows:
execute from a command line per the requirement spec
parse the command line, validate parameters
call initializeGame() to set up data structures
initialize the 'message' module
print the port number on which we wait
call message_loop(), to await clients
call gameOver() to inform all clients the game has ended
clean up
`initializeGame`: set up the map
`message_loop`: relies on `messageHandler`
`messageHandler`: parses and validates the recieved message and calls the function corresponding to the message.
- if the command is KEY, it will validate the key as a move command or quit and call the correct function. It will not allow a server to call move.
- the individual functions called by messageHandler will decide what message to send back to the clients
### Major data structures
- Map, provided by map module
### Testing
We will use the sample client provided from CS50 instruction team to test the message handling.
---
## Map Module (Dylan)
This module will contain a map data structure manipulated by the server. The map is a 2D array of gridpoints, which are themselves a data structure that contains relevant information.
### Functional decomposition
`map_load` - initializes a map struct and loads in map data from map input
`map_distrbute_gold` - distributes gold across the map randomly
`map_add_player` - adds player to the map
`map_move` - attempts to move a player
`map_get_location` - returns the gridpoint at a certain location
`map_update_visibility` - updates the seen of gridpoints in the map
### Pseudo code for logic/algorithmic flow
Psuedocode for `map_load`
array
open file
for i, line in file
for j, char in line
array[i][j] = new gridpoint with char
Pseudocode for `map_distribute_gold`
gridpoint
gridpoint is floor
if(random = true)
add gold to point
Pseudocode of `map_update_visibility`
for point in visibility:
map[point.y][point.x]->seen.add(player)
### Major data structures
To store location information, we expect a new `gridpoint` data structure, which holds the initial map character, as provided, the player in the location, if any, the gold amount, if any, and players that have seen the gridpoint.
We also expext a new `map` data structure to store the global state of the game. This includes the static environment, such as the walls and tunnels, and also dynamic objects, such as players and gold. The map will allow for the movement of players, the collection of gold, and the getting of all map information.
The map information is stored in a 2 dimensional array of gridpoints, with coordinates in the array corresponding gridpoint, sized according to the dimensions of the inputted map. Player locations and gold locations and sizes are each stored in their own array
### Testing
The map module can be tested by loading a variety of maps.
For each map, the following should be tested for multiple random seeds:
* Loading gold
* Loading in players
* Moving players around
* Managing visibility to each player at each location
* Getting the location
By putting in specific inputs (such as loading two players next to each other and testing collision case), we can adequately test many cases. Additionally, using random seeds to find edge cases will allow us to identify edge cases.
---
## Visibility Module (Will)
This module will preform the necessary logic and calculations to determine the extent of the map that is visible to a user. It will recieve a map data structure containing gridpoints from the server, and for each
### Functional decomposition
We expect two primary functions:
*getVisibility*, which calculates which gridpoints should be visible to a particular player.
*clearVisibility*, which resets the gridpoints that are visible while retaining those that have been seen.
### Pseudo code for logic/algorithmic flow
#### getVisibility
pseudocode:
mark player's location as visible and seen
iterate through each gridpt in the map
get the horizontal distance from player to gridpt
get the vertical distance from player to gridpt
get the slope (dy/dx)
iterate through each row between player and gridpt
calculate the column (with decimals) from row
if the this row is a gridpt (column is an integer)
if the gridpt is a room, does not block visibility
mark as visible and keep moving
otherwise, it is a wall or tunnel
mark as visible, but move to next tile
otherwise, round down column and check both col and col +1
if one or both are room spaces, not blocking visibility
mark as visible and keep moving
otherwise, this is a wall and is blocking visibility
mark as visible, but move to next tile
iterate through each column between player and gridpt
calculate the row (with decimals) from column
if the this column is a gridpt (row is an integer)
if the gridpt is a room, does not block visibility
mark as visible and keep moving
otherwise, it is a wall or tunnel
mark as visible, but stop checking along this line
otherwise, round down row and check both row and row +1
if one or both are room spaces, not blocking visibility
mark as visible and keep moving
otherwise, this is a wall and is blocking visibility
mark as visible, but move to next tile
if we made it to here, then the gridpoint is visible!
### clearVisibility
for each gridpoint in the map:
if a gridpoint was visible, mark it as seen
mark visibility as false
### Major data structures
We expect to employ a Gridpoint data structure, defined above, that contains the contents of a particular gridpoint in the map. This will contain the type of gridpoint, and will also document whether a point is visible and if it has already been seen.
We expect to map gridpoint visibility to each player via an array. Setting visibility to true or false will therefore involve getting the index corresponding to the player.
### Testing
We intend to test this module with a script that builds a small room and places a single player at predefined location. We will calculate the visibility and print the resulting map. We will step the player in one direction and recalculate the visibility. We will print the new visibility. Then we will print the tiles that have been seen.
---
## System Testing
We will use the shell script created by the
CS50 instruction team to test the system with random inputs.
We will also stress test by trying to have too many clients, reaching max number, killing clients and trying to rejoin.