Inexistent double decrement? - c++

I was writing a little game, where there is an hidden word, and the user must guess, char to char, what word is.
While coding this I got stucked in something that I don't understeand where and how it happens.
while(true)
{
if(Hue == 0)
Try -= 1;
if(Hue == 1)
Hue = 0;
GotoXY(0, 3);
printf("Inserisci una lettera maiuscola\n>");
GotoXY(1, 4);
scanf("%c", &Key);
GotoXY(0, 4);
printf(" ");
GotoXY(0, 6);
printf("Numero di tentativi rimasti: %d ", Try);
for(unsigned short Iterator = 1; Iterator < Length - 1; ++Iterator)
if(Key == UserString[Iterator])
{
for(unsigned short SecIterator = Iterator; SecIterator < Length - 1; ++SecIterator)
{
if(Key == UserString[SecIterator])
{
GotoXY(SecIterator, 1);
printf("%c", Key);
}
}
Hue = 1;
break;
}
}
Hue is a simple control variable to check if the key was in the word.
If it's still 0 then the key wasn't in the word, so the Try decrements it self and so on.
But what happen is that Hue, either is 0 or 1 causes the decrement of Try, and the thing even more stange is that Try decrement twice when is 0, evenly in the code isn't written nothing like that.
Thanks for the help.

It seems the confusion is mostly due to the double decrement: well, you are reading chars and most likely you hit return making two chars available: the entered character and the '\n' from the return. Since apparently neither character matches you get two decrements.
Just for a bit of explanation: when using the formatted input using std::cin >> Key leading whitespace is skipped. When using scanf("%c", &c) each character is extracted. I think you can have scanf() skip leading spaces using
if (1 == scanf(" %c", &c)) {
// process the input
}
Note the extra space in front of the '%c'. To debug issues like this it is generally a good idea to print what was read. ...and, of course, you always need to verify that the read was actually successful.

Related

Add character at every vowel

I had a similiar question earlier and managed to solve it. Now I'm trying to do it backwards, this is my code at the moment.
Basically I want the end result to "p5A5SSW5o5R5o5d", but when I run this it just find the first "o" which is in the first part of passworod, I need it to skip the the vowel it have already added a 5 before and after to.
I want every vowel (only included AOao in the current string as thats all the vowels appearing in my string), to have a 5 as prefix and suffix. It gets stuck at the first o and doesnt proceed to the next o. I have created a nested for loop which means it takes the first character in the encrypt-string, proceeds to the next for-loop and loops through every single vowel Ive included in the vowel string until it finds a match. Otherwise it restarts at the first for-loop but incremented by one. First go it should search the letter "p", second run it should search the letter "A" and so on.
Result: p5A5SSW55o55rod
Expected Result: p5A5SSW5o5R5o5d
In the end I will also want to rotate all the characters, but thats for another task, I think I can just use either if-statement or a switch to do that. If it ends up on a 5, do nothing, otherwise rotate.
I hope I made myself clear and provided you with all the relevant information, otherwise just holler in the comments.
Thanks in advance.
#include <string>
#include <sstream>
const string vowel = "AOao";
string encrypt, decrypt;
encrypt = "pASSWoRod";
decrypt = encrypt;
for (int i=0; i<encrypt.length(); i++){
for (int j=0; j<vowel.length(); j++){
if (encrypt[i] == vowel[j]){
decrypt.insert(decrypt.find(vowel[j]), 1, '5');
decrypt.insert(decrypt.find(vowel[j]) + 1, +1, '5');
}
}
}
return decrypt;
}
find, when not proved a starting point, always finds the first instance.
Searching and keeping track of the string length and where you've already inserted characters is much harder than it seems at first glance (as you've noticed).
Build the result from scratch instead of inserting characters into an initial string.
Also, implement this function (actual implementation left as an exercise):
bool is_vowel(char c);
and then
std::string encrypt = "pASSWoRod";
std::string decrypt;
for (auto c: encrypt)
{
if (is_vowel(c))
{
decrypt += '5';
decrypt += c;
decrypt += '5';
}
else
{
decrypt += c;
}
}
find with one argument starts from the beginning. You would need the other find.
However maintaing an index in decrypt, one no longer would need a find.
int encryptI = 0;
for (int i = 0; i < decrypt.length(); i++, encyptI++){
for (int j=0; j<vowel.length(); j++){
if (decrypt[i] == vowel[j]){
//encryptI = encrypt.find(vowel[j], encryptI);
encrypt.insert(encryptI, 1, '5');
encrypt.insert(encryptI + 1, +1, '5');
encryptI += 2;
break;
}
}
}
The code could be nicer.
string encrypt;
for (int i = 0; i < decrypt.length(); i++, decyptI++){
char ch = decrypt[i];
if (vowel.find(ch) != string::npos) {
encrypt.append('5');
encrypt.append(ch);
encrypt.append('5');
} else {
encrypt.append(ch);
}
}
Your find is stopping at the first instance of the vowel, 'o'. You should include a starting position for your find so you ignore the part of the decrypt string you've already analyzed.

How to input a multi-digit integer into an Arduino using a 4x4 keypad?

I am trying to make a combination lock using an Arduino, a keypad and a Servo but I have come across an obstacle.
I can't find a way to store a 4 digit value in a variable. since keypad.getKey only allows to store one digit.
After some browsing on the internet I came upon a solution for my problem on a forum but the answer didn't include a code sample, and I couldn't find anything else about in on the internet.
The answer said to either use a time limit for the user to input the number or a terminating character (which would be the better option according to them).
I would like to know more bout these terminating characters and how to implement them, or if anybody could suggest a better solution that would be much appreciated as well.
Thank you in advance,
To store 4 digit values, the easiest and naive way to do it is probably to use an array of size 4. Assuming keypad.getKey returns an int, you could do something like this: int input[4] = {0};.
You will need a cursor variable to know into which slot of the array you need to write when the next key is pressed so you can do some kind of loop like this:
int input[4] = {0};
for (unsigned cursor = 0; cursor < 4; ++cursor) {
input[cursor] = keypad.getKey();
}
If you want to use a terminating character (lets say your keyboard have 0-9 and A-F keys, we could say the F is the terminating key), the code changes for something like:
bool checkPassword() {
static const int expected[4] = {4,8,6,7}; // our password
int input[4] = {0};
// Get the next 4 key presses
for (unsigned cursor = 0; cursor < 4; ++cursor) {
int key = keypad.getKey();
// if F is pressed too early, then it fails
if (key == 15) {
return false;
}
// store the keypress value in our input array
input[cursor] = key;
}
// If the key pressed here isn't F (terminating key), it fails
if (keypad.getKey() != 15)
return false;
// Check if input equals expected
for (unsigned i = 0; i < 4; ++i) {
// If it doesn't, it fails
if (expected[i] != input[i]) {
return false;
}
}
// If we manage to get here the password is right :)
return true;
}
Now you can use the checkPassword function in your main function like this:
int main() {
while (true) {
if (checkPassword())
//unlock the thing
}
return 0;
}
NB: Using a timer sounds possible too (and can be combined with the terminating character option, they are not exclusive). The way to do this is to set a timer to the duration of your choice and when it ends you reset the cursor variable to 0.
(I never programmed on arduino and don't know about its keypad library but the logic is here, its up to you now)
In comment OP says a single number is wanted. The typical algorithm is that for each digit entered you multiply an accumulator by 10 and add the digit entered. This assumes that the key entry is ASCII, hence subtracting '0' from it to get a digit 0..9 instead of '0'..'9'.
#define MAXVAL 9999
int value = 0; // the number accumulator
int keyval; // the key press
int isnum; // set if a digit was entered
do {
keyval = getkey(); // input the key
isnum = (keyval >= '0' && keyval <= '9'); // is it a digit?
if(isnum) { // if so...
value = value * 10 + keyval - '0'; // accumulate the input number
}
} while(isnum && value <= MAXVAL); // until not a digit
If you have a backspace key, you simply divide the accumulator value by 10.

Converting scancodes to ASCII

I'm implementing my own text editor in c++. It's going... ok. ;P
I need a way to turn a keycode (specifically Allegro, they call it scancodes) into an ASCII-char. I can do A-Z easy, and converting those to a-z is easy as well. What I do currently is use a function in Allegro that returns a name from a scancode (al_keycode_to_name), meaning if the key pressed is A-Z it returns "A" to "Z". That's easy peasy, but I can't simply read special characters like ",", ";" etc. That's where I'm having a hard time.
Is there a way to do this automatically? Maybe a library that does this? The real trick is taking different layouts into consideration.
Here's what I have so far, in case anyone's interested. The class InputState is basically a copy of the Allegro inputstate, with added functionality (keyDown, keyUp, keyPress for example):
void AllegroInput::TextInput(const InputState &inputState, int &currentCharacter, int &currentRow, std::string &textString)
{
static int keyTimer = 0;
static const int KEY_TIMER_LIMIT = 15;
for (int i = 0; i < 255; i++)
{
if (inputState.key[i].keyDown)
{
keyTimer++;
}
if (inputState.key[i].keyPress)
{
keyTimer = 0;
}
if ((inputState.key[i].keyPress) || ((inputState.key[i].keyDown) && (keyTimer >= KEY_TIMER_LIMIT)))
{
std::string ASCII = al_keycode_to_name(i);
if ((ASCII.c_str()[0] >= 32) && (ASCII.c_str()[0] <= 126) && (ASCII.length() == 1))
{
textString = textString.substr(0, currentCharacter) + ASCII + textString.substr(currentCharacter, textString.length());
currentCharacter++;
}
else
{
switch(i)
{
case ALLEGRO_KEY_DELETE:
if (currentCharacter >= 0)
{
textString.erase(currentCharacter, 1);
}
break;
case ALLEGRO_KEY_BACKSPACE:
if (currentCharacter > 0)
{
currentCharacter--;
textString.erase(currentCharacter, 1);
}
break;
case ALLEGRO_KEY_RIGHT:
if (currentCharacter < textString.length())
{
currentCharacter++;
}
break;
case ALLEGRO_KEY_LEFT:
if (currentCharacter > 0)
{
currentCharacter--;
}
break;
case ALLEGRO_KEY_SPACE:
if (currentCharacter > 0)
{
textString = textString.substr(0, currentCharacter) + " " + textString.substr(currentCharacter, textString.length());
currentCharacter++;
}
break;
}
}
}
}
}
You should be using the ALLEGRO_EVENT_KEY_CHAR event with the event.keyboard.unichar value to read text input. ALLEGRO_EVENT_KEY_DOWN and ALLEGRO_EVENT_KEY_UP correspond to physical keys being pressed. There is not a 1:1 correspondence between them and printable characters.
Say a dead key is being used to convert the two keys e' to é. You'd get two key down events for e and ' (and neither are useful for capturing the proper input), but one key char event with é. Or inversely, maybe somebody mapped F4 to a macro that unleashes an entire paragraph of text. In that case, you'd have multiple chars for a single key down.
Or a simple test: if you hold down a key for five seconds, you will get one ALLEGRO_EVENT_KEY_DOWN but multiple ALLEGRO_EVENT_KEY_CHAR as the OS' keyboard driver sends repeat events.
You can use ALLEGRO_USTR to easily store these unicode strings.
ALLEGRO_USTR *input = al_ustr_new("");
// in the event loop
al_ustr_append_chr(input, event.keyboard.unichar);
There's also ways to delete characters if backspace is pressed, etc. You can use the ustr data types with the font add-on directly via al_draw_ustr(font, color, x, y, flags, input), or you can use al_cstr(input) to get a read-only pointer to a UTF-8 string.

getchar() doesn't actually take input from user

I am writing a flexible command-line (but not for long!) diamond-square generator in C++. I have just finished writing the user input half. However, on the very last command, input "slips" and a newline is automatically inputted to getchar(). I have taken precautions to ensure that it's not any sort of overflow, namely, fflushing both stdin, and, for good measure, stdout. The problem persists. Here is my code:
#include <stdio.h>
#include <stdlib.h>
int main () {
unsigned long seed = 0, x = 0, y = 0, initial = 0, range = 0;
int smooth = 0, fail = 1;
char flagchar1 = 'n';
printf("Welcome to my diamond-square generator! This isn't full-feature yet, so I'm just gonna have you input the variables one by one. ");
do {
printf("Please input the seed (this is a positive integer):\n");
fail = scanf("%lu", &seed);
while (fail == 0) {
printf("Try again, smartass.\n");
fail = scanf("%lu", &seed);
}
fail = 1;
printf("Now input the x, or horizontal, size of your grid:\n");
fail = scanf("%lu", &x);
while (fail == 0) {
printf("An integer. Not a string. An integer. You can do that, can't you?\n");
fail = scanf("%lu", &x);
}
fail = 1;
printf("Now input the y, or vertical, size of your grid:\n");
fail = scanf("%lu", &y);
while (fail == 0) {
printf("What was that supposed to be? An integer, please.\n");
fail = scanf("%lu", &y);
}
fail = 1;
printf("Now input about how high you'd like the grid to be (this goes from a scale of 1 to 256):\n");
fail = scanf("%lu", &initial);
while (initial == 0 || initial > 256 || fail == 0) {
printf("ahahahahaha how HIGH do you have to be just to HAVE that hieght........\n");
fail = scanf("%lu", &initial);
}
fail = 1;
printf("Now input the range of the heights on your grid (this must be equal to or less than 256):\n");
scanf("%lu", &range);
while (range >= 256 || fail == 0) {
printf("What did I say about being equal to or less than 256? Give me something reasonable to work with here.\n");
fail = scanf("%lu", &range);
}
fail = 1;
printf("Just one more variable to go! Now, I need you to input the smoothness of your grid. Smaller numbers make spikier grids. You can make this negative, but beware!\n");
fail = scanf("%d", &smooth);
while (fail == 0) {
printf("That... was not a number.\n");
fail = scanf("%d", &smooth);
}
fail = 1;
printf("\nOkay. Are these the values you want?\n Seed: %lu\n Width: %lu\n Length: %lu\n Height: %lu\n Range: %lu\n Smoothness: %d\nDo you want to keep these? Type Y/n.\n", seed, x, y, initial, range, smooth);
fflush(stdin);
fflush(stdout);
flagchar1 = getchar();
} while (flagchar1 != 'y' && flagchar1 != 'Y' && flagchar1 != '\n');
}
Here is my output, the program having ended (the program just repeats the entire do-while loop if I remove the && flagchar1 != '\n' from while()):
Welcome to my diamond-square generator! This isn't full-feature yet, so I'm just gonna have you input the variables one by one. Please input the seed (this is a positive integer):
12345678
Now input the x, or horizontal, size of your grid:
40
Now input the y, or vertical, size of your grid:
30
Now input about how high you'd like the grid to be (this goes from a scale of 1 to 256):
1288
ahahahahaha how HIGH do you have to be just to HAVE that hieght........
128
Now input the range of the heights on your grid (this must be equal to or less than 256):
30
Just one more variable to go! Now, I need you to input the smoothness of your grid. Smaller numbers make spikier grids. You can make this negative, but beware!
10
Okay. Are these the values you want?
Seed: 12345678
Width: 40
Length: 30
Height: 128
Range: 30
Smoothness: 10
Do you want to keep these? Type Y/n.
What's happening, and how do I fix it?
P.S. I know my input validation is essentially useless. Help with this is also greatly appreciated.
Make the end of your loop look like this:
// Ignore remaining characters on current line.
int ch;
while( (ch = getchar()) != EOF && ch != '\n')
;
// fetch first character on next line
flagchar1 = getchar();
} while (flagchar1 != 'y' && flagchar1 != 'Y' && flagchar1 != '\n');
You are leaving the '\n' in stdin after your last call to scanf.
You must not rely upon fflush(stdin) having any specific behavior. The result of invoking fflush on a input stream is undefined. See Using fflush(stdin)
The code is behaving exactly as you tell it to. If the user enters 'y', 'Y' or enter, one of those conditions in the while loop will be false, which causes it to exit.
What you want is:
while (flagchar1 == 'y' || flagchar1 == 'Y' || flagchar1 == '\n');
Edit: I would also delete the fflush(stdin) and replace getchar() with fgets(). That will guarantee the entire line is read without having to use fflush, which may be the issue.
I'm guessing you are on Linux? This works fine on VS in Windows. It prompts, reads from keyboard, and if examined contains the correct 'y' or 'Y' in question.
I might suggest you try changing the last scanf to:
fail = scanf("%d ", &smooth);
You could also try calling fpurge() instead of fflush(), but that's non standard, and I think the space at the end of the format string will get you what you want.
The trailing space will ask scanf to consume any extra whitespace (including newlines) in the input data. fflush() probably won't do what you want for input.
I suspect whatever system you are on is indeed leaving the carriage return in the stream and if you print flagchar1 as an int you'll get 10?
Suggestions:
Use C++ streams.
Use tolower or toupper before comparing characters.
Use std::string.
The C language, which uses fgets, gets, fflush, strcmp, has many issues in this area. The C++ language has resolved many of these issues in the std::stream classes.
Since you are not using C++ features, you should change the C++ tag to C.
Try
} while (flagchar1 != 'y' || flagchar1 != 'Y' || flagchar1 != '\n');
instead of
} while (flagchar1 != 'y' && flagchar1 != 'Y' && flagchar1 != '\n');

input string validation without external libraries for c++

I need to validate one input string from a user. Eventually it will need to break down into two coordinates. ie a4 c3. And once they are coordinates they need to be broken out into 4 separate ints. a=0 b=1, etc. They must also follow the following stipulations:
If an end-of-input signal is reached the program quits.
Otherwise, all non-alphanumeric characters are discarded from the input.
If what remains is the single letter 'Q'
Then the program quits.
If what remains consists of 4 characters, with one letter and one digit among the first two characters and one letter and one digit among the last two characters, and if each letter-digit pair is in the legal range for our grid
Then input is acceptable.
I have completely over-thought and ruined my function. Please let me know where I can make some corrections.
I am mainly having trouble going from one string, to four chars if and only if the data is valid. Everything else I can handle.
Here is what I have so far.
void Grid::playerMove()
{
string rawMove;
string pair1 = " ";
string pair2 = " ";
bool goodInput = false;
char maxChar = 'a';
char chary1, chary2;
int x11,x22,y11,y22;
for (int i =0; i<size; i++)
{
maxChar++;
}
while(!goodInput)
{
cout<<"What two dots would you like to connect? (Q to quit) ";
cin>>rawMove;
rawMove = reduceWords(rawMove);
if (rawMove == "Q")
{
cout<<"end game";
goodInput = false;
}
else if (rawMove.size() == 4)
{
for(int j=0;j<2;j++)
{
if (pair1[j] >='a' && pair1[j] <=maxChar)
{
chary1 = pair1[j];
}
else if(pair1[j] >=0 && pairl[j]<=size+1)
{
x1 = pair1[j];
}
}
for(int k=0;k<2;k++)
{
if (pair2[k] >='a' && pair2[k] <=maxChar)
{
chary2 = pair2[k];
}
else if(pair2[k] >=0 && pair2[k]<=size+1)
{
x2 = pair2[k];
}
}
}
if(char1 != NULL && char2 != NULL && x1 !=NULL && x2 != NULL)
{
for (int m = 0; m <= size m++)
{
if (char1 == m;)
{
x1 = m;
}
}
for (int n = 0; n <= size n++)
{
if (char2 == n)
{
x2 = n;
}
}
}
}
The end goal would be to have x1, x2, y1, and y2 with their respective values.
Keep in mind I am not allowed to have any external libraries.
It's not clear what exactly you want to achieve, but here are some pointers to get you started:
The while loop will never end because you're setting goodInput to false on quit which lets the loop continue.
The code probably does not even compile? You are missing a curly closing brace..
You are initializing pair1 and pair2 to empty strings but never change them again, so they will never contain any real information about your moves
maybe what you really want is to split up rawMove into the pair1 and pair2 substrings first?
Since this is a homework - and you're supposed to learn from those (right?) - I'm not going to give you the complete answer, but rather something like a recipe:
Use std::istream::getline(char*, std::streamsize s) to read a whole line from std::cin. Make sure you allocate a buffer large enough to hold the expected input (including the terminating null character) plus some more for invalid characters. After the call, check the failbit (input was too long) and the eofbit (hit the end-of-input) of the std::cin stream and handle those cases. Construct a std::string from the buffer if there was no error or EOF has not been reached.
Write a character-classification function (e.g. call it isAlNum(char c)) that returns true if the char argument is alpha-numeric, and false otherwise.
Combine std::string::erase(), std::remove_if(), std::not1(), std::ptr_fun() and your function isAlNum() to sanitise the input string.
Write a function that validates and parses the coordinates from the sanitised input string and call it with the sanitised input string.
Wrap the whole thing in an appropriate while() loop.
This should get you started in the right direction. Of course, if you're allowed to use C++11 features and you know how to write good regular expressions, by all means, use the <regex> header instead of doing the parsing manually.