Cでよく使われる(?)関数ポインタを用いたステートマシンのサンプルです。
Cでよく使われる(?)関数ポインタを用いたステートマシンのサンプルです。
#include <stdio.h>
// 状態番号
static unsigned char sucState;
// 投入金額
static int siCharge;
// Suica残高(仮)
static int siSuica = 2000;
// 状態
enum E_STATE{
IDLE = 0,
POOR,
SELECTED,
SUFFICE,
STATE_MAX
};
// イベント
enum E_EVENT{
INJECT = 0,
CHANGE,
SUICA,
JUICE_SELECT,
EVENT_MAX
};
// ジュースの値段
const int JUICE_PRICE = 120;
//
const char MESSAGE[EVENT_MAX][20]= {
"100円投入",
"おつり返却",
"Suicaタッチ",
"ジュース選択"
};
// 関数ポインタの型宣言
typedef int (*JumpTable)( int* );
// ダミー関数宣言
int Dummy( int * );
// 関数宣言
int St00Ev00( int* );
int St00Ev02( int* );
int St00Ev03( int* );
int St01Ev00( int* );
int St01Ev01( int* );
int St02Ev02( int* );
int St03Ev00( int* );
int St03Ev03( int* );
// ジャンプテーブルの登録
const JumpTable fpVendingMachine[STATE_MAX][EVENT_MAX] = {
// 100円投入 おつり返却 Suicaタッチ ジュース選択
{ &St00Ev00, &Dummy, &St00Ev02, &St00Ev03 }, // 初期状態
{ &St01Ev00, &St01Ev01, &Dummy, &Dummy }, // 金額不足状態
{ &Dummy, &Dummy, &St02Ev02, &Dummy }, // ジュース選択状態
{ &St03Ev00, &St01Ev01, &Dummy, &St03Ev03 }, // 購入可能状態
};
// ダミー関数
int Dummy( int *arg ) {
return( sucState );
}
int St00Ev00( int *arg ) {
*arg += 100;
return( POOR );
}
int St00Ev02( int *arg ) {
printf("Suica残高:%d円\n",*arg);
return( sucState );
}
int St00Ev03( int *arg ) {
printf("ジュース選択\n");
return( SELECTED );
}
int St01Ev00( int *arg ) {
int ret = sucState;
St00Ev00( arg );
if ( siCharge >= JUICE_PRICE ) {
ret = SUFFICE;
}
return( ret );
}
int St01Ev01( int *arg ) {
printf("%d円返却\n",*arg);
*arg = 0;
return( IDLE );
}
int St02Ev02( int *arg ) {
int ret = IDLE;
if ( *arg >= JUICE_PRICE ) {
ret = St03Ev03( arg );
}
return( ret );
}
int St03Ev00( int *arg ) {
*arg += 100;
return( sucState );
}
int St03Ev03( int *arg ) {
int ret = IDLE;
printf("ジュース購入!\n");
*arg -= JUICE_PRICE;
if ( fpVendingMachine[sucState][CHANGE] != Dummy ) {
if ( *arg < JUICE_PRICE ) {
ret = fpVendingMachine[sucState][CHANGE](arg);
} else {
ret = sucState;
}
}
return( ret );
}
int main( int argc, char* argv[] )
{
int i, c, event, *p;
// メインループ
while( 1 ){
// コマンド表示
for( i = 0; i < EVENT_MAX; i++ ){
if ( fpVendingMachine[sucState][i] != Dummy ) {
printf("%d:%s\n", i,MESSAGE[i] );
}
}
puts("");
// コマンド入力
scanf("%d",&c);
fflush( stdin );
event = ( c >= 0 && c <= EVENT_MAX )? c: EVENT_MAX;
if ( event >= EVENT_MAX ) {
puts("error");
continue;
}
if ( event == SUICA ) {
p = &siSuica;
} else {
p = &siCharge;
}
// 関数コール
sucState = fpVendingMachine[sucState][event](p);
}
return( 0 );
}