Skip to content

eric15342335/comp2113-engg1340-group-project

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Stock Market Simulator

C++ Linux

CI CodeFactor Coverage Status

Menu

  1. Team Members
  2. Game Description
  3. How to Play
  4. Code Requirements
    1. Generation of random game sets or events
    2. Data structures for storing game status (e.g., arrays, STL containers)
    3. Dynamic memory management (e.g., dynamic arrays, linked lists, STL containers)
    4. File input/output (e.g., for loading/saving game status)
    5. Program codes in multiple files (recall separate compilation)
    6. Proper indentation and naming styles
    7. In-code documentation
  5. Credits
    1. Logo
    2. Non-standard Libraries Used

Team members

Name UID Profile
Cheng Ho Ming 3036216734 Cheng Ho Ming
Chung Shing Hei 3036216760 Chung Shing Hei
Chow Yui Hei 3036222446 Chow Yui Hei
Chu Chun Yin 3036270778 Chu Chun Yin
Wong Sonny 3036222458 Wong Sonny

Game Description

"Stock Market Simulator" is a game that attempts to introduce a realistic stock buying experience to players. The game utilizes the random number generation capability of the operating system to mimic real-life stock unpredictable trends while giving players breathing room to better think about their investing strategies.

How to Play

Demo gameplay video

Compilation

Prerequisite:

  • This repository.
  • A working g++ compiler that supports C++17
  • make
  • A terminal that supports ANSI escape codes

To compile:

make

To run the game:

./stocksim

Or if you prefer one step:

make all

To ensure an optimal gaming experience, please adopt the following recommendations before running the game:

Terminal Size

Maximize your terminal window to its fullest extent.

On Windows, you can achieve this by pressing the Alt+Enter key combination, which will toggle the terminal to fullscreen mode.

Font Size Adjustment

Reduce your terminal's font size initially.

Unsuitably large font sizes may cause the table displaying stock information and data to be cut off or misaligned within the terminal window.

Start with a smaller font size, such as 10, to ensure the stock table displays correctly, and then increase the size if needed.

Tutorial

After displaying the ASCII game logo, you will be prompted by this screen:

Please enter.
0 for new save,
1 for loading old save(s),
2 for deleting save,
3 to quit:

Type 0 and press Enter. Type your preferred name and press Enter again.

Now you should enter the game's main menu.

Some user inputs the game receives (case-insensitive):

  • B: Buy a stock.
  • S: Sell a stock.
  • T: Select a stock (or 0 for Happy Stock Index) to display a corresponding price history graph, which shows the historical performance of a stock and the fluctuations in stock price. Enter T again to hide the pop-up.
  • E: Display all ongoing events that affect the performance of stocks. Enter E again to hide the pop-up.
  • N: Proceed to the next round. The game will generate new stock prices and events.
  • X: Exit the game.

You may wonder why there is no save button. The answer is --- you don't need it!

Each time when you enter N: Next Round, the game data is saved automatically in the saves/ folder. See more information on File I/O part.

Table column explanation:

  • #: The index of the stock. You will enter it when you are purchasing/selling a stock.
  • Category: The respective categories a stock corresponds to. Some events are applied to a specific category only!
  • Name: Self-explainatory.
  • $Price: The current price (per unit) of the stock.
  • Change: The change in the stock price compared to the last round.
  • %Change: The percentage change of stock price.
  • #Has: Number of stocks that you can sell.
  • #Max: Number of stocks that you can buy. This takes account of trading_fees_percent.

Some additional columns are hidden, they served for debugging purposes only.

Code Requirements

Generation of random game sets or events

Generation of stock prices:

  • We used normal distribution to generate the percentage change in the stock price for each new round.

float percentage_change_price(Stock stock) {
std::random_device rd;
std::mt19937 gen(rd());
std::map<stock_modifiers, float> _modifiers = getProcessedModifiers(stock);
std::normal_distribution<float> distribution(
_modifiers[mean], _modifiers[standard_deviation]);
// std::cout << offset << " " << sd << " " << lower_lim << " " << upper_lim <<
// std::endl; Implementing a max loop here so will not be infinite if there is a
// fault.
for (unsigned int max_loop = 0; max_loop < 100; max_loop++) {
float x = distribution(gen);
if (x > _modifiers[lower_limit] && x < _modifiers[upper_limit]) {
return x / std::pow(2, stock.get_split_count());
}
}

Generation of in-game events:

  • In our game, we also included 99 events that will each have a possibility to happen in your gameplay.
    • The (relative) probability of each event is determined by the Stock_event.probability_permille member variable.

const std::vector<Stock_event> all_stock_events = {
// event_id 0 to 7 affect all stocks
{
/** event_id */ 0,
/** mutually_exclusive_events */ {1},
/** text */ "The FED has decreased the interest rate!",
/** duration */ 5,
/** percentage_permille */ 4,
/** type_of_event */ all_stocks,
/** category */ 0,
/** modifiers*/
{{standard_deviation, 0.1}, {mean, 20}, {lower_limit, 0}, {upper_limit, 20}},
},

Data structures for storing game status (e.g., arrays, STL containers)

In stock.h, we declared class Stock which utilizes STL vector, list and map to store various game data.

private:
/** @brief Name of the stock that we assigned to it. */
std::string name;
/** @brief Current price of the stock. */
float price;
/** @brief Number of stocks the player has purchased. */
unsigned int quantity;
/** @brief Use numbers to represent the category of the stock.
* @note The range of the numbers should be `[0, category_list_size - 1]`.
* @ref category_list_size
*/
unsigned int category;
/** @brief Stores all the events that will apply to this stock specifically. */
std::list<Stock_event> events;
/** @brief Stores the initial value of the stock_modifiers (e.g. standard
* deviation, mean and limits). */
std::map<stock_modifiers, float> attributes;
/** @brief Contains the stock price history. First element (index 0) is the
* oldest. */
std::vector<float> history;
/** @brief Contains the spliting count of a stock */
unsigned int split_count;

The class Stock itself represents an Stock object, which you can purchase, sell, generate a new price for it, etc.

/**
* @class Stock stock.h "stock.h"
* @brief A class that represents a stock object in the game.
* The stock has a name, price, quantity, category, money spent, events, attributes, and
* history. The stock can be purchased, sold, and updated.
* @note Example usage:
* @code {.cpp}
* // Create a stock object. The constructor will initialize the stock automatically.
* Stock stock;
* // Purchase a stock.
* float balance = 1000; stock.purchase(balance, 1, 0.01);
* // Sell a stock.
* stock.sell(balance, 1, 0.01);
* // What is the name of the stock?
* std::string name = stock.get_name();
* // Get the upper limit of the percentage change of the stock price:
* float upper_limit = stock.getTotalAttribute(stock_modifiers::upper_limit);
* @endcode
*/
class Stock {
public:
/** @brief Constructor of class Stock */
Stock(void);

Other than class Stock, we have struct Stock_event that represents an in-game event.

struct Stock_event {
public:
/** @brief The id of the event.
* This is still required for checking, despite the fact that we are using a
* vector.
*/
unsigned int event_id;
/** @brief A list of event_ids that this event is mutually exclusive with. */
std::vector<unsigned int> mutually_exclusive_events;
/** @brief The text that will be displayed to the player. */
std::string text;
/** @brief Number of rounds the event will last. If the event has duration <= 0
* then it will be removed. */
unsigned int duration;
/** @brief 0 to 1000, so 114 means 11.4% */
unsigned int probability_permille;
/** @brief The type of event: Apply to all stocks, in one category or randomly?
*/
event_type type_of_event;
unsigned int category;
/** @brief Stores the stock_modifiers that the event applies. */
std::map<stock_modifiers, double> modifiers;
/** @brief Overload the == operator to compare two Stock_event */
bool operator==(const Stock_event & other) const {
return event_id == other.event_id && text == other.text &&
probability_permille == other.probability_permille &&
type_of_event == other.type_of_event && category == other.category &&
modifiers == other.modifiers;
}
/**
* @brief Serialize the event as std::ostream object.
* @param outputstream The std::ostream object to write the data.
* @param event The event object to get the data from.
* @return A std:ostream object contains all the data of the event.
* @code
* // Create a event object by calling the constructor
* Stock_event event;
* // Print the data of the event.
* std::cout << event << std::endl;
* @endcode
*/
friend std::ostream & operator<<(
std::ostream & outputstream, const Stock_event & event) {
outputstream << event.event_id << " ";
for (unsigned int i = 0; i < event.mutually_exclusive_events.size(); i++) {
outputstream << event.mutually_exclusive_events[i] << " ";
}
outputstream << ";" << event.text << ";" << event.duration << " "
<< event.probability_permille << " " << event.type_of_event
<< " " << event.category << " ";
for (const auto & modifier : event.modifiers) {
outputstream << modifier.second << " ";
}
return outputstream;
}
/**
* @brief Deserialize the event from a std::istream object.
* @param inputstream The std::istream object to read the data.
* @param event The event object to store the data.
* @return A std:istream object contains all the data of the event.
*/
friend std::istream & operator>>(
std::istream & inputstream, Stock_event & event) {

Dynamic memory management (e.g., dynamic arrays, linked lists, STL containers)

  • Stock.history is an std::vector<float> that stores the history of the stock prices.
  • Stock.events is an std::list<Stock_event> that stores on-going events that applies to the stock itself.
  • Stock.attributes is an std::map<stock_modifiers, float> that stores the properties related to stock price generation.

/** @brief Stores all the events that will apply to this stock specifically. */
std::list<Stock_event> events;
/** @brief Stores the initial value of the stock_modifiers (e.g. standard
* deviation, mean and limits). */
std::map<stock_modifiers, float> attributes;
/** @brief Contains the stock price history. First element (index 0) is the
* oldest. */
std::vector<float> history;

File input/output (e.g., for loading/saving game status)

This game provides players with the ability to create a new save file, load an existing save, or delete a save upon starting the game. The save files are distinguished by the std::string playerName variable.

Save File Structure

  • Each stock in the game has a separate .save file.
  • Basic player information is stored in the playerstatus.save file.
  • The Happy Stock Index (HSI) is stored in the hsi.save file.

Automatic Saving

To prevent loss of progress and prevent rollbacks, the game automatically saves the current state at the end of every round.

File Management

The game heavily relies on the <filesystem> library introduced in C++17 to maintain file organization. This library enables the game to:

  • Obtain a list of available save files.
  • Create new folders for save files.
  • Delete existing save files.

Note for macOS and Linux Users

If you are running the game on macOS or Linux and not from the terminal, the saves folder will be located in the root directory.

Program codes in multiple files (recall separate compilation)

We split our program codes into multiple files according to their functionality and purpose. Click me to see the details of each file.

Proper indentation and naming styles

We enforce our code formatting style via the use of clang-format tool. You can see our configuration file here.

For naming styles, different members of our group has different preferences. Some notable examples (list may not include all styles and files):

In-code documentation

We place a strong emphasis on code documentation in our project. We utilize the JavaDoc format to write our comments, which enables seamless integration with third-party documentation auto-generation tools like Doxygen.

If you've noticed the numerous hyperlinks throughout this README.md file, they are pointing to the automatically generated documentation hosted on our GitHub Pages site. You can access this documentation by clicking here.

Credits

Non-standard libraries used

External Libraries

For printing prettified tables in our code, we used the VariadicTable library. VariadicTable is a third-party header-only library licensed under LGPL-2.1.

Logo

The logo used in this game is generated with Text to ASCII.

Back to top