from dataclasses import dataclass
from typing import Callable, Iterable
from enum import Enum, auto


@dataclass(frozen=True)
class Automaton[Q, S]:
    delta: Callable[[Q, S], Q]
    start: Q
    finals: frozenset[Q]

    def accept(self, input: Iterable[S]) -> bool:
        state = self.start
        for c in input:
            state = self.delta(state, c)
        return state in self.finals


class State(Enum):
    Q0 = auto(),
    Q1 = auto(),
    Q2 = auto(),
    TRASH = auto(),


class Input(Enum):
    COIN = auto(),
    STOP = auto(),
    DRINK = auto(),
    TAKE = auto(),


def delta(state: State, input: Input) -> State:
    match (state, input):
        case (State.Q0, Input.COIN):
            return State.Q1
        case (State.Q1, Input.STOP):
            return State.Q0
        case (State.Q1, Input.DRINK):
            return State.Q2
        case (State.Q2, Input.TAKE):
            return State.Q0
        case _:
            return State.TRASH


if __name__ == '__main__':
    automata = Automaton(delta, State.Q0, frozenset([State.Q0]))
    assert automata.accept(
        [Input.COIN, Input.STOP, Input.COIN, Input.DRINK, Input.TAKE])
    assert not automata.accept(
        [Input.COIN, Input.TAKE, Input.DRINK, Input.TAKE])
