Универсальный FSM в c # для реализации любого конечного автомата .. и для проверки любого следующего состояния при вводе пользователем - PullRequest
1 голос
/ 19 сентября 2019

Может ли быть проще?Я хочу, чтобы он работал универсально для любого конечного автомата, просто меняя таблицу переходов main () ... любым способом, как я могу получить от пользователя данные для выбора любого состояния и показать следующие возможные состояния в качестве вывода в цикле.Как я могу сделать его подходящим для всех машин и как получить от пользователя информацию для выбора следующего возможного состояния машины?

    using System; 
    using System.Activities.Statements; 
    using System.Collections; 
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;     
    namespace FSM_PACMAN
     {
    class Program
    {
        static async Task Main(string[] args)
        {
            StateMachine<string> machine = new StateMachine<string>("Sets","Spawned", "SuperPac","Lvlcomplete","Dead","Successfullgameover")
        {
            { "Spawned", "Spawned","Eatcheese" },
            { "Spawned", "Dead", "EatenbyGost" },
            { "Spawned", "Superpac", "EatTablet" },
            { "Spawned", "Lvlcomplete", "Eatlastcheese" },
            { "SuperPac", "SuperPac", "EATcheese" },
            { "SuperPac", "SuperPac", "EATTablet" },
            { "SuperPac", "Spawned", "Timeout" },
            { "SuperPac", "Lvlcomplete", "Eatlastcheese" },
            { "SuperPac", "SuperPac", "EATghost" },
            { "SuperPac", "Dead", "EatenbySpawnedGhost" },
            { "Lvlcomplete", "Spawned", "Lvlleft" },
            { "Lvlcomplete", "Spawned", "NewGame" },
            { "Lvlcomplete", "Successfullgameover", "Nomorelevels" },
            { "Dead", "Spawned", "Lifeleft"},
            { "Dead", "Spawned", "NewGame" },
            { "Successfullgameover", "Spawned", "NewGame" },

        };

            for (int i = 1; i <= 100; i++) {
                Console.WriteLine(machine);

                Console.WriteLine("current state = " + machine.start);
                Console.WriteLine("Enter State");
                string input = Console.ReadLine();
                machine.start = input;
                    }
           //Console.WriteLine(StateMachine.Equals());
            //  Console.WriteLine("Nomorelevels -> NewGame " + machine.Accepts(""));
            //  Console.WriteLine("NewGame --> Nomorelevels " + machine.Accepts("NewGameNomorelevels"));
            Console.ReadLine();
            await Task.Delay(100000);
        }
    }

    class StateMachine<T> : IEnumerable<Transition<T>>
    {
        public string start { get; set; }
        HashSet<string> ends = new HashSet<string>();
        Dictionary<string, Dictionary<T, string>> transitions = new Dictionary<string, Dictionary<T, string>>();

        public string name { get; set; }

        public StateMachine(string name, string start, params string[] ends)
        {
            this.name = name;
            this.start = start;
            this.ends.UnionWith(ends);
        }

        public void Add(string from, string to, T value)
        {
            if (transitions.ContainsKey(from) == false)
                transitions[from] = new Dictionary<T, string>();

            transitions[from][value] = to;
        }


        public override string ToString()
        {
            string nodes = string.Join(", ", this.transitions.Keys);
            string values = string.Join(", ", this.transitions[start].Keys);
            string ends = string.Join(", ", this.ends);
            string transitions = string.Join("\n   ", this);

            return $"{name} = (\n{{{nodes}}}, \n{{{values}}}, \nQ,\n Start = {start},\n {{{ends}}})\nQ: {transitions}";
            //return $"{start} = (\n{{{nodes}}}, \n{{{values}}}, \nQ,\n Start = {start},\n {{{ends}}})\nQ: {transitions}";

        }

        public IEnumerator<Transition<T>> GetEnumerator()
        {
            return transitions.SelectMany(
                node => node.Value.Select(to => new Transition<T>(node.Key, to.Value, to.Key))).GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

       /* public bool Accepts(IEnumerable<T> @string)
        {
            string state = start;

            foreach (T value in @string)
                state = transitions[state][value];

            return ends.Contains(state);
        }
        */

    }

class Transition<T>
    {
        public string From { get; }
        public string To { get; }
        public T Value { get; }

        public Transition(string from, string to, T value)
        {
            From = from;
            To = to;
            Value = value;
        }

        public override string ToString() => $"q({From}, {Value}) = {To}";
    }
}

1 Ответ

0 голосов
/ 20 сентября 2019

Самый простой FSM реализует метод State Next(Event e), а ваш не делает этого.Не следует ожидать, что каждый потребитель будет перебирать все переходы, чтобы найти следующее состояние.

Состояния должны быть типами значений, такими как Enums, а не ссылочными типами, такими как Strings, и вы должны реализовать таблицы переходов, такие как Dictionary<ValueTuple<State current, Event transition>, State result>, а некак Dictionary<State current, <Dictionary<Event transition, State result>>, который потребует двойного поиска.

Конечные автоматы являются фундаментальной концепцией в информатике, вам следует изучить некоторые теории и существующие реализации.

...