C++ How to new line without chopping words - c++

I am currently making a text game in c++. I am using a function that prints text one character at the time (to give a "narration" effect), which also goes to a new line to some condition defined by the function.
Here is the function:
void smart_print(const std::string& str, int spacer)//str is the printed message. spacer is the amount of space you want at the beginning and at the end of the cmd window
{
int max = Console::BufferWidth - (spacer * 2);
int limit = max;
ut.spacer(5);//this prints 5 spaces
for (int i = 0; i != str.size(); ++i)//this loop prints one character of the string every 50 milliseconds. It also checks if the limit is exceeded. If so, print new line
{
if (limit < 0)
{
cout << endl;
ut.spacer(5);
limit = max;
}
limit--;
std::cout << str[i];
Sleep(50);
}
}
The problem with this function, is that it chops the words, because it does a new line everytime the "limit" variable is less than 0, regardless if there is an incomplete word or not.
I made a sort of scheme to try to figure out how it should work correctly, but i can't manage to "translate" it into code.
1) Analyze the string, and check how long is the first word
2) Count the characters and stop counting when there is a space
3) Calculate if it can print the word (by subtracting the number of letters to max)
4) If the limit is exceeded, go to new line. Otherwise proceed to print the word one letter at the time
I really can't manage to make such function. I hope someone can help me out :P
Thanks in advance.

I think you should do something like checking if the current character is blank, using the std::isspace method like this:
// inside your for
if (limit < 0 && isspace(str[i]))
{
cout << endl;
ut.spacer(5);
limit = max;
}
limit--;
if(!isspace(str[i])) std::cout << str[i];
Sleep(50);
Note: I haven't tested the code so I am not 100% sure if it works correctly.

Related

Counting correct and misplaced digits

This program is a "Codebreaker" game. In this section of the program, the computer checks the digits guessed by the player, compares each of them to every one of the digits in the secret code, and determines if the digit is "correct" or simply "misplaced." I can not get this section to work correctly. I wrote the code for "correct" and "misplaced" in different passes, and I know I need to replace the original variables with a letter so that one number is not checked as more than one and is instead replaced by either "y" or "z". When I run the program, the values for "correct" and "misplaced" are not correct. I am getting random values.
correct_digits = 0;
misplaced_digits = 0;
misplaced_digit = false;
/* Get and validate the player's guess using "get_player_code()"; increment guess counter */
player_code = get_player_code();
++num_guesses;
for(int x=0;x<CODE_LENGTH;x++){
if(player_code[x]==secret_code[x]){
correct_digits++;
secret_code[x]='y';
}
}
for(int x=0;x<CODE_LENGTH;x++){
for(int i=0;i<CODE_LENGTH;i++){
if(player_code[i]==secret_code[i]){
misplaced_digits++;
secret_code[i]='z';
}
}
}
/* Print player's guess and number of correct/misplaced digits */
cout << setw(40) << player_code << setw(15) << correct_digits << setw(15) << misplaced_digits << '\n';
Assuming player_code and secret_code will always be the same length (if player_code is less you will have undefined behavior) and assuming all of the code you're not showing us is correct, then all you need to do is fix this check:
if(player_code[i]==secret_code[i]){
You're checking the same character in each string. You want to compare a character in one of the strings to every character in the other. Your condition should be:
if(player_code[x]==secret_code[i]){

Determine the current output to the speaker C++ Beginner

Recently, I've began learning C++ in college and was asked to make a looping sequence of "*" with the sequence going like this:
*
***
*****
*******
*********
*********
*******
*****
***
*
[continues indefinitely until it goes x lines, where x is specified at the start]
How I did it if you need a visualisation:
#include<iostream>
#include<windows.h>
using namespace std;
int main() {
int hFar=0; //Variable that will be used to find out how many parts into the sequence the user would like to travel.
unsigned long int fibSequenceA = 0; //Unsigned doesn't overflow as easilly. This is the first value of the fibunacci sequence, it's defined as 0 to start.
unsigned long int fibSequenceB = 1; // Second Value of fibbunacci sequence. Defined at 1 to start.
int sPart = 1;//Used for the * sequence, it is the part of the sequence that the loop is on. It changes dynamically by either +2 or -2 every loop.
int cValue = 0;// also for the * sequence, it is the current number of * typed.
int sDirection = 0; // used to change from subtracting 2, and adding 2.
int redo = 1; // used to ensure that every 9 and every 1 the sequence repeats that number a second time. Starts at one because the sequence starts with only 1 single * rather then 2 *.
cout << "How far into the second sequence would you like to travel?" << endl; //Requests how far into the * sequence you'd like to go.
cin >> hFar; //inputs answer into variable.
for(int i = 0; i < hFar; i++ ) {//begins for statement. Notice there's no hfar/2. There will only be 1 output per line now.
while(cValue < sPart) { //Basic while loop to input the ammount of * on the current line. Works by adding a * depending on what part of the sequence it is.
cout << "*"; //self explainitory.
cValue++; //raises the cValue in order to keep track of the current number of *. Also prevents infinite loop.
}
if(sPart == 9 && redo == 0) { //Checks if the sequence part is 9, meaning that the value begins to reduce to 1 again. But first, it must repeat 9 to keep with the sequence.
sDirection = 3; //sets the direction to 3 to make sure that the value of sPart stays at 9, instead of reducing by 2.
redo = 1; //resets the redo.
cValue = 8; //changes the value of the current number of 8. Not sure if this is important, It gets done again later to make sure anyway.
sPart = 9; //Changes the sPart to 9, the needed number of *. Also redone later, but to make sure, I kept this here.
}
else if(sPart == 9 && redo == 1) { // if the sequence has already redone the 9th *
sDirection = 1; //sets the direction to 1; The sequence will reverse.
redo = 0; //returns redo to 0 to ensure that next time it reaches 1, it repeats the 1 * again.
}
else if(sPart == 1 && redo == 0) { //when the value reaches one for the second time, it needs to repeat that value.
sDirection = 3; //sets the direction to 3 again to stop the change.
redo = 1; //resets the redo.
cValue = 0;//also might be redundant.
}
else if(sPart == 1 && redo == 1) { // stops the duplicate number of *
sDirection = 0; //sets the direction to +2 again.
redo = 0;//resets the redo.
}
Sleep(50);
cout << endl; //adds a new line. This ensures that we get a new line after every part rather then 900 * on one line.
if(sDirection == 0) { //if the direction is positive.
sPart += 2; //adds 2 to the spart to keep with the sequence.
cValue = 0; //resets the cValue to 0 so the while statement works again.
}
else if(sDirection == 1) { //if the direction is negative
sPart -=2; //subtracts 2 from the spart to keep with the sequence.
cValue = 0; //resets the cValue to keep the while statement working.
}
else if(sDirection = 3) { //if the change is
//Could have been done differently. Could have just set the values to themselves, but it wasn't working. not sure why.
if(sPart == 9){ //if the spart is currently 9.
sPart = 9; //keeps it at 9.
cValue = 0; //resets the cValue.
}
else if(sPart == 1){ //if the spart is currently 1
sPart = 1; //keeps it at one.
cValue = 0; //resets the cValue.
}
}
}
return 1;//ends the code.
}
[Sorry about all the comments, I'm trying to make sure I understand what I'm doing, like I said, I'm learning :)]
While fooling around with the loops, I ended up putting the Sleep() function in, so that it produced a wave effect when generating the sequence. This got me thinking, and I wanted to know if it would be possible to make the command prompt act like a makeshift volume visualizer. (The more "*" the higher the volume at that point in time).
So, when playing a song on my computer, the program would find the total output to the speaker, and put a number of "*" that correlate to that volume, and would continue this until the program ends, producing (hopefully) an interesting effect. (if you're confused, play a song on your computer, right click on the speaker icon on the task bar, and click open volume mixer, and look at the volume levels change, this is the type of effect that I'm looking for)
Would this be possible? I've been googling the issue, (found things like This and I've found a number of ways to find out the current MASTER volume, and change that, But I'm looking for more of the actual volume that one hears, not the maximum volume that my speakers can output.
Here's somewhat of what I'm looking to do.
int sPart = x; //x = the current output of the speaker
int cValue = 0 //the current number of "*" output
while([somecondition I'm not sure when i want the sequence to stop yet]) {
while(cValue < sPart) {
cout << "*";
cValue++;
}
cout << endl; //ends the current line, making room for the next value of the volume.
Sleep(50); //waits 50ms before finding the next volume value.
sPart = [current speaker value]; //finds the value of the speaker again.
cValue = 0; //resetting the number of "*" back to zero.
}
//I just reused the variables from my original code.
Would this be possible? If so, would a beginner be capable of this? Again, If so, how would it be done?

Strange characters appearing in 2D Char Array

I'm coding a game that utilizes a 'grid', which I have created using a 2 dimensional array of structs, which contain a char value and a boolean value. In my program's .h file, I declare the struct and create the grid.
struct Tile
{
char letter;
bool active;
};
Tile grid [6][5];
In my .cpp file, I initialize the grid so that all values are blank.
for (int i = 0; i < 7; ++i)
{
for (int j = 0; j < 6; ++j)
{
grid[i][j].active == false;
//grid[i][j].letter = '.';
//it always crashes when i try doing the above line
}
}
The function that prints the grid, printGrid, is below
for (int i = 0; i < 7; ++i)
{
for (int j = 0; j < 6; ++j)
{
cout << i;
//the above statement is for debugging purposes so that I can see
//which column easier
std::cout << grid[i][j].letter;
}
std::cout << std::endl;
}
cout << "1 2 3 4 5 6" << endl;
Now, the original goal was to have the default .letter value be '.'. But for some reason, when I tried to do this, there are disastrous results; the screen fills up with characters moving so fast I can't entirely see what they are (I recall some hearts and smiley faces), along with an obnoxious, rapid beeping. So I decided to leave that commented line out.
When I run the program without that line, for some reason, the "grid" always displays characters in certain spots, without any input from the user, or without me having expressly declared any values to that spot. For instance, the spot of the 1st column from the left and the bottom row, always has a character in it (grid[6][5].letter). It changes every time I run the program, and I've seen it range from a heart, to the letter A, to the spanish 'n' (the one with a ~ over it).
I thought to myself, "Hey, since grid[6][5] is the spots that are always buggy, I'll just declare those individual spot's .letter values to be blank (' ')!". That didn't work.
I've got no idea why this one spot is giving me trouble. There were other areas that would have an abnormal character, but I was able to neutralize them by setting their .letter values to blank. If anyone has any idea on how to fix this, pleas
EDIT: The other abnormal characters, which appear at grid[6][0], grid[6][1], grid[6][5], and grid[6][4], all make my program crash at later stages if I set them to blank (' '); however, blanking grid[6][5] is the one that makes it crash at the get go. I tried using a debugger, but it wasn't able to tell me anything helpful.
you're running over the end of your arrays
Tile grid [6][5]; needs to be Tile grid [7][6];
or you need to loop only to i < 6 and j < 5.

C++ std::string::find always returns npos?

I'm trying to get this function to cut up a string, and then return it without whitespace and all lowercase. And to do this I'm trying to find a " " to see if a string, "The Time Traveller (for so it will be convenient to speak of him)", contains a space.
The code is as follows, passing in the string above to this function. It always returns string::npos. Any idea about the problem?
string chopstring(string tocut){
string totoken = "";
int start = 0;
while(tocut[0] == ' ' || tocut[0] == 10 || tocut[0 == 13]){
tocut.erase(0);
}
int finish = 0;
finish = tocut.find(" ", start);
if (finish == string::npos){
cout << "NPOS!" << endl;
}
for (int i = start; i < finish; i++){
totoken += tocut[i];
}
tocut.erase(start, finish);
return tokenize(totoken);
}
tocut.erase(0) is erasing all of tocut. The argument is the first character to erase, and the default length is "everything".
tocut[0 == 13] should probably be tocut[0] == 13. Those are very different statements. Also, please compare with character values ('\t') instead of integers. Incidentally, this in conjunction with the previous is your actual problem: tocut[0 == 13] becomes tocut[false], which is tocut[0], which is true. So the loop runs until tocut is empty, which is immediately (since you erase it all overzealously in the first go).
The net effect of the above two bugs is that when you reach the find statement, tocut is the empty string, which does not contain a space character. Moving on...
You can use the substr function instead of your loop to migrate from tocut to totoken.
Your last tocut.erase(start, finish) line isn't doing anything useful, since tocut was pass-by-value and you immediately return after that.
Actually, the majority of the code could be written much simpler (assuming my understanding that you want to remove all spaces is correct):
string chopstring(string tocut) {
std::string::size_type first(tocut.find_first_of(" \n\r"));
if (first != tocut.npos) {
tocut.substr(first);
}
tocut.erase(std::remove(tocut.begin(), tocut.end(), ' '), tocut.end());
return tokenize(tocut);
}
If you actually want to remove all whitespace, you probably want to use std::remove_if() with a suitable predicate.

Do I need more space?

I have code that is supposed to separate a string into 3 length sections:
ABCDEFG should be ABC DEF G
However, I have an extremely long string and I keep getting the
terminate called without an active exception
When I cut the length of the string down, it seems to work. Do I need more space? I thought when using a string I didn't have to worry about space.
int main ()
{
string code, default_Code, start_C;
default_Code = "TCAATGTAACGCGCTACCCGGAGCTCTGGGCCCAAATTTCATCCACT";
start_C = "AUG";
code = default_Code;
for (double j = 0; j < code.length(); j++) { //insert spacing here
code.insert(j += 3, 1, ' ');
}
cout << code;
return 0;
}
Think about the case when code.length() == 2. You're inserting a space somewhere over the string. I'm not sure but it would be okay if for(int j=0; j+3 < code.length(); j++).
This is some fairly confusing code. You are looping through a string and looping until you reach the end of the string. However, inside the loop you are not only modifying the string you are looping through, but you also change the loop variable when you say j += 3.
It happens to work for any string with a multiple of 3 letters, but you are not correctly handling other cases.
Here is a working example of the for loop that is a bit more clear it what it's doing:
// We skip 4 each time because we added a space.
for (int j = 3; j < code.length(); j += 4)
{
code.insert(j, 1, ' ');
}
You are using an extremely inefficient method to do such an operation. Every time you insert a space you are moving all the remaining part of the string forward and this means that the total number of operations you will need is in the order of o(n**2).
You can instead do this transormation with a single o(n) pass by using a read-write approach:
// input string is assumed to be non-empty
std::string new_string((old_string.size()*4-1)/3);
int writeptr = 0, count = 0;
for (int readptr=0,n=old_string.size(); readptr<n; readptr++) {
new_string[writeptr++] = old_string[readptr];
if (++count == 3) {
count = 0;
new_string[writeptr++] = ' ';
}
}
A similar algorithm can be written also to work "inplace" instead of creating a new string, simply you have to first enlarge the string and then work backward.
Note also that while it's true that for a string you don't need to care about allocation and deallocation still there are limits about the size of a string object (even if probably you are not hitting them... your version is so slow that it would take forever to get to that point on a modern computer).