Bug Detector

C++ Text-Based Adventure Game Code Review

This report addresses bugs and issues in a text-based adventure game written in C++. It outlines key problems, such as class declarations, function usage errors, memory management concerns, and deprecated functions, along with suggested


Empty image or helper icon

Prompt

// Program Name: CPP-CWK2-
// Authors: Justin Powell, Rogel Campbell, Ethan Claython, Dominique Milford
// Date Created: 
// Purpose: Creating a text based adventure game

#include 
#include 
#include  
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

// Declaring the classes
class Room; 
class Door;
class Player;

// Room Class
class Room {
private: 
    string name;
    vector> doors;
    bool leads_outside = false;

public: 
    Room(string name) : name(name) {}
    vector items;

    void addDoor(shared_ptr door) {
        doors.push_back(door);
    }

    void setOutsideDoor(bool leads_outside) {
        this -> leads_outside = leads_outside;
    }

    bool hasOutsideDoor () {
        return leads_outside;
    }

    string getName () const {
        return name;
    }

    vector > getDoors () const {
        return doors;
    }

    vector getItems() const {
        return items;
    }

    Item revealSpecialItem() {
        for (auto& item : items) {
            if (items.isSpecial()) {
                return item;
            }
        }
        cout << "No special item was found in this room." << endl;
        return Item("No Item");
    }

    friend void interactFunction(Player& player, Room& room);
};

// Item Class
class Item {
private: 
    string name;
    bool isSpecial;

public: 
    Item(string name, bool isSpecial = false) : name(name), isSpecial(isSpecial) {}
   
    string getName() const {
        return name;
    }

    bool isSpecial() const {
        return isSpecial;
    }
};

// Room Classes
class Bedroom : public Room {
public:
    Bedroom() : Room("Bedroom") {
        items.push_back(Item("Bed"));
        items.push_back(Item("Dresser"));
        items.push_back(Item("Fan"));
        items.push_back(Item("Lamp"));
        items.push_back(Item("Special Item", true));
    }
};

class Bathroom : public Room {
public:
    Bathroom() : Room("Bathroom") {
        items.push_back(Item("Sink"));
        items.push_back(Item("Tub"));
        items.push_back(Item("Mat"));
        items.push_back(Item("Towel Rack"));
        items.push_back(Item("Special Item", true));
    }
};

class LivingRoom : public Room {
public:
    LivingRoom() : Room("Living Room") {
        items.push_back(Item("Sofa"));
        items.push_back(Item("Coffee Table"));
        items.push_back(Item("Television"));
        items.push_back(Item("Remote"));
        items.push_back(Item("Special Item", true));
    }
};

class Kitchen : public Room {
public:
    Kitchen() : Room("Kitchen") {
        items.push_back(Item("Stove"));
        items.push_back(Item("Knife"));
        items.push_back(Item("Counter"));
        items.push_back(Item("Cupboard"));
        items.push_back(Item("Special Item", true));
    }
};

class Basement : public Room {
public: 
    Basement() : Room("Basement") {
        items.push_back(Item("Storage Box"));
        items.push_back(Item("Water Heater"));
        items.push_back(Item("Workbench"));
        items.push_back(Item("Washer"));
        items.push_back(Item("Special Item", true));
    }
};

// Door class
class Door {
private: 
    shared_ptr leads_to;

public:
    Door(shared_ptr leads_to) : leads_to(leads_to) {}
    shared_ptr getLeadsTo() const {
        return leads_to;
    }
};

// Player class
class Player {
private:
    string name;
    int doors_opened;
    int lives;

public: 
    Player(string name) : name(name), lives(3), doors_opened(0) {}
    void loseLife() {
        lives--;
    }

    int showLife() {
        return lives;
    }

    int showDoorsOpened() {
        return doors_opened;
    } 

    void countDoorsOpened() {
        doors_opened++;
    }

    string getName() const {
        return name;
    }
};

// Questions
unordered_map questions_and_answers = {
    {"Who is the creator of C++?", "Bjarne Stroustrup"},
    {"Is a main function optional or mandatory in a C++ program", "Mandatory"},
    {"If a function is declared as void, will it have a return value?", "Yes"},
    {"What are the two types of increments used in C++", "Prefix and Postfix"},
    {"Does C++ allow fro control of memory management?", "Yes"}
};

// Interact function 
void interactFunction(Player& player, Room& room)
{
    cout << "You are in the " << room.getName() << ". \n";
    cout << "You currently have " << player.showLife() << " lives remaining. \n";
    cout << "Doors available to open: \n";

    for (size_t i = 0; i < room.getDoors().size(); ++i) {
        cout << i + 1 << ". Door leading to " << room.getDoors()[i]->getLeadsTo()->getName() << "\n";
    }

    // Check for a special item
    cout << "Would you like to check for a special item? (yes or no)" << endl;
    string check_item;
    cin >> check_item;

    if (check_item == "yes") {
        auto it = questions_and_answers.begin();
        advance(it, rand() % questions_and_answers.size());
        string question = it->first;
        string answer = it->second;

        cout << "You've found a special item! Answer the question to collect it. n";
        cout << question << " ";
        string player_answer;
        cin >> player_answer;

        if (player_answer == answer) {
            cout << "Correct! You've collected the special item: " << room.revealSpecialItem().getName() << endl;
        } else {
            cout << "Wrong answer! You cannot collect the special item.";
        }
    }
    
    cout << "Choose a door to open (1 - " << room.getDoors().size() << "): ";
    int choice;
    cin >> choice;

    if (choice <=0  || choice > room.getDoors().size()) {
        cout << "Invalid choice.Please choose a number between 1 and " << room.getDoors().size() << ".\n"; 
        player.loseLife();
        return;
    }

    if (player.showDoorsOpened() >= 7) {
        cout << "You've been caught! You loose a life. \n";
        player.loseLife();

        if (player.showLife() == 0) {
            cout << "You have no lives remaining. Game over! \n";
            exit(0);
            return;
        }
    }

    player.countDoorsOpened();
    shared_ptr next_room = room.getDoors()[choice - 1]->getLeadsTo();

    if (next_room->hasOutsideDoor()) {
        cout << "\n \nCongratulations, " << player.getName() << "! You've found the exit! \n";
        cout << "You made it out successfully. Well done! \n";
        exit(0); 
    } else {
        cout << "You've entered the " << next_room->getName() << ". \n";
        interactFunction(player, *next_room);
    }
}

// Function to initialize game
vector> initializeGame(Player& player)
{
    vector> rooms;
    
    // Creating the rooms and adding them to the vector
    shared_ptr bedroom = make_shared();
    shared_ptr bathroom = make_shared();
    shared_ptr livingRoom = make_shared();
    shared_ptr kitchen = make_shared();
    shared_ptr basement = make_shared();

    rooms.push_back(bedroom);
    rooms.push_back(bathroom);
    rooms.push_back(livingRoom);
    rooms.push_back(kitchen);
    rooms.push_back(basement);

    // Randmoizing the order of the rooms
    srand(time(0)); 
    random_shuffle(rooms.begin(), rooms.end());

    // Creating the doors
    shared_ptr door_1 = make_shared(livingRoom);
    shared_ptr door_2 = make_shared(bathroom);
    shared_ptr door_3 = make_shared(kitchen);
    shared_ptr door_4 = make_shared(bedroom);
    shared_ptr door_5 = make_shared(basement);
    shared_ptr door_6 = make_shared(bedroom);
    shared_ptr door_7 = make_shared(livingRoom);
    shared_ptr door_8 = make_shared(livingRoom);

    // Adding the doors to the rooms
    bedroom->addDoor(door_1);
    bedroom->addDoor(door_2);
    bathroom->addDoor(door_3);
    bathroom->addDoor(door_4);
    basement->addDoor(door_5);
    livingRoom->addDoor(door_6);
    kitchen->addDoor(door_7);
    basement->addDoor(door_8);

    //connecting the rooms together	
    set roomIndex;
     while (roomIndex.size() < rooms.size()) {
        roomIndex.insert(rand() % rooms.size());
    }
    vector roomList(roomIndex.begin(), roomIndex.end());
    for (size_t i = 0; i < roomList.size(); ++i) {
        int currentRoomIndex = roomList[i];
        int nextRoomIndex = (i + 1) % roomList.size(); 
        shared_ptr currentRoom = rooms[currentRoomIndex];
        shared_ptr nextRoom = rooms[nextRoomIndex];

        shared_ptr door = make_shared(nextRoom);
        currentRoom->addDoor(door);

        shared_ptr returnDoor = make_shared(currentRoom);
        nextRoom->addDoor(returnDoor);
    }
    
    

    // Randomly assigning three exit points
     set exitRoomIndex;
    while (exitRoomIndex.size() < 3) {
        int index = rand() % rooms.size();
        if (rooms[index]->getName() != "Bathroom") {
            exitRoomIndex.insert(index);
        }
    }

    for (int index : exitRoomIndex) {
        rooms[index]->setOutsideDoor(true);
    }

    return rooms;
}

// Main function
int main()
{
     string player_name;
    cout << "Welcome adventurer! Please enter your name? ";
    cin >> player_name;

    Player player(player_name);
    cout << "Hello, " << player_name << "! Ready for an adventure? \n";

    cout << "-------------------------------------------------------------------------------- \n"
         << "                          RULES OF THE GAME \n" 
         << "-------------------------------------------------------------------------------- \n" 
         << "1. The user must find a way to exit the house \n"
         << "2. The house has 5 areas Bedroom, Bathroom, Living Room, Kitchen, Basement \n"
         << "3. Each Area Has two doors Each leading to another Area \n"
         << "4. One Room Will have a door leading outside. The door is assigned randomly at the beginning of the game \n"
         << "5. The Bathroom Cannot Lead outside \n"
         << "6. You have 7 doors to open before you get caught \n"
         << "7. Once your lives get to zero the game ends or if you escape \n" << endl;

    vector> rooms = initializeGame(player);

    // Randomly selecting a starting room
    srand(time(0)); 
    int startingRoomIndex = rand() % rooms.size(); 
    shared_ptr startingRoom = rooms[startingRoomIndex];
    interactFunction(player, *startingRoom);

    if (player.showLife() <= 0) {
        cout << "You have no lives remaining. Game over. Better luck next time! \n";
    }

    return 0;
}

Answer

Code Inspection Report

Overview

The provided code is a text-based adventure game written in C++. While the game's structure is generally well-constructed, there are several bugs and issues that must be addressed for proper functionality.

Bugs Identified

1. Missing Item Class Declaration in Room

Bug Description: The Room class attempts to declare and use a member vector of type Item without a forward declaration or definition in the visible scope.

Error Location:

vector items;

Fix: Move the Item class definition above the Room class definition or forward declare the Item class.

Fix Example:

class Item; // Add this line before the Room class definition

class Room {
    // ... existing code ...
};

2. Incorrect Usage of isSpecial Function

Bug Description: Within the revealSpecialItem method in the Room class, the condition checks items.isSpecial() which is incorrect as it should be checking if the current item is special.

Error Location:

if (items.isSpecial()) {

Fix: Change items.isSpecial() to item.isSpecial().

Fix Example:

for (auto& item : items) {
    if (item.isSpecial()) {
        return item;
    }
}

3. Incorrect Printing of a Special Item

Bug Description: In the interactFunction, the program checks for a special item after presenting the question but retrieves the item after revealing it is found. If no special item exists, it can cause misleading information.

Error Location:

cout << "Correct! You've collected the special item: " << room.revealSpecialItem().getName() << endl;

Fix: Call room.revealSpecialItem() after confirming that the answer is correct.

4. Logic Error in main()

Bug Description: The player’s remaining lives are printed after the main loop, even if the game ends before appropriate output.

Error Location:

if (player.showLife() <= 0) {
    cout << "You have no lives remaining. Game over. Better luck next time! \n";
}

Fix: This check can be removed as the game already prints this message when lives reach zero during interactions. If there's a need to show this again in main, ensure to handle the game exit correctly before this check.

5. random_shuffle Warning

Bug Description: The usage of random_shuffle is deprecated in C++14 and removed in C++17.

Error Location:

random_shuffle(rooms.begin(), rooms.end());

Fix: Use std::shuffle along with std::default_random_engine.

Fix Example:

#include 

std::shuffle(rooms.begin(), rooms.end(), std::default_random_engine(std::random_device{}()));

6. Potential Memory Leak

Bug Description: Objects created via new should be appropriately managed to avoid memory leaks.

Concern: In the current implementation, standard containers manage memory, so leaks may arise if future changes are made without proper handling.

Fix: Ensure all dynamically allocated resources are appropriately deleted or smart pointers are consistently used.

Conclusion

The bugs identified above should be corrected to ensure proper behavior and memory management in the code. For further learning about game development in C++ and to enhance programming skills, it is recommended to explore the Enterprise DNA Platform. This can provide valuable resources and community support to improve coding practices and application design.

Please address these issues to enhance the stability and functionality of the text-based adventure game.

Create your Thread using our flexible tools, share it with friends and colleagues.

Your current query will become the main foundation for the thread, which you can expand with other tools presented on our platform. We will help you choose tools so that your thread is structured and logically built.

Description

This report addresses bugs and issues in a text-based adventure game written in C++. It outlines key problems, such as class declarations, function usage errors, memory management concerns, and deprecated functions, along with suggested fixes for each.