Ответы здесь кажутся действительно сложными (но, тем не менее, точными). Вот мои мысли.
Во-первых, мне нравится (FSM) определение dmckee FSM и как они применяются к программированию.
Конечный автомат состоит из
конечное число дискретных состояний (I
знаю педантичный, но все же), который может
как правило, представляется как целое число
ценности. В C или C ++, используя
перечисление очень распространено.
Машина реагирует на конечное
количество входов, которые часто могут быть
представлен другим целым числом
ценная переменная. В более сложном
случаи вы можете использовать структуру для
представляет состояние ввода.
Каждая комбинация внутреннего состояния и
внешний вход вызовет машину
для:
- возможно переход в другое состояние
- возможно сгенерировать какой-нибудь вывод
Итак, у вас есть программа. У него есть состояния, и их конечное число. («лампочка горит», «лампочка тусклая» или «лампочка не горит». 3 состояния. конечный.) Ваша программа может находиться только в одном состоянии одновременно.
Итак, скажем, вы хотите, чтобы ваша программа меняла состояния. Обычно вам нужно, чтобы что-то произошло , чтобы вызвать изменение состояния. В этом примере, как насчет пользовательского ввода для определения состояния, скажем, нажатия клавиши.
Возможно, вы захотите такую логику. Когда пользователь нажимает клавишу:
- Если лампа выключена, то лампа тускнеет.
- Если лампа тусклая, сделайте лампочку яркой.
- Если лампа «яркая», выключите ее.
Очевидно, что вместо «замены лампочки» вы можете «менять цвет текста» или делать то, что нужно вашей программе. Прежде чем начать, вы захотите определить свои состояния.
Итак, посмотрим на какой-то псевдоиш-код C:
/* We have 3 states. We can use constants to represent those states */
#define BULB_OFF 0
#define BULB_DIM 1
#define BULB_BRIGHT 2
/* And now we set the default state */
int currentState = BULB_OFF;
/* now we want to wait for the user's input. While we're waiting, we are "idle" */
while(1) {
waitForUserKeystroke(); /* Waiting for something to happen... */
/* Okay, the user has pressed a key. Now for our state machine */
switch(currentState) {
case BULB_OFF:
currentState = BULB_DIM;
break;
case BULB_DIM:
currentState = BULB_BRIGHT;
doCoolBulbStuff();
break;
case BULB_BRIGHT:
currentState = BULB_OFF;
break;
}
}
И, вуаля. Простая программа, которая меняет состояние.
Этот код выполняет только небольшую часть оператора switch
- в зависимости от текущего состояния . Затем он обновляет это состояние. Вот как работают автоматы.
Теперь вот несколько вещей, которые вы можете сделать:
Очевидно, что эта программа просто изменяет переменную currentState
. Вы захотите, чтобы ваш код делал что-то более интересное при изменении состояния. Функция doCoolBulbStuff()
может, я не знаю, на самом деле поставить изображение лампочки на экране. Или что-то.
Этот код ищет только нажатие клавиши. Но ваш FSM (и, следовательно, ваш оператор switch) может выбирать состояние на основе того, что пользователь ввел (например, «O» означает «выключить», а не просто переходить к следующему в последовательности.)
Часть вашего вопроса о структуре данных.
Один человек предложил использовать enum
для отслеживания состояний. Это хорошая альтернатива #defines
, которую я использовал в своем примере. Люди также предлагали массивы - и эти массивы отслеживают переходы между состояниями. Это также тонкая структура для использования.
Учитывая вышесказанное, вы могли бы использовать любую структуру (что-то древовидное, массив, что угодно), чтобы отслеживать отдельные состояния и определять, что делать в каждом состоянии (отсюда и некоторые рекомендации по использованию «указатели на функции» - имеют отображение состояния на указатель на функцию, который указывает, что делать в этом состоянии.)
Надеюсь, это поможет!