Out of state State Machine

Discussion in 'Programmer's Corner' started by nanobyte, Mar 15, 2005.

  1. nanobyte

    Thread Starter Senior Member

    May 26, 2004
    118
    1
    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.
     
  2. Brandon

    Senior Member

    Dec 14, 2004
    306
    0
    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')
     
  3. nanobyte

    Thread Starter Senior Member

    May 26, 2004
    118
    1
    :) 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:
     
  4. nanobyte

    Thread Starter Senior Member

    May 26, 2004
    118
    1
    :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:
     
  5. Brandon

    Senior Member

    Dec 14, 2004
    306
    0
    FLURFF...

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

    Senior Member

    Dec 14, 2004
    306
    0
    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.
     
  7. nanobyte

    Thread Starter Senior Member

    May 26, 2004
    118
    1
    :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:
     
  8. Brandon

    Senior Member

    Dec 14, 2004
    306
    0
    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.
     
  9. nanobyte

    Thread Starter Senior Member

    May 26, 2004
    118
    1
    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?
     
  10. Brandon

    Senior Member

    Dec 14, 2004
    306
    0
    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();
     
  11. nanobyte

    Thread Starter Senior Member

    May 26, 2004
    118
    1
    I tried your suggestion by testing it out with state1:

    Code ( (Unknown Language)):
    1.  
    2. //wannabe engineer
    3.  
    4. #include<iostream>
    5. #include<conio.h>
    6. #include<string.h>
    7. #pragma hdrstop
    8. using namespace std;
    9.  
    10.  
    11. /*program will:
    12. 1. tell the user that it is conducting a state machine test
    13. 2. prompt the user to enter the first state
    14. 3. when the user presses '1' and only '1' go to the first state
    15. 4. when the user presses '2'and only '2' while the first state is in progress go to the second state
    16. 5. when the users presses '3' and only '3' while the second state is in progress go to the third state
    17. 6. when the users press '4' and only '4' while the third state is in progress go to the fouth state
    18. 7. when the users press '5' and only '5' while the fourth state is in progress go to the fifth state and then end
    19. 8. within any state, if 'Q' or 'q' is pressed the program will exit
    20. */
    21.  
    22.  
    23. void myHeader();
    24. void startup(void);
    25. void state1(void);
    26. void state2(void);
    27. void state3(void);
    28. void state4(void);
    29. void finalstate();
    30. void finishup();
    31.  
    32.  
    33.  
    34. void myHeader()
    35. {
    36.  cout <<"\nwannabe engineer\n";
    37. }
    38.  
    39.  
    40.  
    41. string response;
    42.  
    43.  
    44. void startup(void)
    45. {
    46.  cout <<"\nThis is a state machine test\n";
    47.  cout <<"\n\nPress 1 to go to the first state\n";
    48. }
    49.  
    50.  
    51.  
    52. /*Wait for key press. If the key press is not equal to the specified value
    53. and is not 'Q' or 'q' then print out "wrong key". If the key press is equal to
    54. the specified value go to next state else. If the key pressis equal to 'Q' or
    55. 'q' exit.*/
    56.  
    57. void state1(void)
    58. {
    59.  do{
    60.   cin >> response;
    61.   clrscr();
    62.  
    63.   if(response=='1')
    64.    cout <<"\nYou're in state 1. Press 2 to go to state 2 or Q or q to quit.\n";
    65.  
    66.    if(response!='1' && response!='Q' && response!='q' || strlen(response)>1)
    67.    cout <<"\nWrong key, try again\n";
    68.  
    69.    if(response=='Q' || response=='q')
    70.     exit(0);
    71.  
    72.    }while(response!='1'); //end of do/while
    73. }//end of state1
    74.  
    75.  
    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'
     
  12. nanobyte

    Thread Starter Senior Member

    May 26, 2004
    118
    1
    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:

    Code ( (Unknown Language)):
    1. //wannabe engineer
    2.  
    3. #include<iostream>
    4. #include<conio.h>
    5. #include<cstring>
    6. #pragma hdrstop
    7. using namespace std;
    8.  
    9.  
    10. /*program will:
    11. 1. tell the user that it is conducting a state machine test
    12. 2. prompt the user to enter the first state
    13. 3. when the user presses '1' and only '1' go to the first state
    14. 4. when the user presses '2'and only '2' while the first state is in progress go to the second state
    15. 5. when the users presses '3' and only '3' while the second state is in progress go to the third state
    16. 6. when the users press '4' and only '4' while the third state is in progress go to the fouth state
    17. 7. when the users press '5' and only '5' while the fourth state is in progress go to the fifth state and then end
    18. 8. within any state, if 'Q' or 'q' is pressed the program will exit
    19. */
    20.  
    21.  
    22. void myHeader();
    23. void startup(void);
    24. void state1(void);
    25. void state2(void);
    26. void state3(void);
    27. void state4(void);
    28. void finalstate();
    29. void finishup();
    30.  
    31.  
    32.  
    33. void myHeader()
    34. {
    35.  cout <<"\nwannabe engineer\n";
    36. }
    37.  
    38.  
    39.  
    40. strlen response.c_str()
    41.  
    42.  
    43. void startup(void)
    44. {
    45.  cout <<"\nThis is a state machine test\n";
    46.  cout <<"\n\nPress 1 to go to the first state\n";
    47. }
    48.  
    49.  
    50.  
    51. /*Wait for key press. If the key press is not equal to the specified value
    52. and is not 'Q' or 'q' then print out "wrong key". If the key press is equal to
    53. the specified value go to next state else. If the key pressis equal to 'Q' or
    54. 'q' exit.*/
    55.  
    56. void state1(void)
    57. {
    58.  do{
    59.   cin >> response;
    60.   clrscr();
    61.  
    62.   if(response=='1')
    63.    cout <<"\nYou're in state 1. Press 2 to go to state 2 or Q or q to quit.\n";
    64.  
    65.    if(response!='1' && response!='Q' && response!='q' || strlen(response) >1 )
    66.    cout <<"\nWrong key, try again\n";
    67.  
    68.    if(response=='Q' || response=='q')
    69.     exit(0);
    70.  
    71.    }while(response!='1'); //end of do/while
    72. }//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
     
  13. Brandon

    Senior Member

    Dec 14, 2004
    306
    0
    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.
     
  14. nanobyte

    Thread Starter Senior Member

    May 26, 2004
    118
    1
    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 .*

    Code ( (Unknown Language)):
    1.  
    2. //wannabe engineer
    3.  
    4. #include<iostream>
    5. #include<conio.h>
    6. #include<string>
    7. #pragma hdrstop
    8. using namespace std;
    9.  
    10.  
    11. /*program will:
    12. 1. tell the user that it is conducting a state machine test
    13. 2. prompt the user to enter the first state
    14. 3. when the user presses '1' and only '1' go to the first state
    15. 4. when the user presses '2'and only '2' while the first state is in progress go to the second state
    16. 5. when the users presses '3' and only '3' while the second state is in progress go to the third state
    17. 6. when the users press '4' and only '4' while the third state is in progress go to the fouth state
    18. 7. when the users press '5' and only '5' while the fourth state is in progress go to the fifth state and then end
    19. 8. within any state, if 'Q' or 'q' is pressed the program will exit
    20. */
    21.  
    22.  
    23. void myHeader();
    24. void startup(void);
    25. void state1(void);
    26. void state2(void);
    27. void state3(void);
    28. void state4(void);
    29. void finalstate();
    30. void finishup();
    31.  
    32.  
    33.  
    34. void myHeader()
    35. {
    36.  cout <<"\nwannabe engineer\n";
    37. }
    38.  
    39.  
    40. char response;
    41.  
    42.  
    43. void startup(void)
    44. {
    45.  cout <<"\nThis is a state machine test\n";
    46.  cout <<"\n\nPress 1 to go to the first state\n";
    47. }
    48.  
    49.  
    50.  
    51. /*Wait for key press. If the key press is not equal to the specified value
    52. and is not 'Q' or 'q' then print out "wrong key". If the key press is equal to
    53. the specified value go to next state else. If the key pressis equal to 'Q' or
    54. 'q' exit.*/
    55.  
    56. void state1(void)
    57. {
    58.  do{
    59.   cin >> response;
    60.   clrscr();
    61.  
    62.   if(response=='1')
    63.    cout <<"\nYou're in state 1. Press 2 to go to state 2 or Q or q to quit.\n";
    64.  
    65.    if(response!='1' && response!='Q' && response!='q' || response.length() > 1) --------ERROR HERE
    66.    cout <<"\nWrong key, try again\n";
    67.  
    68.    if(response=='Q' || response=='q')
    69.     exit(0);
    70.  
    71.    }while(response!='1'); //end of do/while
    72. }//end of state1
    73.  
    74.  
     
  15. nanobyte

    Thread Starter Senior Member

    May 26, 2004
    118
    1
    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.

    Code ( (Unknown Language)):
    1. //---------------------------------------------------------------------------
    2. //wannabe engineer
    3.  
    4. #include<iostream>
    5. #include<conio.h>
    6. #include<string>
    7. #pragma hdrstop
    8. #include "statetestmyHeader.h"
    9. using namespace std;
    10. //---------------------------------------------------------------------------
    11.  
    12. #pragma argsused
    13. void myHeader();
    14. void startup();
    15. void state1();
    16. void state2();
    17. void state3();
    18. void state4();
    19. void finalstate();
    20. void finishup();
    21. int main()
    22. {
    23.  myHeader();
    24.  //do{
    25.  startup();
    26.  state1();
    27.  state2();
    28.  state3();
    29.  state4();
    30.  finalstate();
    31.  finishup();
    32.  //}while(response!='Q'&&response!='q');
    33.  
    34.  cin.ignore(1);
    35.  cin.get();
    36.  
    37.  
    38.     return 0;
    39.  
    40. }
    41. //---------------------------------------------------------------------------
    42.  
    43.  
    44.  
    45.  
    46.  
    47.  
    48.  
    49.  
    50.  
    51.  
    52.  
    53. //wannabe engineer
    54.  
    55. #include<iostream>
    56. #include<conio.h>
    57. #include<string>
    58. #pragma hdrstop
    59. using namespace std;
    60.  
    61.  
    62. /*program will:
    63. 1. tell the user that it is conducting a state machine test
    64. 2. prompt the user to enter the first state
    65. 3. when the user presses '1' and only '1' go to the first state
    66. 4. when the user presses '2'and only '2' while the first state is in progress go
    67.   to the second state
    68. 5. when the users presses '3' and only '3' while the second state is in progress
    69.   go to the third state
    70. 6. when the users press '4' and only '4' while the third state is in progress go
    71.   to the fouth state
    72. 7. when the users press '5' and only '5' while the fourth state is in progress go
    73.   to the fifth state and then end
    74. 8. within any state, if 'Q' or 'q' is pressed the program will exit
    75. */
    76.  
    77.  
    78.  
    79. void myHeader();
    80. void startup(void);
    81. void state1(void);
    82. void state2(void);
    83. void state3(void);
    84. void state4(void);
    85. void finalstate();
    86. void finishup();
    87.  
    88.  
    89.  
    90. void myHeader()
    91. {
    92.  cout <<"\nwannabe engineer\n";
    93. }
    94.  
    95.  
    96. string response;
    97.  
    98.  
    99. void startup(void)
    100. {
    101.  cout <<"\nThis is a state machine test\n";
    102.  cout <<"\n\nPress 1 to go to the first state\n";
    103. }
    104.  
    105.  
    106.  
    107. /*Wait for key press. If the key press is not equal to the specified value
    108. and is not 'Q' or 'q' then print out "wrong key". If the key press is equal to
    109. the specified value go to next state else. If the key pressis equal to 'Q' or
    110. 'q' exit.*/
    111.  
    112. void state1(void)
    113. {
    114.  do{
    115.   cin >> response;
    116.   clrscr();
    117.  
    118.   if(response=="1")
    119.    cout <<"\nYou're in state 1. Press 2 to go to state 2 or Q or q to quit.\n";
    120.  
    121.    if(response!="1" && response!="Q" && response!="q")
    122.    cout <<"\nWrong key, try again\n";
    123.  
    124.    if(response=="Q" || response=="q")
    125.     exit(0);
    126.  
    127.    }while(response!="1"); //end of do/while
    128. }//end of state1
    129.  
    130.  
    131. /*While in current state wait for another key press.If the key press is not equal
    132. to the specified value and is not 'Q' or 'q' then print out "wrong key". If the
    133. key press is equal to the specified value go to next state else. If the key press
    134. is equal to 'Q' or 'q' exit.*/
    135.  
    136. void state2(void)
    137. {
    138.  do{
    139.   cin >> response;
    140.   clrscr();
    141.  
    142.   if(response=="2")
    143.    cout <<"\nYou're in state 2. Press 3 to go to state 3 or Q or q to quit.\n";
    144.  
    145.    if(response!="2" && response!="Q" && response!="q")
    146.    cout <<"\nWrong key, try again\n";
    147.  
    148.    if(response=="Q" || response=="q")
    149.     exit(0);
    150.  
    151.   }while(response!="2"); //end of do/while
    152. }//end of state2
    153.  
    154.  
    155. /*While in current state wait for another key press.If the key press is not equal
    156. to the specified value and is not 'Q' or 'q' then print out "wrong key". If the
    157. key press is equal to the specified value go to next state else. If the key press
    158. is equal to 'Q' or 'q' exit.*/
    159.  
    160. void state3(void)
    161. {
    162.  do{
    163.   cin >> response;
    164.   clrscr();
    165.  
    166.   if(response=="3")
    167.    cout <<"\nYou're in state 3. Press 4 to go to state 4 or Q or q to quit.\n";
    168.  
    169.    if(response!="3" && response!="Q" && response!="q")
    170.    cout <<"\nWrong key, try again\n";
    171.  
    172.    if(response=="Q" || response=="q")
    173.     exit(0);
    174.  
    175.   }while(response!="3"); //end of do/while
    176.  
    177. }//end of state3
    178.  
    179.  
    180. /*While in current state wait for another key press.If the key press is not equal
    181. to the specified value and is not 'Q' or 'q' then print out "wrong key". If the
    182. key press is equal to the specified value go to next state else. If the key press
    183. is equal to 'Q' or 'q' exit.*/
    184.  
    185. void state4(void)
    186. {
    187.  do{
    188.    cin >> response;
    189.    clrscr();
    190.  
    191.    if(response=="4")
    192.    cout <<"\nYou're in state 4. Press 5 to go to state 5 or Q or q to quit.\n";
    193.  
    194.    if(response!="4" && response!="Q" && response!="q")
    195.    cout <<"\nWrong key, try again\n";
    196.  
    197.    if(response=="Q" || response=="q")
    198.     exit(0);
    199.  
    200.   }while(response!="4"); //end of do/while
    201.  
    202. }//end of state4
    203.  
    204.  
    205. /*While in current state wait for another key press.If the key press is not equal
    206. to the specified value and is not 'Q' or 'q' then print out "wrong key". If the
    207. key press is equal to the specified value go to next state else. If the key press
    208. is equal to 'Q' or 'q' exit.*/
    209.  
    210. void finalstate(void)
    211. {
    212.  do{
    213.   cin >> response;
    214.   clrscr();
    215.  
    216.   if(response=="5")
    217.    cout <<"\nYou're in state 5, the final state. Press Q or q to quit.\n";
    218.  
    219.    if(response!="5" && response!="Q" && response!="q")
    220.    cout <<"\nWrong key, try again\n";
    221.  
    222.    if(response=="Q" || response=="q")
    223.     exit(0);
    224.  
    225.   }while(response!="5"); //end of do/while
    226.  
    227. }//end of state5
    228.  
    229.  
    230.  
    231. /*Wait for key press. If the key press is not equal to the specified
    232. character('Q' or 'q') then print out "wrong key". If the key press is equal to
    233. the character('Q' or 'q') print "This has been a successfully state machine test"
    234. and quit on the next key press by the user.*/
    235.  
    236. void finishup(void)
    237. {
    238.  do{
    239.   cin >> response;
    240.   clrscr();
    241.  
    242.   if(response=="Q" || response=="q")
    243.    cout <<"\nThis has been a successfully state machine test.\n";
    244.  
    245.   if(response!="Q" && response!="q")
    246.    cout <<"\nWrong key, try again\n";
    247.  
    248.  }while (response!="Q" && response!="q");//end of do/while
    249.  
    250. }
     
  16. Brandon

    Senior Member

    Dec 14, 2004
    306
    0
    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.
     
Loading...