...почти что полной грудью :) Под катом пример описания агента, реализующего конечный автомат из вот этого поста. Только пару недель назад это были первые наметки, а сейчас уже компилирующийся и работающий код. КА даже оказался чуток более навороченным, т.к. пришлось добавить еще парочку состояний, дабы имитация была более правдоподобной.
В принципе, сделал уже почти все, что хотел. Параллельных состояний нет и, вероятно, не будет. Аналогичных результатов можно добиваться и посредством вспомогательных агентов, как это и происходит в данном примере. А вот чего явно пока не хватает, так это автоматической смены состояния после определенного тайм-аута. Как такое сделать, в принципе, понятно. Но это утяжелит объект state_t на пару умных указателей... В общем, нужно подумать, стоит ли оно того...
Ну а вот, собственно, и получившийся код. Глядя на него уже недоумеваешь, а почему мы не сделали иерархические конечные автоматы раньше? Ведь это так классно! Особенно отлаживать ;)
class controller final : public so_5::agent_t { state_t inactive{ this, "inactive" }, active{ this, "active" }, wait_activity{ initial_substate_of{ active }, "wait_activity" }, number_selection{ substate_of{ active }, "number_selection" }, dialling{ substate_of{ active }, "dialling" }, special_code_selection{ substate_of{ active }, "special_code_selection" }, special_code_selection_0{ initial_substate_of{ special_code_selection }, "special_code_selection_0" }, user_code_selection{ substate_of{ special_code_selection }, "user_code_selection" }, user_code_apartment_number{ initial_substate_of{ user_code_selection }, "apartment_number" }, user_code_secret{ substate_of{ user_code_selection }, "secret_code" }, service_code_selection{ substate_of{ special_code_selection }, "service_code" }, door_unlocked{ substate_of{ special_code_selection }, "door_unlocked" }; ... public : controller( context_t ctx, so_5::mbox_t intercom_mbox ) : so_5::agent_t{ ctx } , m_intercom_mbox{ std::move(intercom_mbox) } , m_apartments{ make_apartment_info() } { inactive .transfer_to_state< key_digit >( m_intercom_mbox, active ) .transfer_to_state< key_grid >( m_intercom_mbox, active ) .transfer_to_state< key_bell >( m_intercom_mbox, active ) .transfer_to_state< key_cancel >( m_intercom_mbox, active ); active .on_enter( [this]{ active_on_enter(); } ) .event( m_intercom_mbox, &controller::active_on_grid ) .event( m_intercom_mbox, &controller::active_on_cancel ) .just_switch_to< intercom_messages::deactivate >( m_intercom_mbox, inactive ); wait_activity .transfer_to_state< key_digit >( m_intercom_mbox, number_selection ); number_selection .on_enter( [this]{ apartment_number_on_enter(); } ) .event( m_intercom_mbox, &controller::apartment_number_on_digit ) .event( m_intercom_mbox, &controller::apartment_number_on_bell ) .suppress< key_grid >( m_intercom_mbox ); dialling .on_enter( [this]{ dialling_on_enter(); } ) .on_exit( [this]{ dialling_on_exit(); } ) .suppress< key_grid >( m_intercom_mbox ) .suppress< key_bell >( m_intercom_mbox ) .suppress< key_digit >( m_intercom_mbox ) .event( &controller::dialling_no_answer_from_apartment ); special_code_selection_0 .transfer_to_state< key_digit >( m_intercom_mbox, user_code_selection ) .just_switch_to< key_grid >( m_intercom_mbox, service_code_selection ); user_code_apartment_number .on_enter( [this]{ user_code_apartment_number_on_enter(); } ) .event( m_intercom_mbox, &controller::apartment_number_on_digit ) .just_switch_to< key_grid >( m_intercom_mbox, user_code_secret ); user_code_secret .on_enter( [this]{ user_code_secret_on_enter(); } ) .event( m_intercom_mbox, &controller::user_code_secret_on_digit ) .event( m_intercom_mbox, &controller::user_code_secret_on_bell ); service_code_selection .on_enter( [this]{ service_code_on_enter(); } ) .event( m_intercom_mbox, &controller::service_code_on_digit ) .event( m_intercom_mbox, &controller::service_code_on_grid ); door_unlocked .on_enter( [this]{ door_unlocked_on_enter(); } ) .on_exit( [this]{ door_unlocked_on_exit(); } ) .suppress< key_grid >( m_intercom_mbox ) .suppress< key_bell >( m_intercom_mbox ) .suppress< key_digit >( m_intercom_mbox ) .event( &controller::door_unlocked_on_lock_door ); } virtual void so_evt_start() override { this >>= inactive; } private : ... }; |
Комментариев нет:
Отправить комментарий