状态机 例子

直接上代码

from enum import Enum
from typing import Dict, List
from blinker import Signal


class StateState(Enum):
    NotIn = 0
    Oning = 1
    Outed = 2


class BaseState:
    """state base"""

    def __init__(self) -> None:
        self.sg_oningStart = Signal()
        self.sg_oningEnd = Signal()
        self._sstate = StateState.NotIn

    def destory(self):
        self.sg_oningStart._cleanup_receiver()
        self.sg_oningStart._cleanup_sender()
        self.sg_oningEnd._cleanup_receiver()
        self.sg_oningEnd._cleanup_sender()

    @property
    def is_ready(self) -> bool:
        """StateState.NotIn"""
        return self._sstate.value == 0

    @property
    def is_oning(self) -> bool:
        """StateState.Oning"""
        return self._sstate.value == 1

    @property
    def is_outed(self) -> bool:
        """StateState.Outed"""
        return self._sstate.value == 2

    @property
    def sstate(self) -> StateState:
        """StateState \n
        NotIn = 0 \n
        Oning = 1 \n
        Outed = 2 \n
        """
        return self._sstate

    def enter(self):
        """sg_oningStart send"""
        assert self.is_ready
        self._sstate = StateState.Oning
        self.sg_oningStart.send()

    def exit(self):
        """sg_oningEnd send"""
        assert self.is_oning
        self._sstate = StateState.Outed
        self.sg_oningEnd.send()

    def reset(self):
        """强制初始化"""
        self._sstate = StateState.NotIn


class State(BaseState):
    """state"""

    def __init__(self, name: str) -> None:
        super().__init__()
        self.name = name
        self.order = -1

    def __str__(self):
        return "{ State->" + f"{self.name:<10}: {self.sstate} " + "}"

    __repr__ = __str__


class BaseStateMachine:
    def __init__(self, listState: List[State]) -> None:
        names = []
        self.nowid = -1
        self.ss: Dict[int, State] = {}
        k = 0
        self.ss[k] = State("start")
        k += 1
        for s in listState:
            assert isinstance(s, State)
            if s.name not in names:
                names.append(s.name)
                assert s.order == -1
                s.order = k
                self.ss[k] = s
                k += 1
            else:
                raise ValueError("name 重复")
        self.ss[k] = State("end")
        self.endid = k

    def __getitem__(self, key: int):
        return self.ss.get(key)

    @property
    def s_start(self):
        return self.ss[0]

    @property
    def s_end(self):
        return self.ss[self.endid]

    @property
    def s_now(self):
        return self.ss[self.nowid]

    @property
    def s_next(self):
        if self.nowid < self.endid:
            return self.ss[self.nowid + 1]

    @property
    def s_back(self):
        if self.nowid > 0:
            return self.ss[self.nowid - 1]

    def states(self):
        for k, v in self.ss.items():
            yield (k, v.name, v)

    def _strSS(self):
        return [
            ("    " if k != self.nowid else " -> ") + f"{k}:{str(v)}"
            for k, v in self.ss.items()
        ]

    def __str__(self):
        s = "{ StateMaching:\n"
        s += "\n".join(self._strSS())
        s += "\n}"
        return s

    __repr__ = __str__


class OrderSM(BaseStateMachine):
    def __init__(self, lst: List[str]) -> None:
        super().__init__([State(i) for i in lst])
        self.enter(0)

    def Next(self):
        if self.nowid < self.endid:
            if self.nowid >= 0:
                self.ss[self.nowid].exit()
            self.nowid += 1
            if self.endid >= self.nowid >= 0:
                self.ss[self.nowid].enter()

    def enter(self, id: int):
        if self.endid >= id:
            while id > self.nowid:
                self.Next()
        else:
            raise ValueError(f"id 过大 ,id:{id},self.nowid:{self.nowid}")

    def __str__(self):
        s = "{ OrderSM:\n"
        s += "\n".join(self._strSS())
        s += "\n}"
        return s

    __repr__ = __str__


class RandomSM(BaseStateMachine):
    def __init__(self, lst: List[str]) -> None:
        super().__init__([State(i) for i in lst])
        self.enter(0)

    def enter(self, id: int, is_reEnter: bool = False):
        if self.endid >= id >= 0:
            if self.nowid != id:
                if self.nowid >= 0:
                    self.ss[self.nowid].exit()
                    self.ss[self.nowid].reset()
                self.nowid = id
                self.ss[self.nowid].enter()
            else:
                if is_reEnter:
                    self.reEnter()
        else:
            raise ValueError(f"id 过大 ,id:{id},self.nowid:{self.nowid}")

    def reEnter(self):
        self.ss[self.nowid].exit()
        self.ss[self.nowid].reset()
        self.ss[self.nowid].enter()

    def __str__(self):
        s = "{ RandomSM:\n"
        s += "\n".join(self._strSS())
        s += "\n}"
        return s

    __repr__ = __str__


if __name__ == "__main__":

    sm = OrderSM(["a1", "a2", "a3", "a4"])
    sm.enter(3)
    print(sm)
    sm2 = RandomSM(["b1", "b2", "b3", "b4"])
    sm2.enter(3)
    print(sm2)
    print(sm2[2])

posted @ 2022-05-03 08:54  方头狮  阅读(54)  评论(0)    收藏  举报