Article View: comp.lang.c.moderated
Article #2446Re: State engine
From: Kazimir Kylheku
Date: Mon, 01 Apr 1996 13:19
Date: Mon, 01 Apr 1996 13:19
178 lines
4386 bytes
4386 bytes
In article <4jmcoa$lri@solutions.solon.com>,
terres <terres@servidor.dgsca.unam.mx> wrote:
>Hello!
>
>I think that when you have complex problem like many conditions, paths
>and cases, a traditional program could be to big and inneficient on
>execution.
>
>I have seen a system that uses a state engine that triggers some pieces
>of code when an encounters take effect between: states & stimuli.
>
>Like this:
> Stimuli
>State | 1 2 3
>1 |
>2 |
>3 |
>
>When some conditions are acomplished some specific pieces of code are
>executed and that pieces send the control to another crosspoint.
>
>I want to know how to implement this idea in C.
There are all kinds of ways. One is to simply have nested switch statements:
switch (state) {
case 1:
switch(stimulus) {
case 1:
do_something();
state = 2;
break;
case 2:
do_something_else();
state = 3;
break;
case 3:
break;
}
break;
case 2:
break;
case 3:
break;
default:
/* shouldn't reach this */
break;
}
You fill in the missing bits from the table. If you move a lot of the work to
functions, you can keep the switch statement manageable.
Another way is to assing to each state/input combination a function. The
functions don't have to be unique. For instance, if you have a lot of
state/input pairs that do nothing, you can assign to them a function called
idle(). To each state/input combination, you also assign a number which tells
it what state to go into next after the action is called:
enum states {
IDLE, HUNGRY, SLEEPING, IRRITATED, NUMSTATES
};
enum inputs {
FOOD, BELL, NEW_AGE_MUSIC, TIMER, NUMINPUTS
};
typedef void (* action_fun)(void);
struct actiongoto {
action_fun action;
int go;
};
void idle(void);
void eat(void);
void salivate(void);
void growl(void);
static struct actiongoto statetable[NUMSTATES][NUMINPUTS] =
{
{ /* IDLE state */
{ idle, IDLE }, /* FOOD input */
{ idle, IDLE }, /* BELL input */
{ idle, SLEEPING }, /* NEW_AGE_MUSIC input */
{ idle, HUNGRY }, /* TIMER input */
},
{ /* HUNGRY state */
{ eat, IDLE }, /* eat FOOD, be idle */
{ salivate, HUNGRY }, /* salivate on BELL */
{ growl, IRRITATED }, /* growl on music */
{ idle, HUNGRY }, /* stay hungry on timer */
}, /* SLEEPING state */
{
{ idle, SLEEPING },
{ idle, IDLE }, /* awake on bell */
{ idle, SLEEPING }, /* stay asleep w/ music */
{ idle, SLEEPING },
}, /* IRRITATED state */
{
{ eat, IDLE }, /* soothing food */
{ growl, IRRITATED }, /* bell is irritating */
{ growl, IRRITATED }, /* so is new age music */
{ idle, HUNGRY }, /* irritation timeout */
}
};
To use the state table, you look at what state you are in, and what the input
is, and lookup the appropriate actiongoto structure in the two-dimensional
table. You invoke the given function pointer, and advance to the given state.
Assuming you start in the IDLE state, and a TIMER input happens, you call
function idle() and advance to the HUNGRY state. Then, when a BELL input
arrives, you salivate() and stay in the HUNGRY state, and so forth:
#include <stdio.h>
unsigned int getnextinput(void)
{
unsigned int input;
char *menu =
"Enter input\n\n"
"0. FOOD\n"
"1. BELL\n"
"2. NEW_AGE_MUSIC\n"
"3. TIMER\n";
puts(menu);
do {
fputs(">",stdout);
scanf("%u",&input);
} while (input >= NUMINPUTS);
return input;
}
int main()
{
unsigned int input;
unsigned int state = 0;
while(1) {
input = getnextinput();
statetable[state][input].action();
state = statetable[state][input].go;
}
return 0;
}
void eat(void)
{
puts("Munch munch!");
}
void salivate(void)
{
puts("drool!");
}
void growl(void)
{
puts("grr!");
}
void idle(void)
{
puts("yawn!");
}
--
Technical Details
Message-ID:
<4jol5l$1qe@solutions.solon.com>Path:
arc1-ca.pugleaf.net!solon.com!not-for-mailReferences:
<4jmcoa$lri@solutions.solon.com>Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!solon.com!not-for-mail From: c2a192@ugrad.cs.ubc.ca (Kazimir Kylheku) Newsgroups: comp.lang.c.moderated Subject: Re: State engine Date: 1 Apr 1996 07:19:49 -0600 Organization: Computer Science, University of B.C., Vancouver, B.C., Canada Sender: clc@solutions.solon.com Approved: clc@solutions.solon.com Message-ID: <4jol5l$1qe@solutions.solon.com> References: <4jmcoa$lri@solutions.solon.com> NNTP-Posting-Host: solutions.solon.com