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