
This assignment introduces foundational programming concepts in C++ by teaching students how to manipulate 2D arrays, use structs as lightweight objects, and implement key game mechanics. Students will parse and load structured data from a CSV file into a 2D array using methods like string.find and string.substr, which are practical for processing real-world datasets. By programming functions for movement, resource collection, and inventory management, students will develop problem-solving skills in working with constraints such as inventory limits and object interactions.
This assignment will focus on using structs to represent objects. Focusing on structs instead of classes allows students to grasp the core principles of object-oriented design in a simpler context, reinforcing the relationship between data and behavior. These skills are directly applicable to various fields, such as game development, simulation programming, and software systems that involve managing grid-based or spatial data. After college, the ability to process external files, manipulate data structures, and implement rule-based logic will help students build efficient, scalable solutions in a variety of technical domains.
All files needed for this assignment can be downloaded here
In this assignment, the objective is to create a functional game-like simulation of the game \textbf{Old School Runescape} by reading and processing a map file, managing player actions, and implementing inventory and banking mechanics using structs and 2D arrays. The tasks focus on reading structured data, manipulating a grid-based map, and programming logical rules for player interactions within a defined set of constraints.
In order to do this you will need to:
Read the map:
Write the readMap() function to parse map.csv and populate the 2D array representing the game map.
You may only use string.find() and string.substr() to read from the .csv files. No other method will be graded.
For a video on this method see:
https://www.youtube.com/watch?v=S2pvOeWyqBc
If a tree or rock is read in, they will have a probability that you are able to chop or mine them, respectively.
If a tree is read in, set the chance attribute of the tree to 0.8 (80% chance of chopping).
If a rock is read in, set the chance attribute of the rock to 0.4 (40% chance of mining).
Implement the game mechanics:
Write the move() function to handle player movement. The player cannot go off the edges of the map and cannot move to positions other entities (trees/rocks/bankers/walls) already occupy.
Write the chop() function to allow the player to chop trees. To chop, the player must be directly next to a tree horizontally or vertically (not diagonally), and their inventory cannot be full.
Write the mine() function to allow the player to mine rocks. To mine, the player must be directly next to a rock horizontally or vertically (not diagonally), and their inventory cannot be full.
Write the bank() function to allow the player to bank items from their inventory. To bank, the player must be directly next to a banker horizontally or vertically (not diagonally), and their bank cannot be full.
Call the game mechanics from the main function in the spaces provided.
In this assignment, the map is represented as a 2D array stored in memory, where data is stored row by row. This means the first index of the array corresponds to the row (y-coordinate), and the second index corresponds to the column (x-coordinate). However, when working with coordinates in this assignment, students will receive data as x, y pairs, where:
x refers to the horizontal position (column).
y refers to the vertical position (row).
To correctly access elements in the 2D array, the order of indices must follow the array's storage format: map[y][x].
The y (row) value corresponds to the first index of the array.
The x (column) value corresponds to the second index of the array.
For example:
If a record specifies x = 5 and y = 3, the corresponding element in the array would be accessed as map[3][5].
Attempting to access the array as map[5][3] would result in incorrect behavior, as the row and column values would be swapped.
In this assignment there are 2 user defined data types:
Entity
Player
These objects are implemented as structures, encapsulating related data fields to represent map elements and player attributes.
EntityThe Entity data type represents objects on the game map, such as trees, rocks, walls, and bankers. It contains the following attributes:
type (string): Describes the type of the entity (e.g., "tree", "rock", "wall", "banker"). An empty string indicates no entity is present at that position.
chance (double): Represents the success probability for actions performed on the entity:
0.8 for chopping trees.
0.4 for mining rocks.
Default value is 1.0 unless explicitly set.
The Entity data type is instantiated to populate the 2D map array, allowing each array element to hold information about any present objects on the map. It is also used to populate the 1D inventory array attached to the player.
PlayerThe Player data type represents the player in the game and tracks their state, including position, inventory, and actions. It contains the following attributes:
position (int[2]): An array storing the player’s current x and y coordinates on the map. Default starting position is (18, 15).
inventorySize (int): Tracks the number of items currently in the player’s inventory. Maximum capacity is MAX_INVENTORY (24 items).
inventory (Entity[MAX_INVENTORY]): An array storing the entities collected by the player, such as "wood" or "rock".
The Player data type is instantiated to manage the player’s interactions with the game world, including movement, resource collection, and inventory management.
void displayMap(Entity map[MAP_Y_SIZE][MAP_X_SIZE], Player player) - Outputs the Entitys in the map (showing their types first character) to the terminal, and displaying the player as a p when it's position is hit. This function is already called in main when it is needed for this assignment.
void displayInventory(Player player) - Outputs the players inventory. This function is already called in main when it is needed for this assignment.
void displayBank(Entity storage[MAX_BANK], int size) - Outputs the item types in the storage. This function is already called in main when it is needed for this assignment. This function is already called in main when it is needed for this assignment.
string getCommand() - Gets the command the user wants to perform in the game and returns the command name as a string. Valid commands are "move", "chop", "mine", "bank", and "exit" This function is already called in main when it is needed for this assignment.
double rng() - Returns system neutral random numbers between 0 and 1. These random values will be the same each time the program is run thus they really are pseudo-random numbers. This function will need to be called and used appropriately in chop() and mine() as described below.
readMap(Entity[MAP_Y_SIZE][MAP_X_SIZE])
The readMap function populates the passed 2D array representing the game map by reading data from a CSV file (map.csv) by:
Opening the File: Open map.csv using an ifstream object.
Skipping the Headers: Skips the first line of the file containing the column headers.
Reading Records: For each subsequent line, read the x-coordinate, y-coordinate, and entity type (e.g., tree or rock) using the string.find() and string.substr() methods to parse the comma-separated values.
Populating the Map: Using the parsed x (column) and y (row) coordinates, update the corresponding position in the passed 2D array to being the read in object.
Assign the entity type to the type field of the Entity struct at that position.
Assign the chance field of the Entity struct:
If the entity type is "rock", the chance is set to 40% (0.4).
If the entity type is "tree", the chance is set to 80% (0.8).
string move(Player &, Entity[MAP_Y_SIZE][MAP_X_SIZE])
The move function allows the player to move to a valid and unoccupied new position on the game map by:
Getting Input:
Prompt the user to input an x-coordinate between 0 and MAP_X_SIZE - 1.
Prompt the user to input a y-coordinate between 0 and MAP_Y_SIZE - 1.
Validating the Location: Check if the location at the chosen (x, y) coordinates is unoccupied (i.e., no entity at map[y][x]). If the location is occupied, display an error message indicating that an entity is blocking the path and read a new (x, y) coordinate to move to.
Updating Player Position: Once a valid position is provided, update the player's x and y coordinates.
Returning the Success Message: Return a success message "moved to position x, y" from the function to be output by main.
string chop(Player &, Entity[MAP_Y_SIZE][MAP_X_SIZE])
The chop function allows the player to chop wood from a nearby tree if certain conditions are met by:
Checking for Nearby Trees: Check the spaces directly above, below, left, and right of the player for a tree entity. If no tree is found return "no wood nearby to chop" from the function to be output by main.
Checking Inventory Capacity: If a tree is found, check if the player's inventory is full by comparing the player's inventorySize with MAX_INVENTORY. If full return "inventory too full to chop wood" from the function to be output by main.
Attempting to Chop Wood: If the inventory is not full, call the provided rng() function and store the returned pseudo-random number. If the number is not below the tree’s chance value return "unsuccessful at chopping wood" from the function to be output by main. Otherwise, if successful at chopping:
Add an entity with type "wood" to the back of the player's inventory.
Increment the player's inventorySize.
Return the success message "successfully chopped wood" from the function to be output by main.
string mine(Player &, Entity[MAP_Y_SIZE][MAP_X_SIZE])
The mine function allows the player to mine rocks from a nearby rock entity if certain conditions are met. It mirrors the chop function closely by:
Checking for Nearby Rocks: Check the spaces directly above, below, left, and right of the player for a rock entity. If no rock is found return "no rocks nearby to mine" from the function to be output by main.
Checking Inventory Capacity: If a rock is found, check if the player's inventory is full. If full return "inventory too full to mine rocks" from the function to be output by main.
Attempting to Mine Rocks: If the inventory is not full, call the provided rng() function and store the returned pseudo-random number. If the number is not below the rock’s chance value return "unsuccessful at mining rocks" from the function to be output by main. Otherwise, if successful at mining:
Add an entity with type "rock" to the back of the player's inventory.
Increment the player's inventorySize.
Return the success message "successfully mined rocks" from the function to be output by main.
string bank(Player &, Entity[MAX_BANK], Entity[MAP_Y_SIZE][MAP_X_SIZE], int &)
The bank function allows the player to deposit items into the bank if certain conditions are met by:
Checking for a Nearby Banker: Check directly above, below, left, and right of the player for a "banker" entity. If no banker is found return "there doesn't seem to be any bankers around" from the function to be output by main.
Depositing Items: If a banker is found, deposit items from the player’s inventory into the bank until either:
The inventory is empty, or
The bank reaches MAX_BANK capacity.
Items should be removed from the inventory starting from the back of the inventory working toward the front. For each deposited item:
Place the item into the bank array by assigning the bank element the inventory element.
Increment the bankSize.
Decrement the player's inventorySize.
If the bank becomes full while adding items, any remaining items stay in the player's inventory.
Returning a Success Message: Once the items are tone being stored in the bank return "banked X items", where X is the number of deposited items. If the bank becomes full, " - bank full" is appended.
If valid x, y coordinates are entered when the player wants to move, return from the function to output in main: "moved to position x, y" where x and y are replaced with the actual coordinates.
If a tree is successfully chopped, return from the chop function to output in main: "successfully chopped wood".
If a rock is successfully mined, return from the mine function to output in main: "successfully mined rocks".
Once all items in inventory are placed in the bank or the bank is full, return from the bank function to be output in main: "banked COUNT items" where COUNT is the actual count of items banked. If the bank becomes full append " - bank full" to the end of the message.
If an invalid x-coordinate is entered when the player wants to move, output the error message: "Invalid x-coordinate\n"
If an invalid y-coordinate is entered when the player wants to move, output the error message: "Invalid y-coordinate\n"
If the player wants to move to a space where an entity already exists, output the error message: "There's a TYPE in your way!\n" replacing TYPE with the type of entity that is already there.
If there are no trees around for the player to chop, return the error message: "no wood nearby to chop" from the chop function to be output in main.
If the player's inventory is too full to chop, return the error message: "inventory too full to chop wood" from the chop function to be output in main.
If the a random number is not low enough to chop, return the error message: "unsuccessful at chopping wood" from the chop function to be output in main.
If there are no rocks around for the player to mine, return the error message: "no rocks nearby to mine" from the mine function to be output in main.
If the player's inventory is too full to mine, return the error message: "inventory too full to mine rocks" from the mine function to be output in main.
If the a random number is not low enough to mine, return the error message: "unsuccessful at mining rocks" from the mine function to be output in main.
If there are no bankers around for the player to bank, return the error message: "there doesn't seem to be any bankers around" from the bank function to be output in main.
See provided reference output files or the automated tests in CodeGrade.
Save: Save your code as main.cpp. Do not ignore this step or save your file(s) with different names.
Submit: Your program source code must be submitted via CodeGrade as a properly named .cpp file prior to the deadline to receive full credit. Any submissions after the deadline will be subject to the class’ late policy.