Last active
          April 12, 2021 16:35 
        
      - 
      
- 
        Save JettMonstersGoBoom/6f03d5435c2e156e20cb39a59f4b12d8 to your computer and use it in GitHub Desktop. 
    Simple Finite State machine in C
  
        
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | // | |
| // simple finite state machine in C | |
| // | |
| #include <stdio.h> | |
| #include <stdint.h> | |
| #include <stdlib.h> | |
| // for this example lets have N objects/entities | |
| #define MAX_ENTS 4 | |
| // types | |
| typedef struct entity_t | |
| { | |
| int (*current_state)(struct entity_t *self); | |
| int ID; | |
| int counter; | |
| } entity_t; | |
| typedef int (*function_pointer_t)(entity_t *); | |
| // return types to handle | |
| enum return_codes { OK, FAIL, REPEAT, ATTACK}; | |
| // transition type | |
| struct transition { | |
| function_pointer_t source_state; | |
| enum return_codes ret_code; | |
| function_pointer_t destination_state; | |
| }; | |
| // possible state functions | |
| int OnEnterState(entity_t *self); | |
| int OnIdleState(entity_t *self); | |
| int OnWalkState(entity_t *self); | |
| int OnAttackState(entity_t *self); | |
| int OnExitState(entity_t *self); | |
| // transition from State if code == state to State | |
| struct transition state_transitions[] = { | |
| // if source is entry , we can respond to OK or FAIL states | |
| {OnEnterState, OK, OnIdleState}, | |
| {OnEnterState, FAIL, OnExitState}, | |
| // if attack state, respond to OK or FAIL | |
| {OnAttackState,OK, OnWalkState}, | |
| {OnAttackState,FAIL, OnIdleState}, | |
| // if idle state, can repeat, ok , fail , or attack | |
| {OnIdleState, OK, OnWalkState}, | |
| {OnIdleState, FAIL, OnExitState}, | |
| {OnIdleState, REPEAT, OnIdleState}, | |
| {OnIdleState, ATTACK, OnAttackState}, | |
| // if walk state, can repeat, ok, or fail | |
| {OnWalkState, OK, OnExitState}, | |
| {OnWalkState, FAIL, OnExitState}, | |
| {OnWalkState, REPEAT, OnIdleState}, | |
| {NULL,OK,NULL} | |
| }; | |
| // example states | |
| int OnEnterState(entity_t *self) | |
| { | |
| printf("OnEnterState %x\n",self); | |
| self->counter = 5; | |
| return OK; | |
| } | |
| // idle count down and attack | |
| int OnIdleState(entity_t *self) | |
| { | |
| printf("OnIdleState(%d) %d\n",self->ID,self->counter); | |
| if (self->counter!=0) | |
| { | |
| self->counter--; | |
| return REPEAT; | |
| } | |
| self->counter=1+(rand()&7); | |
| return ATTACK; | |
| } | |
| // another state | |
| int OnWalkState(entity_t *self) | |
| { | |
| printf("OnWalkState(%d)\n",self->ID); | |
| return OK; | |
| } | |
| int OnExitState(entity_t *self) | |
| { | |
| printf("OnExitState(%d) %x\n",self->ID,self); | |
| return OK; | |
| } | |
| int OnAttackState(entity_t *self) | |
| { | |
| printf("OnAttackState(%d)\n",self->ID); | |
| if (rand()<64) | |
| return OK; | |
| return FAIL; | |
| } | |
| int OnInvalidState(entity_t *self) | |
| { | |
| printf("OnInvalidState\n"); | |
| return FAIL; | |
| } | |
| function_pointer_t SearchTransitions(function_pointer_t cur_state, enum return_codes rc) | |
| { | |
| function_pointer_t next_state; | |
| next_state = OnInvalidState; | |
| // Searching loop | |
| for(int i=0; state_transitions[i].source_state!=NULL; i++) | |
| { | |
| if ((state_transitions[i].source_state == cur_state) && (state_transitions[i].ret_code == rc)) | |
| { | |
| next_state = state_transitions[i].destination_state; | |
| break; | |
| } | |
| } | |
| return(next_state); | |
| } | |
| int main(int argc, char *argv[]) | |
| { | |
| enum return_codes rc; | |
| entity_t entities[MAX_ENTS]; | |
| for (int q=0;q<MAX_ENTS;q++) | |
| { | |
| entities[q].ID = q; | |
| entities[q].current_state = &OnEnterState; | |
| } | |
| for (;;) { | |
| for (int q=0;q<MAX_ENTS;q++) | |
| { | |
| rc = entities[q].current_state(&entities[q]); | |
| if (OnExitState == (function_pointer_t)entities[q].current_state) | |
| exit(0); | |
| entities[q].current_state = SearchTransitions(entities[q].current_state, rc); | |
| } | |
| } | |
| return 0; | |
| } | 
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment