Click here to Skip to main content
15,848,157 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
My friend and I are building a text-based game. But the problem so far is I cannot figure out how to resolve this problem. The goal was to make two functions. One to print a vector and another to find a specific element within.
C++
#include <iostream>
#include <string>
#include <cmath>
#include <stdlib.h>
#include <random>
#include <ctime>
#include <cctype>
#include <ctype.h>
#include "bits/stdc++.h"
#include <list>
#include <vector>
#include <numeric>

using namespace std;

// Variables

// Abilites
string Darkvision = "Darkvision: The ability to see in darkness but only in monotone";
string LowLightVision = "Low light vision: The ability to see in unfavorable conditions";
string Stonecunning = "Stonecunning: The innate ability to know the condition of stonework";
vector<string> abilites;

// Lists
list<string> raceChoiceList = {};
list<string>::iterator it = raceChoiceList.begin();
list<string> yesList = {"Y","Y.","YES","YES."}; // All words that would count as yes. Make sure all letters are uppercase. ex. "YES", "YES."
list<string>::iterator yes = yesList.begin();
list<string> noList = {"N","N.","NO","NO."};  // All words that would count as no. Make sure all letters are uppercase. ex. "NO", "NO."
list<string>::iterator no = noList.begin();
//list<>

//Pointers

// Booleans
bool raceChoiceHuman = false;
bool raceChoiceDwarf = false;
bool raceChoiceElf = false;
bool hasAbility = false;
bool literacy = true;
bool common = true;
bool elvish = false;
bool dwarvish = false;

// Strings / String Streams
string yesNoInput;

// Integers
int bugFixer1 = 0; // Used to fix the bug that would say "Invalid Command." immediately.
int yesNoOut;

// End of Variables

int Die(int sides, int minVal) {
    srand((unsigned int) time(NULL));
    int roll = (rand() % sides) + minVal;
    return roll;
}

template <typename T>
T printVector(T vectorName) {
    for (int i = 0; i < vectorName.size(); i++) {
        cout << vectorName[i] << "\n";
    }
};

template <typename T>
T findElement(T vectorName, string Element) {
    string element;
    auto itr = find(Element.begin(), Element.end(), element);
    if (itr != Element.end()) {
        cout << "You have the ability of " << element << "\n";
        hasAbility = true;
    } else {
        cout << "You do not have the ability of " << element << "\n";
        hasAbility = false;
    }
};

// Classes
class Player {

    public:
        int d6_1;
        int d6_2;
        int d6_3;
        int d6_4;
        int d6_5;
        int d6_6;
        double pi = 2 * acos(0.0);
        string playerClass;
        string name;
        string race;
        string size;
        int speed;
        int xp = 0;
        int expReq = 1000;
        int HD;
        int level = 1;
        int strength = Die(18, 3);
        int dexterity = Die(18, 3);
        int constituion = Die(18, 3);
        int intelligence = Die(18, 3);
        int wisdom = Die(18, 3);
        int charisma = Die(18, 3);
        //Abilites Mods'
        int strMod;
        int dexMod;
        int conMod;
        int wisMod;
        int intMod;
        int chaMod;
        string meleeWeapon = "fists";
        string rangedWeapon;
        string magic;

        void statMods() {
            strMod = floor((strength - 10) / 2);
            dexMod = floor((dexterity - 10) / 2);
            conMod = floor((constituion - 10) / 2);
            wisMod = floor((wisdom - 10) / 2);
            intMod = floor((intelligence - 10) / 2);
            chaMod = floor((charisma - 10) / 2);
        }
        
        void levelUp() {
            if (expReq <= xp) {
                level++;
                int n = n + (level * 1000);
                expReq + n;
                // incomplete as of now... Once classes are installed I'll go further.
            }
        } 
};

class Item {
    
    public:
        string effect;
        int price;
};

class Weapon: public Item {

    public:
        string material;
        string enchantment;
        int dmg;
        string dmgType;
};

/*
class Dice {

    public:
        int sides;

        int Roll(int times){
            int rolls;
            srand(time(NULL)); //initialise random num generator using time
            for (int i = 0; i < times; i++){
                int roll_; //declare a variable to keep store the random number
                roll_ = rand() % sides + 1; // generate a random number between 1 and 6
                rolls += roll_;
            }
            return rolls;
        }
};
/// I have now just made this useless.^
// Functions                           |
*/
//void menu() {

//}

//Takes string and makes It capitalized
void toupper(std::string &stri) {
    if (stri.length() == 0) {
        return;
    }
 
    transform(begin(stri), end(stri), begin(stri), [](char const &c) {
                    return tolower(c);
                });
    
    int counter = 0;
    for (char letter : stri){
        stri[counter] = toupper(stri[counter]);
        counter += 1;
    }
}

int yesNo(){ // Work in progress
    string yesNoChoice = "aaa";
    getline(cin, yesNoChoice);
    getline(cin, yesNoChoice);
    toupper(yesNoChoice);
    // Marker (for control + h)
    stringstream s(yesNoChoice);  
    string word;
    while (s >> word){
        for (string option : yesList){
            if (word == option){
                cout << "Press enter to continue. \n>";
                return 1;
            }
        for (string option : noList){
            if (word == option){
                return 0;
            }
        }
        }
    }
    return 2;
}

int main() {

    Player player1;
    player1.statMods();
    Weapon Torch;
    Torch.effect = "light";
    Torch.material =  "wood";
    Item inventory[10] = {Torch};

    //cout << "Type everything in lowercase" << "\n"; // You can type with any order of capital or lowercase thanks to toupper()
    // Ok thanks man
    cout << "What is your name, traveler?" << "\n";
    bool nameRestart = true;
    while (nameRestart) {
        cout << "> ";
        cin >> player1.name;
        cout << player1.name << "? Are you sure that's your true name?" << "\n";
        cout << "> ";
        yesNoOut = yesNo();
        if (yesNoOut == 1) {
            nameRestart = false;
        }
    }
    bool raceRestart = true;
    while (raceRestart/* == true <--- Redundant*/) {
        raceRestart = false;
        if (bugFixer1 == 1){
        cout << "Where do you hail from " << player1.name << "?" << "\n";
        cout << "The Human Cities? the Elven Forests? the Mightly Dwarven Kingdoms?" << "\n";
        cout << "> ";
        }
        string raceChoice;
        getline (cin, raceChoice);
        toupper(raceChoice);
        // Marker (for control + h)
        stringstream ss(raceChoice);  
        string word;
        // What was this supposed to be????????
        // Something that decided ear shape. And you don't need to include the ones with periods.
        // Actually, I did.
        while (ss >> word) { 
            if (word == "ELF" || word == "ELF." || word == "FOREST" || word == "FOREST."|| word == "FORESTS" || word == "FORESTS." || word == "ELVEN" || word == "ELVEN."){
                raceChoiceElf = true;
            } else if (word == "DWARF" || word == "DWARF." || word == "KINGDOM" || word == "KINGDOM."|| word == "KINGDOMS" || word == "KINGDOMS." || word == "DWARVEN" || word == "DWARVEN."){
                raceChoiceDwarf = true;
            } else if (word == "HUMAN" || word == "HUMAN." || word == "CITY" || word == "CITY."|| word == "CITIES" || word == "CITIES."){
                raceChoiceHuman = true;
            }
        }
            if (raceChoiceHuman) {
                player1.race = "Human";
                player1.size = "M";
                player1.speed = 30;
                break;
            } else if (raceChoiceElf) {
                player1.race = "Elf";
                player1.strength--;
                player1.strength--;
                player1.dexterity++;
                player1.dexterity++;
                player1.size = "M";
                player1.speed  = 30;
                abilites.push_back(LowLightVision);
                break;
            } else if (raceChoiceDwarf) {
                player1.race = "Dwarf";
                player1.constituion++;
                player1.constituion++;
                player1.charisma--;
                player1.charisma--;
                player1.size = "M";
                player1.speed = 20;
                abilites.push_back(Darkvision);
                abilites.push_back(Stonecunning);
                // Note: Dwarves does not suffer from speed reduction from armor or such conditions
                break;
            } else {
                if (bugFixer1 == 0){
                    bugFixer1 = 1;
                    raceRestart = true;
                } else {
                cout << "Invalid command" << "\n";
                raceRestart = true;
                }
            }
        }
    cout << "Hmm, so you are a " << player1.race << "?" << "\n";
    string raceCheck;
    cin >> raceCheck;
    toupper(raceCheck);
    player1.statMods();
    if (raceCheck == "No") {
        raceRestart = true;
    } else {
        cout << "Race:" << player1.race << "\n" << "Strength: " << player1.strength << "\n" << "Dexterity: "  << player1.dexterity << "\n" << "Constitution: " << player1.constituion << "\n" << "Wisdom: " << player1.wisdom << "\n" << "Intelligence: " << player1.intelligence << "\n" << "Charisma: " << player1.charisma << "\n" << "Size: " << player1.size << "\n" << printVector<vector>(abilites);
    }
    cout << "\n" << "What class are you?" << "\n" << "1) Barbarian" << "\n" << "2) Bard" << "\n" << "3) Cleric" << "\n" << "4) Druid" << "\n" << "5) Fighter" << "\n" << "6) Monk" << "\n" << "7) Paladin" << "\n" << "8) Ranger" << "\n" << "9) Rogue" << "\n" << "10) Sorcerer" << "\n" << "11) Wizard" << "\n";
    int classChoice;
    cin >> classChoice;
    switch(classChoice) {
        case 1:
            player1.playerClass = "Barbarian";
            literacy =  false;
            break;
        case 2:
            break;
        case 3:
            break;
        case 4:
            break;
        case 5:
            break;
        case 6:
            break;
        case 7:
            break;
        case 8:
            break;
        case 9:
            break;
        case 10:
            break;
        case 11:
            break;
    }
    

}

The error:
main.cpp: In function ‘int main()’:
main.cpp:311:394: error: no matching function for call to ‘printVector<template<class _Tp, class _Alloc> class std::vector>(std::vector<std::__cxx11::basic_string<char> >&)’
  311 |         cout << "Race:" << player1.race << "\n" << "Strength: " << player1.strength << "\n" << "Dexterity: "  << player1.dexterity << "\n" << "Constitution: " << player1.constituion << "\n" << "Wisdom: " << player1.wisdom << "\n" << "Intelligence: " << player1.intelligence << "\n" << "Charisma: " << player1.charisma << "\n" << "Size: " << player1.size << "\n" << printVector<vector>(abilites);
      |                                                                                                                                                                                                                                                                                                                                                                                                          ^
main.cpp:61:3: note: candidate: ‘template<class T> T printVector(T)’
   61 | T printVector(T vectorName) {
      |   ^~~~~~~~~~~
main.cpp:61:3: note:   template argument deduction/substitution failed:


Now I understand the error but my question is: how do I achieve both of these functions (In working order, preferably). Thanks in advance for any help you can give whether it be a full comprehensive read-through (Which would be amazing) or an alternate route I can take to get where I want to go.

What I have tried:

Google, youtube, 5 metric tons of documentation... the works.
Posted
Updated 13-Aug-23 15:59pm

It seems to me that templates might not be the right way for the desired functions. I would first overload only the output operator. There are several ways to do this. Instead of the function as before, a class VectorPrinter can be created that contains a printVector functionality. The call would then be possible as follows:
C++
abilites.push_back(Darkvision);
abilites.push_back(LowLightVision);
std::cout << "abilites:\n" << VectorPrinter(abilites) << "\n";

The VectorPrinter class contains t_strvector as a member variable and overloads the output operator << to output the contents of the vector. The desired syntax with cout can then be used by creating an object of the VectorPrinter class.

For example, the class could look like this:
C++
typedef std::vector<std::string> t_strvector;

class VectorPrinter {
public:
    VectorPrinter(const t_strvector& vectorName) : vectorName(vectorName) {}
    friend std::ostream& operator<<(std::ostream& os, const VectorPrinter& vp)
    {
        for (size_t i = 0; i < vp.vectorName.size(); i++) {
            os << vp.vectorName[i] << "\n";
        }
        return os;
    }
private:
    const t_strvector& vectorName;
};



The class can of course be written as a template to use different vector types. Here's one way to do that:

C++
template <typename T>
class VectorPrinter {
public:
    VectorPrinter(const std::vector<T>& vectorName) : vectorName(vectorName) {}
    // ...
};
 
Share this answer
 
v2
Comments
Brennon Nevels 14-Aug-23 5:56am    
Hmm the class was a good idea, I'm going to try and replicate that for the find element.
The function should look more like this :
C++
template <typename T>
void printVector( const std::vector< T > & vec )
{
    for (int i = 0; i < vec.size(); i++) {
        cout << vec[ i ] << "\n";
    }
};
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900