• Recent Tutorials

  • Tripping The Class Fantastic: State Machines

    Coding It Up
    So now you have a list of states, the transitions and triggers you can start writing.

    State Index Constants
    Code: [View]
    CONST
      STATE_NONE             = 0;
      STATE_INITIALISEMODEM  = 1;
      STATE_BEGINWAITING     = 2;
      STATE_WAITINGFORCALL   = 3;
      STATE_CALLDETECTED     = 4;
      STATE_CALLINPROGRESS   = 5;
      STATE_ENDCALL          = 6;
      STATE_CALLDISCONNECTED = 7;
    Main Loop
    Code: [View]
    state:=STATE_INITIALISEMODEM;
    nextState:=STATE_NONE;
    
    while (1=1) do
    begin
      case state of
        STATE_INITIALISEMODEM : begin
          modem.initialise;
          nextState:=STATE_BEGINWAITING;
        end;
    
        STATE_BEGINWAITING : begin
          modem.waitForCall;
          nextState:=STATE_WAITINGFORCALL;
        end;
    
        STATE_WAITINGFORCALL : begin
          if (modem.signalRingIndicator) then
          begin
            nextState:=STATE_CALLDETECTED;
          end;
        end;
    
        STATE_CALLDETECTED : begin
          modem.pickup;
          nextState:=STATE_CALLINPROGRESS;
        end;
    
        STATE_CALLINPROGRESS : begin
          if (not modem.signalCarrierDetect) then
          begin
            nextState:=STATE_CALLDISCONNECTED;
          end
          else
          begin
            if (modem.dataReady) then
            begin
              command:=modem.readString;
              processCommand(command,quit);
    
              if (quit) then
              begin
                nextState:=STATE_ENDCALL;
              end;
            end;
          end;
        end;
    
        STATE_ENDCALL : begin
          modem.hangUp;
          nextState:=STATE_INITIALISEMODEM;
        end;
    
        STATE_CALLDISCONNECTED : begin
          nextState:=STATE_INITIALISEMODEM;
        end;
      end;
    
      if (nextState<>STATE_NONE) then
      begin
        state:=nextState;
        nextState:=STATE_NONE;
      end;
    end;
    Some thoughts on this sample code...

    Hopefully it's easy to see that we can optimise some of the states. There are some states which just perform simple operations and then move on... this is only possible because we aren't worrying about responses to our commands. For example, STATE_INITIALISEMODEM and STATE_BEGINWAITING can be combined into a single state and STATE_CALLDISCONNECTED could be dropped entirely by simply having the code move to STATE_INITIALISEMODEM instead of STATE_CALLDISCONNECTED.

    And on the flipside, it is possible to split STATE_CALLINPROGRESS into two states. STATE_CALLINPROGRESS which would check the carrier detect signal and the data ready flag and a new state 'STATE_PROCESSINGCOMMAND' that simply read the command , processed it and then moved to either STATE_CALLINPROGRESS if the user didn't quit or STATE_ENDCALL if they did.

    Whether you make these changes is ultimately a judgement call. Personally I would happy with just making the state reduction optimisations highlighted first. I don't feel STATE_CALLINPROGRESS is too complex, but much more logic and flow in there and I would probably split it into a number of simpler states.

    If you are confident that you won't compromise the machine, you can make these sorts of optimisations during the design. If not, then leave the optimising until you've got the code.
    Comments 3 Comments
    1. Ñuño Martínez's Avatar
      Ñuño Martínez -
      Just did a very fast reading (titles and some of the code, not much more). Looks very interesting.

      I did my own state-machine library translating the one described in"Programming Game AI by Example". Your approach seems slightly different. I'll tell you once I read your tutorial in-deep and compare both ways.
    1. AthenaOfDelphi's Avatar
      AthenaOfDelphi -
      If anyone has downloaded the attachment, the file classBaseStateMachine.pas was missing. Sorry about that, thanks to d.spinetti for pointing out my mistake.
    1. Ñuño Martínez's Avatar
      Ñuño Martínez -
      Read. Your implementation is way different than the one described in"Programming Game AI by Example" but it's a nice approach.

      Thank-you.