evexwening
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # 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).

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully