Out of state State Machine

Thread Starter

nanobyte

Joined May 26, 2004
120
I am trying to make a state machine on Borland C++ Builder 6. There are 5 states (1,2,3,4,5). I want the states in ascending order so for example if the user is in state1 and tries to go to state3 the program will print "wrong key, try again". Once the users presses the right key it should go on to the next state. The problem is the last funtion finishup it's not working properly. I want the user to only have the opinion of pressing 'Q' or 'q' to quit the program while in the final state(state 5). The program should then conduct one more print out and quit. The finishup function is suppose to:

1. Read the response and see if it is equal to 'Q' or 'q'
2. If the response is equal to one of the two characters the program will print "This has been a successful state machine test." and quit.
3. If it is not equal to one of the two characters the program will print "wrong key, try again"

The if statement for an incorrect key press is working properly, but the if statement for a correct key press isn't. The if statement for the correct key press keeps printing out its sentence and the sentence for an incorrect key press and also the program won't quit.

The first bit of code is the program file and the code about 10-11 lines below that is the header file. Please somebody help me out; I'm at a lost. I don't what the problem is.
 

Brandon

Joined Dec 14, 2004
306
Originally posted by nanobyte@Mar 15 2005, 09:54 AM
I am trying to make a state machine on Borland C++ Builder 6. There are 5 states (1,2,3,4,5). I want the states in ascending order so for example if the user is in state1 and tries to go to state3 the program will print "wrong key, try again". Once the users presses the right key it should go on to the next state. The problem is the last funtion finishup it's not working properly. I want the user to only have the opinion of pressing 'Q' or 'q' to quit the program while in the final state(state 5). The program should then conduct one more print out and quit. The finishup function is suppose to:

1. Read the response and see if it is equal to 'Q' or 'q'
2. If the response is equal to one of the two characters the program will print "This has been a successful state machine test." and quit.
3. If it is not equal to one of the two characters the program will print "wrong key, try again"

The if statement for an incorrect key press is working properly, but the if statement for a correct key press isn't. The if statement for the correct key press keeps printing out its sentence and the sentence for an incorrect key press and also the program won't quit.

The first bit of code is the program file and the code about 10-11 lines below that is the header file. Please somebody help me out; I'm at a lost. I don't what the problem is.
[post=6101]Quoted post[/post]​
Your going to kick yourself.

void finishup(void)
{
do{
cin >> response;
clrscr();

if(response=='Q'||response=='q')
cout <<"\nThis has been a successfully state machine test.\n";

if(response!='Q'||response!='q')
cout <<"\nWrong key, try again\n";

}while (response!='Q'||response!='q');//end of do/while <-- PROBLEM

}

ok.. I input Q
while (response!='Q'||response!='q')
While (False or True) so its true

Now I input q
while (response!='Q'||response!='q')
While (True or False) so its true

i think you want this
while (response!='Q'&&response!='q')
 

Thread Starter

nanobyte

Joined May 26, 2004
120
:) Thanks Brandon. I don't know where my mind was at. But there is still something wrong with the finishup function. For some reason it's printing out the c-out message for both if statements even though only one condition is being meet. :huh:
 

Thread Starter

nanobyte

Joined May 26, 2004
120
:D Never mind I see what's going on. I was making the same mistake in the second if statement as I was with the while statement. Now I want the user to be able to quit the program with a response of 'Q' or 'q' while in any of the states. How would I go able doing that? :huh:
 

Brandon

Joined Dec 14, 2004
306
Originally posted by nanobyte@Mar 17 2005, 09:16 AM
:) Thanks Brandon. I don't know where my mind was at. But there is still something wrong with the finishup function. For some reason it's printing out the c-out message for both if statements even though only one condition is being meet. :huh:
[post=6149]Quoted post[/post]​
FLURFF...

Heh.. you must have posted while I was writing this post..
 

Brandon

Joined Dec 14, 2004
306
Originally posted by nanobyte@Mar 17 2005, 10:38 AM
:D Never mind I see what's going on. I was making the same mistake in the second if statement as I was with the while statement. Now I want the user to be able to quit the program with a response of 'Q' or 'q' while in any of the states. How would I go able doing that? :huh:
[post=6152]Quoted post[/post]​
You would probably want to take the cin out of the individual functions and make a seperate function just for user input. Maybe something like this.

char GetInput(void)
{
char x;
cin >> x;
return x;
}


int main()
{
char Input='0';

void myHeader();
void startup(void);

do
{

do
{
OldInput=Input;
Input=GetInput();
} while !(Input==OldInput+1 || Inpu=t='Q' || Input=='q')

switch (Input)
{
case '1': State1();break;
case '2': State2();break;
case '3': State3();break;
case '4': State4();break;
case 'Q': break;
}

} while !(Input=='Q' || Input=='q')

//Q or q is entered, we exit the while loop
finalstate();
finishup();


Proably a few compile errors in here, but you probably see the direction I was shooting for.
 

Thread Starter

nanobyte

Joined May 26, 2004
120
:lol: I did it! The user can now quit inside of any state by pressing 'Q' or 'q'. I pulled it off by replacing return; with exit(0); in a new if statement that I added in states1-5. There is one little thing that is nagging me now. <_< The fact that the user can go state to state if they put in multiple numbers at a time. For example, let's say that I'm in state1 and I press 67892. The program will still go to state2. I guess because it's reading each digit as an indepedent input. I want the program to only respond to an input of single digit numbers. If the input is a multi-digit number like 235 I want the program to print "Wrong key, try again". Get where I'm coming from? If it's possible, how could I make that happen? :huh:
 

Brandon

Joined Dec 14, 2004
306
Originally posted by nanobyte@Mar 22 2005, 11:04 AM
:lol: I did it! The user can now quit inside of any state by pressing 'Q' or 'q'. I pulled it off by replacing return; with exit(0); in a new if statement that I added in states1-5. There is one little thing that is nagging me now. <_< The fact that the user can go state to state if they put in multiple numbers at a time. For example, let's say that I'm in state1 and I press 67892. The program will still go to state2. I guess because it's reading each digit as an indepedent input. I want the program to only respond to an input of single digit numbers. If the input is a multi-digit number like 235 I want the program to print "Wrong key, try again". Get where I'm coming from? If it's possible, how could I make that happen? :huh:
[post=6291]Quoted post[/post]​
I belived it it caused by your definition of repsonse.

You have signified that repsonse is a single char input word, yet your putting in more than 1 character at a time. Thats creates strange runtime issues which a compiler can not catch since it does not know the users input.

I would make this change

char response[50];

allows user to input upto 50 chars in a single input.

Then, all you do is compare response[1] with 'Q", '1', '2', etc, since all that really matters is the first character of the input. i.e., your just ignoring what ever comes after that first member of the array. Albeit its not a perfect fix, but it works and its simple.

A little more crash proof method would be to use the string.h header and declare response a string so that its dynamic length can change with the users input. Convert to a char array and take the first character as well.

You could also add into the IF statement a strlen function call (got to be useing string.h) and if the length of the input is greater than 1, its a bad input.
 

Thread Starter

nanobyte

Joined May 26, 2004
120
I like the last suggestion involving adding a strlen function call to the if statement. I think I'll go with that, but I don't know how to implement it into my code. I'm very new to C++ so forgive for my dull-wittedness. Could you give my me an example through code of how I would go about it?
 

Brandon

Joined Dec 14, 2004
306
Originally posted by nanobyte@Mar 23 2005, 11:08 AM
I like the last suggestion involving adding a strlen function call to the if statement. I think I'll go with that, but I don't know how to implement it into my code. I'm very new to C++ so forgive for my dull-wittedness. Could you give my me an example through code of how I would go about it?
[post=6319]Quoted post[/post]​
You first need to add the header to the program

<string.h>

then, declare response a string and not a char

string response;

i believe you can just do this. I'm not at my pc to pull up the help file, but I believe it only takes a single input and returns its length.

if (strlen(response)>1)
BadResponseFunc();
 

Thread Starter

nanobyte

Joined May 26, 2004
120
I tried your suggestion by testing it out with state1:

Rich (BB code):
//wannabe engineer

#include<iostream>
#include<conio.h>
#include<string.h>
#pragma hdrstop
using namespace std;


/*program will:
1. tell the user that it is conducting a state machine test
2. prompt the user to enter the first state
3. when the user presses '1' and only '1' go to the first state
4. when the user presses '2'and only '2' while the first state is in progress go to the second state
5. when the users presses '3' and only '3' while the second state is in progress go to the third state
6. when the users press '4' and only '4' while the third state is in progress go to the fouth state
7. when the users press '5' and only '5' while the fourth state is in progress go to the fifth state and then end
8. within any state, if 'Q' or 'q' is pressed the program will exit
*/


void myHeader();
void startup(void);
void state1(void);
void state2(void);
void state3(void);
void state4(void);
void finalstate();
void finishup();



void myHeader()
{
 cout <<"\nwannabe engineer\n";
}



string response;


void startup(void)
{
 cout <<"\nThis is a state machine test\n";
 cout <<"\n\nPress 1 to go to the first state\n";
}



/*Wait for key press. If the key press is not equal to the specified value
and is not 'Q' or 'q' then print out "wrong key". If the key press is equal to
the specified value go to next state else. If the key pressis equal to 'Q' or
'q' exit.*/

void state1(void)
{
 do{
  cin >> response;
  clrscr();

  if(response=='1')
   cout <<"\nYou're in state 1. Press 2 to go to state 2 or Q or q to quit.\n";

   if(response!='1' && response!='Q' && response!='q' || strlen(response)>1)
   cout <<"\nWrong key, try again\n";

   if(response=='Q' || response=='q')
    exit(0);

   }while(response!='1'); //end of do/while
}//end of state1
I got a whole bunch of errors. Mainly this one:

[C++ Error] statetestmyHeader.h(62): E2094 'operator==' not implemented in type 'string' for arguments of type 'char'
 

Thread Starter

nanobyte

Joined May 26, 2004
120
I went to www.cpp-home.com and posted the problem there. I got this suggestion:

"It should be <string>, not <string.h>, which is deprecated. I haven't tested it, but I think strlen is for C-style strings only, so you'd need to call strlen(response.c_str()). As for BadResponseFunc, what is it? I couldn't see it in a quick skim-read of code earlier in this topic. By the naming convention, I guess it might be some kind of Windows function? It will need declaring/defining somewhere though, if that hasn't already been done."

I tried this:

Rich (BB code):
//wannabe engineer

#include<iostream>
#include<conio.h>
#include<cstring>
#pragma hdrstop
using namespace std;


/*program will:
1. tell the user that it is conducting a state machine test
2. prompt the user to enter the first state
3. when the user presses '1' and only '1' go to the first state
4. when the user presses '2'and only '2' while the first state is in progress go to the second state
5. when the users presses '3' and only '3' while the second state is in progress go to the third state
6. when the users press '4' and only '4' while the third state is in progress go to the fouth state
7. when the users press '5' and only '5' while the fourth state is in progress go to the fifth state and then end
8. within any state, if 'Q' or 'q' is pressed the program will exit
*/


void myHeader();
void startup(void);
void state1(void);
void state2(void);
void state3(void);
void state4(void);
void finalstate();
void finishup();



void myHeader()
{
 cout <<"\nwannabe engineer\n";
}



strlen response.c_str()


void startup(void)
{
 cout <<"\nThis is a state machine test\n";
 cout <<"\n\nPress 1 to go to the first state\n";
}



/*Wait for key press. If the key press is not equal to the specified value
and is not 'Q' or 'q' then print out "wrong key". If the key press is equal to
the specified value go to next state else. If the key pressis equal to 'Q' or
'q' exit.*/

void state1(void)
{
 do{
  cin >> response;
  clrscr();

  if(response=='1')
   cout <<"\nYou're in state 1. Press 2 to go to state 2 or Q or q to quit.\n";

   if(response!='1' && response!='Q' && response!='q' || strlen(response) >1 )
   cout <<"\nWrong key, try again\n";

   if(response=='Q' || response=='q')
    exit(0);

   }while(response!='1'); //end of do/while
}//end of state1
I don't know if I'm on the right track or not, but I got only three errors:

[C++ Error] statetestmyHeader.h(40): E2356 Type mismatch in redeclaration of 'strlen(const char *)'

[C++ Error] statetestmyHeader.h(40): E2449 Size of 'strlen(const char *)' is unknown or zero

[C++ Error] statetestmyHeader.h(40): E2141 Declaration syntax error
 

Brandon

Joined Dec 14, 2004
306
The '1' is a char and not a string so you were comparing a string and a char which you can't do. Thats where one of the main errors is coming from.

You need to set up a series of string definitions.

string StateOne = '1'
string StateTwo = '2'
string Quit = 'Q'
string Quit2 = 'q'

etc.

then you can compare Response to StateOne since now both are considered strings and so on.

The whole string or string.h depends on your compiler. If you use VC++6.0 you use string.h if your using VC++7.0 (.NET) you use string i believe.

You really don't need to use strlen, was just a suggestion I threw your way. You could do it with just the if statements and it should still work out just fine.

Sorry, didn't mean to compicate things.
 

Thread Starter

nanobyte

Joined May 26, 2004
120
A person at cpp-home.com gave me alot of interesting info:

"I haven't followed this entire thread but I'd like to point out a few things. The person at allaboutcircuits and a few of the people here have been giving helpful but slightly incorrect advice.

To use strlen you must #include <string.h> or #include <cstring>.

Notice that I said <string.h> or <cstring>. The <string> header is for the STL string class which is completely separate from the C-style string functions found in <string.h> and <cstring>. Also, <string.h> is deprecated in favor of <cstring> when using C style string functions like strlen.

If you want to use a string, you must #include <string>. To find the length of a string, use the length() member function.

If response is a string variable, there is no reason to try strlen(response) or strlen(response.c_str()). The string has a function called length that returns its length. You want (response.length() > 1)."


I tried the suggestion he gave me in - and the program is now down to one error which is:

[C++ Error] statetestmyHeader.h(64): E2294 Structure required on left side of . or .*

Rich (BB code):
//wannabe engineer 

#include<iostream> 
#include<conio.h> 
#include<string> 
#pragma hdrstop 
using namespace std; 


/*program will: 
1. tell the user that it is conducting a state machine test 
2. prompt the user to enter the first state 
3. when the user presses '1' and only '1' go to the first state 
4. when the user presses '2'and only '2' while the first state is in progress go to the second state 
5. when the users presses '3' and only '3' while the second state is in progress go to the third state 
6. when the users press '4' and only '4' while the third state is in progress go to the fouth state 
7. when the users press '5' and only '5' while the fourth state is in progress go to the fifth state and then end 
8. within any state, if 'Q' or 'q' is pressed the program will exit 
*/ 


void myHeader(); 
void startup(void); 
void state1(void); 
void state2(void); 
void state3(void); 
void state4(void); 
void finalstate(); 
void finishup(); 



void myHeader() 
{ 
 cout <<"\nwannabe engineer\n"; 
} 


char response; 


void startup(void) 
{ 
 cout <<"\nThis is a state machine test\n"; 
 cout <<"\n\nPress 1 to go to the first state\n"; 
} 



/*Wait for key press. If the key press is not equal to the specified value 
and is not 'Q' or 'q' then print out "wrong key". If the key press is equal to 
the specified value go to next state else. If the key pressis equal to 'Q' or 
'q' exit.*/ 

void state1(void) 
{ 
 do{ 
  cin >> response; 
  clrscr(); 

  if(response=='1') 
   cout <<"\nYou're in state 1. Press 2 to go to state 2 or Q or q to quit.\n"; 

   if(response!='1' && response!='Q' && response!='q' || response.length() > 1) --------ERROR HERE
   cout <<"\nWrong key, try again\n"; 

   if(response=='Q' || response=='q') 
    exit(0); 

   }while(response!='1'); //end of do/while 
}//end of state1
 

Thread Starter

nanobyte

Joined May 26, 2004
120
I Got the programing working. B) Just had to change char response to string response and put the characters I was using in the if statements in double quotes instead of single quotes.

Rich (BB code):
//---------------------------------------------------------------------------
//wannabe engineer

#include<iostream>
#include<conio.h>
#include<string>
#pragma hdrstop
#include "statetestmyHeader.h"
using namespace std;
//---------------------------------------------------------------------------

#pragma argsused
void myHeader();
void startup();
void state1();
void state2();
void state3();
void state4();
void finalstate();
void finishup();
int main()
{
 myHeader();
 //do{
 startup();
 state1();
 state2();
 state3();
 state4();
 finalstate();
 finishup();
 //}while(response!='Q'&&response!='q');

 cin.ignore(1);
 cin.get();


    return 0;

}
//---------------------------------------------------------------------------











//wannabe engineer

#include<iostream>
#include<conio.h>
#include<string>
#pragma hdrstop
using namespace std;


/*program will:
1. tell the user that it is conducting a state machine test
2. prompt the user to enter the first state
3. when the user presses '1' and only '1' go to the first state
4. when the user presses '2'and only '2' while the first state is in progress go
  to the second state
5. when the users presses '3' and only '3' while the second state is in progress
  go to the third state
6. when the users press '4' and only '4' while the third state is in progress go
  to the fouth state
7. when the users press '5' and only '5' while the fourth state is in progress go
  to the fifth state and then end
8. within any state, if 'Q' or 'q' is pressed the program will exit
*/



void myHeader();
void startup(void);
void state1(void);
void state2(void);
void state3(void);
void state4(void);
void finalstate();
void finishup();



void myHeader()
{
 cout <<"\nwannabe engineer\n";
}


string response;


void startup(void)
{
 cout <<"\nThis is a state machine test\n";
 cout <<"\n\nPress 1 to go to the first state\n";
}



/*Wait for key press. If the key press is not equal to the specified value
and is not 'Q' or 'q' then print out "wrong key". If the key press is equal to
the specified value go to next state else. If the key pressis equal to 'Q' or
'q' exit.*/

void state1(void)
{
 do{
  cin >> response;
  clrscr();

  if(response=="1")
   cout <<"\nYou're in state 1. Press 2 to go to state 2 or Q or q to quit.\n";

   if(response!="1" && response!="Q" && response!="q")
   cout <<"\nWrong key, try again\n";

   if(response=="Q" || response=="q")
    exit(0);

   }while(response!="1"); //end of do/while
}//end of state1


/*While in current state wait for another key press.If the key press is not equal
to the specified value and is not 'Q' or 'q' then print out "wrong key". If the
key press is equal to the specified value go to next state else. If the key press
is equal to 'Q' or 'q' exit.*/

void state2(void)
{
 do{
  cin >> response;
  clrscr();

  if(response=="2")
   cout <<"\nYou're in state 2. Press 3 to go to state 3 or Q or q to quit.\n";

   if(response!="2" && response!="Q" && response!="q")
   cout <<"\nWrong key, try again\n";

   if(response=="Q" || response=="q")
    exit(0);

  }while(response!="2"); //end of do/while
}//end of state2


/*While in current state wait for another key press.If the key press is not equal
to the specified value and is not 'Q' or 'q' then print out "wrong key". If the
key press is equal to the specified value go to next state else. If the key press
is equal to 'Q' or 'q' exit.*/

void state3(void)
{
 do{
  cin >> response;
  clrscr();

  if(response=="3")
   cout <<"\nYou're in state 3. Press 4 to go to state 4 or Q or q to quit.\n";

   if(response!="3" && response!="Q" && response!="q")
   cout <<"\nWrong key, try again\n";

   if(response=="Q" || response=="q")
    exit(0);

  }while(response!="3"); //end of do/while

}//end of state3


/*While in current state wait for another key press.If the key press is not equal
to the specified value and is not 'Q' or 'q' then print out "wrong key". If the
key press is equal to the specified value go to next state else. If the key press
is equal to 'Q' or 'q' exit.*/

void state4(void)
{
 do{
   cin >> response;
   clrscr();

   if(response=="4")
   cout <<"\nYou're in state 4. Press 5 to go to state 5 or Q or q to quit.\n";

   if(response!="4" && response!="Q" && response!="q")
   cout <<"\nWrong key, try again\n";

   if(response=="Q" || response=="q")
    exit(0);

  }while(response!="4"); //end of do/while

}//end of state4


/*While in current state wait for another key press.If the key press is not equal
to the specified value and is not 'Q' or 'q' then print out "wrong key". If the
key press is equal to the specified value go to next state else. If the key press
is equal to 'Q' or 'q' exit.*/

void finalstate(void)
{
 do{
  cin >> response;
  clrscr();

  if(response=="5")
   cout <<"\nYou're in state 5, the final state. Press Q or q to quit.\n";

   if(response!="5" && response!="Q" && response!="q")
   cout <<"\nWrong key, try again\n";

   if(response=="Q" || response=="q")
    exit(0);

  }while(response!="5"); //end of do/while

}//end of state5



/*Wait for key press. If the key press is not equal to the specified
character('Q' or 'q') then print out "wrong key". If the key press is equal to
the character('Q' or 'q') print "This has been a successfully state machine test"
and quit on the next key press by the user.*/

void finishup(void)
{
 do{
  cin >> response;
  clrscr();

  if(response=="Q" || response=="q")
   cout <<"\nThis has been a successfully state machine test.\n";

  if(response!="Q" && response!="q")
   cout <<"\nWrong key, try again\n";

 }while (response!="Q" && response!="q");//end of do/while

}
 

Brandon

Joined Dec 14, 2004
306
Heh...

Never claimed to be a programmer.

I just started using the string class at the time I posted here that you might want to give it a try. I just used it to make passing into my class functions a hell of alot easier than trying to do char arrays and anticipating a persons input.

Glad to see you got it working though.
 
Top