C语言 状态机

早期看到的一个关于电梯状态机的模型

// Reference: 
// FSM: https://stackoverflow.com/questions/50165534/finite-state-machines-in-c
// C Enum: https://www.geeksforgeeks.org/enumeration-enum-c/

/* standard lib */
#include <stdio.h> // printf #include <stdbool.h> // bool for _Bool and true for 1
#include <conio.h> // for clrscr, and getch()
#include "stdlib.h" // for rand()
#include "math.h"

/* event array and enum below must be in sync! */
enum state_codes { _idle=0, _goingUp=1, _goingDown=2, _AtTop=3, _AtBottom=4,  _malfunction=5, _unexpected=6, _end=7 };
enum ret_codes   {   up=0,    down=1,      halt=2,   top=3,   bottom=4, fail=5, quit=6 };

enum state_codes x = _idle;

int target_floor_number = 8;
int current_floor_number = 1;
int accumulated_floor_number = 0;
#define TOP_FLOOR 9
#define BOTTOM_FLOOR 1

int event_idle(void){
    printf("Idle!\n");
    printf("Input target floor number in [1, 9] (which floor you want to go?): \n");
    target_floor_number = getch() - '0';

    if(current_floor_number < target_floor_number)
        return up;
    else if(current_floor_number > target_floor_number)
        return down;
    else if(current_floor_number == target_floor_number)
        return halt;
}
int event_goingUp(void){
    current_floor_number += 1;
    accumulated_floor_number += 1;
    printf("Going up! Floor number is %d\n", current_floor_number);

    if(accumulated_floor_number > 100)
        return fail;
    else if(TOP_FLOOR == current_floor_number)
        return top;
    else if(BOTTOM_FLOOR == current_floor_number)
        return bottom;
    else if(current_floor_number < target_floor_number)
        return up;
    else if(current_floor_number == target_floor_number)
        return halt;
    else
        return quit;
}
int event_goingDown(void){
    current_floor_number -= 1;
    accumulated_floor_number += 1;
    printf("Going down! Floor number is %d\n", current_floor_number);

    if(accumulated_floor_number > 100)
        return fail;
    else if(TOP_FLOOR == current_floor_number)
        return top;
    else if(BOTTOM_FLOOR == current_floor_number)
        return bottom;
    else if(current_floor_number > target_floor_number)
        return down;
    else if(current_floor_number == target_floor_number)
        return halt;
    else
        return quit;
}
int event_atTop(void){
    printf("At top! current_floor_number= %d\n", current_floor_number);
    printf("Input target floor number in [1, 9] (which floor you want to go?): \n");
    target_floor_number = getch() - '0';

    if(current_floor_number > target_floor_number)
        return down;
    else if(current_floor_number == target_floor_number)
        return halt;
}
int event_atBottom(void){
    printf("At Bottom! current_floor_number= %d\n", current_floor_number);
    printf("Input target floor number in [1, 9] (which floor you want to go?): \n");
    target_floor_number = getch() - '0';

    if(current_floor_number < target_floor_number)
        return up;
    else if(current_floor_number == target_floor_number)
        return halt;}

int event_malfunction(void){
    printf("Elevator needs maintanence!\n");
    printf("accumulated_floor_number = %d\n", accumulated_floor_number);
    return quit;
}
int event_end(void){
    printf("Exit!");
    return 0;
}
int event_unexpected(void){
    printf("Debug.");
    return quit;
}


int (* event[])(void) = { event_idle, event_goingUp, event_goingDown, event_atTop, event_atBottom, event_malfunction, event_unexpected, event_end };

// Nice, thanks for this. The only thing possible flaw here is that the lookup_transitions will likely be linear (O(n)) with this transition table datastructure. Its possible to make it better with multidimentional array - guaranteed O(1). Eg. the table can be represented as a multidimentional array where key is state and the value is an array where the key is the return code and value is the next state: int state_transitions[][3] = { [entry] = { foo, end, foo }, ... } /* ok, fail, repeat */    
int lookup_transitions[][7] = { 
                // return codes:
                //      up       down       halt          top         bottom         fail          quit
    [_idle]      = {_goingUp,    _goingDown,  _idle,     _unexpected, _unexpected,  _malfunction,  _end},
    [_goingUp]   = {_goingUp,    _unexpected, _idle,     _AtTop,      _AtBottom,    _malfunction,  _end},
    [_goingDown] = {_unexpected, _goingDown,  _idle,     _AtTop,      _AtBottom,    _malfunction,  _end},
    [_AtTop]     = {_unexpected, _goingDown,  _AtTop,    _unexpected, _unexpected,  _malfunction,  _end},
    [_AtBottom]  = {_goingUp,    _goingDown,  _AtBottom, _unexpected, _unexpected,  _malfunction,  _end},
    [_malfunction] = {_end, _end, _end, _end, _end, _end, _end},
    [_unexpected]  = {_end, _end, _end, _end, _end, _end, _end}
    /* transitions from end state aren't needed */
};

#define ENTRY_STATE _idle
#define END_STATE   _end

int main(){
    
    enum state_codes cur_state = ENTRY_STATE;
    enum ret_codes rc;
    int (* state_func)(void);
    printf("Start the elevator!\n");

    for (;;) {
        state_func = event[cur_state];
        rc = state_func();
        if (END_STATE == cur_state)
            break;
        cur_state = lookup_transitions[cur_state][rc];
    }
    printf("END.");
    getch();
    getch();
    getch();
    return 0;
}


linux可屏蔽#include <conio.h> 并更改getch()运行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值