For the first tutorial we’re going to look at something really important. We’re going to create the first tool in our toolbox for dealing with user commands. It is of course the section function. A small function that takes the player’s input and splits it up into words we can later make use of. It’s not a glamorous function, and doesn’t produce anything the player can see but it is absolutely vital to any parser.
A quick disclaimer, I’m new enough to programming myself, while this will work don’t take it as best practice or the only way this can be done. Experiment, try different things! Feel free to point out if I’ve made any errors and I’ll update and credit you for helping 🙂
The idea is to take whatever text the player enters and split it into individual words we can use later in the parser. While we’re at it we’re also going to capitalise the whole thing to make life easier for us, as this means we don’t have to worry about whether or not certain character in the text are capitalised, or not. Once the words have been capitalised and split up we’ll store them in a vector for later use.
We’re using a vector because it behaves very similar to an array, except it’s also a little more flexible in that you don’t have to specify it’s length and can add to it pretty much for as long as you’d like, which means we don’t necessarily have to limit how much text the user enters.
Your includes are gonna look like this:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
We’ll only need the standard namespace so we’re good to go for now. We can start a few quick bits now just to have some work to show. In our main function we’ll need a string to initially store the players input, a command to take that input in and one to print it to screen just to make sure everything’s working as expected. So we’ll have:
int main()
{
string userInput;
getline(cin, userInput);
cout << userinput;
}
Go ahead and compile and type something in. When you hit return it should reprint exactly what you put in. The greater than and less than signs here are like arrows telling the data where to go, cin gets the data from the user and the puts it into our string userInput. While cout needs data to print to the screen and so it comes from the userInput string. We’re using the getline function to use cin for us as the player will hopefully be using spaces to delineate their commands, cin won’t handle this on it’s own, but getline circumvents this limitation nicely.
Next we’ll make the whole thing uppercase to make it easier to recognise and manipulate in our parser. For this we’ll need to treat the string as if it was an array of chars (characters, or letters) and make each one upper case. We won’t bother to check if it’s already upper case or note, we’ll just change everything to upper case anyway, just to make life easier. We’ll encase it in a for loop and use the handy toupper function to do our work for us, so we now have this between cin and cout:
for(int i = 0; i <= userInput.length() – 1; i++)
{
userInput[i] = toupper(userInput[i]);
}
Compile and run and you’ll see now that everything you type in will be return in all caps as if you were having an argument on the internet, as if such things would ever happen!
The next step is to split it into individual words and put them into a vector so they’re all in one handy, easy to access place. We’ll use another string as a go between which we’ll call subString and of course a vector string which we’ll call words.
For simplicity’s sake why don’t we just loop through the userInput string once and get everything we need out of it in one go. As we loop through we’ll check each character, if it’s a character we’ll add it to the subString. We don’t need spaces so we’ll use spaces to know when we have a full word and move that full word in the subString into the vector words, then clear the subString so we can use it again other wise we’d just be adding another word into the end of the current one and we don’t want that. When we get to the end of the userInput string we’ll add the final word.
The commands we’ll be using here are pretty self explanatory. We’ll be using .length(), .push_back() to add words to the vector, and .clear() to clear out the subString for use again. We end up with this:
for(int i = 0;i <= userInput.length()-1; i++)
{
if(userInput[i] != ‘ ‘ && i <= userInput.length()-1)
{
subString += userInput[i];
}
if(userInput[i] == ‘ ‘ || i == userInput.length()-1)
{
words.push_back(subString);
subString.clear();
}
}
This is great but we can’t test if it works or not, we can’t just use cout on the vector and expect it to print the whole thing, so we’ll have to write a small for loop to display each word seperately! Easily done:
for(int i = 0; i <= words.size()-1; i++)
{
cout << words[i];
}
Compile and run and you should see your word returned back to you, in all caps, and with no spaces between, perfect! The last thing we’re gonna do here is to move this out into a function to make things neat and tidy and not clutter up our main function. We’re also going to use a pointer type vector so we can use the vector of words from anywhere within the program without having to pass it around constantly.
We’ll need to write our function ABOVE the main function so it’s declared and we’ll be able to use it in main. we’ll need 2 variables, the userInput string and the words vector. We’ll use the & on the vector to tell the functi0n to use the vector as a pointer so it can be used outside the function. It’ll look like this:
void section(string userInput, vector<string> &words)
{
}
All you need to do then is to cut and past our two for loops for capitalising and splitting the words up and the subString. After getline call the function, passing it userInput and words like so:
section(userInput, words);
leave the last test loop in place so you can see that everything works. Compile and play, you know have a working section function! Well done 🙂
Any question or queries feel free to post a comment or reach out to me on twitter (@SeveralBytes). Thanks for reading and I hope you get something from this!
Here’s the code in full if you really need it:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
void section(string userInput, vector<string> &words)
{
string subString;
//Make everything upper case for easier handling
for(int i = 0; i <= userInput.length()-1; i++)
{
userInput[i] = toupper(userInput[i]);
}
//Split userInput into a string vector for even easier handling later
for(int i = 0;i <= userInput.length()-1; i++)
{
if(userInput[i] != ‘ ‘ && i <= userInput.length()-1)
{
subString += userInput[i];
}
if(userInput[i] == ‘ ‘ || i == userInput.length()-1)
{
words.push_back(subString);
subString.clear();
}
}
}
int main()
{
string userInput;
vector<string> words;
getline(cin, userInput);
section(userInput, words);
//Loop through the words to make sure it it works
for(int i = 0; i <= words.size()-1; i++)
{
cout << words[i];
}
}
Pingback: Text Adventure Tutorial: Map and Movement | SeveralBytes