├── .gitignore ├── .vscode └── launch.json ├── FiniteStateMachine.Example ├── FiniteStateMachine.Example.csproj └── Program.cs ├── FiniteStateMachine.sln ├── FiniteStateMachine ├── EventHandler │ └── StateMachineEventHandler.cs ├── FiniteStateMachine.csproj └── State │ ├── FiniteStateMachine.cs │ ├── IState.cs │ ├── State.cs │ ├── StateBase.cs │ ├── StateInfo.cs │ ├── StateMachine.cs │ └── StateType.cs ├── LICENSE ├── README.md └── images └── console.png /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # MSTest test Results 33 | [Tt]est[Rr]esult*/ 34 | [Bb]uild[Ll]og.* 35 | 36 | # NUNIT 37 | *.VisualState.xml 38 | TestResult.xml 39 | 40 | # Build Results of an ATL Project 41 | [Dd]ebugPS/ 42 | [Rr]eleasePS/ 43 | dlldata.c 44 | 45 | # .NET Core 46 | project.lock.json 47 | project.fragment.lock.json 48 | artifacts/ 49 | **/Properties/launchSettings.json 50 | 51 | *_i.c 52 | *_p.c 53 | *_i.h 54 | *.ilk 55 | *.meta 56 | *.obj 57 | *.pch 58 | *.pdb 59 | *.pgc 60 | *.pgd 61 | *.rsp 62 | *.sbr 63 | *.tlb 64 | *.tli 65 | *.tlh 66 | *.tmp 67 | *.tmp_proj 68 | *.log 69 | *.vspscc 70 | *.vssscc 71 | .builds 72 | *.pidb 73 | *.svclog 74 | *.scc 75 | 76 | # Chutzpah Test files 77 | _Chutzpah* 78 | 79 | # Visual C++ cache files 80 | ipch/ 81 | *.aps 82 | *.ncb 83 | *.opendb 84 | *.opensdf 85 | *.sdf 86 | *.cachefile 87 | *.VC.db 88 | *.VC.VC.opendb 89 | 90 | # Visual Studio profiler 91 | *.psess 92 | *.vsp 93 | *.vspx 94 | *.sap 95 | 96 | # TFS 2012 Local Workspace 97 | $tf/ 98 | 99 | # Guidance Automation Toolkit 100 | *.gpState 101 | 102 | # ReSharper is a .NET coding add-in 103 | _ReSharper*/ 104 | *.[Rr]e[Ss]harper 105 | *.DotSettings.user 106 | 107 | # JustCode is a .NET coding add-in 108 | .JustCode 109 | 110 | # TeamCity is a build add-in 111 | _TeamCity* 112 | 113 | # DotCover is a Code Coverage Tool 114 | *.dotCover 115 | 116 | # Visual Studio code coverage results 117 | *.coverage 118 | *.coveragexml 119 | 120 | # NCrunch 121 | _NCrunch_* 122 | .*crunch*.local.xml 123 | nCrunchTemp_* 124 | 125 | # MightyMoose 126 | *.mm.* 127 | AutoTest.Net/ 128 | 129 | # Web workbench (sass) 130 | .sass-cache/ 131 | 132 | # Installshield output folder 133 | [Ee]xpress/ 134 | 135 | # DocProject is a documentation generator add-in 136 | DocProject/buildhelp/ 137 | DocProject/Help/*.HxT 138 | DocProject/Help/*.HxC 139 | DocProject/Help/*.hhc 140 | DocProject/Help/*.hhk 141 | DocProject/Help/*.hhp 142 | DocProject/Help/Html2 143 | DocProject/Help/html 144 | 145 | # Click-Once directory 146 | publish/ 147 | 148 | # Publish Web Output 149 | *.[Pp]ublish.xml 150 | *.azurePubxml 151 | # TODO: Comment the next line if you want to checkin your web deploy settings 152 | # but database connection strings (with potential passwords) will be unencrypted 153 | *.pubxml 154 | *.publishproj 155 | 156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 157 | # checkin your Azure Web App publish settings, but sensitive information contained 158 | # in these scripts will be unencrypted 159 | PublishScripts/ 160 | 161 | # NuGet Packages 162 | *.nupkg 163 | # The packages folder can be ignored because of Package Restore 164 | **/packages/* 165 | # except build/, which is used as an MSBuild target. 166 | !**/packages/build/ 167 | # Uncomment if necessary however generally it will be regenerated when needed 168 | #!**/packages/repositories.config 169 | # NuGet v3's project.json files produces more ignorable files 170 | *.nuget.props 171 | *.nuget.targets 172 | 173 | # Microsoft Azure Build Output 174 | csx/ 175 | *.build.csdef 176 | 177 | # Microsoft Azure Emulator 178 | ecf/ 179 | rcf/ 180 | 181 | # Windows Store app package directories and files 182 | AppPackages/ 183 | BundleArtifacts/ 184 | Package.StoreAssociation.xml 185 | _pkginfo.txt 186 | 187 | # Visual Studio cache files 188 | # files ending in .cache can be ignored 189 | *.[Cc]ache 190 | # but keep track of directories ending in .cache 191 | !*.[Cc]ache/ 192 | 193 | # Others 194 | ClientBin/ 195 | ~$* 196 | *~ 197 | *.dbmdl 198 | *.dbproj.schemaview 199 | *.jfm 200 | *.pfx 201 | *.publishsettings 202 | orleans.codegen.cs 203 | 204 | # Since there are multiple workflows, uncomment next line to ignore bower_components 205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 206 | #bower_components/ 207 | 208 | # RIA/Silverlight projects 209 | Generated_Code/ 210 | 211 | # Backup & report files from converting an old project file 212 | # to a newer Visual Studio version. Backup files are not needed, 213 | # because we have git ;-) 214 | _UpgradeReport_Files/ 215 | Backup*/ 216 | UpgradeLog*.XML 217 | UpgradeLog*.htm 218 | 219 | # SQL Server files 220 | *.mdf 221 | *.ldf 222 | *.ndf 223 | 224 | # Business Intelligence projects 225 | *.rdl.data 226 | *.bim.layout 227 | *.bim_*.settings 228 | 229 | # Microsoft Fakes 230 | FakesAssemblies/ 231 | 232 | # GhostDoc plugin setting file 233 | *.GhostDoc.xml 234 | 235 | # Node.js Tools for Visual Studio 236 | .ntvs_analysis.dat 237 | node_modules/ 238 | 239 | # Typescript v1 declaration files 240 | typings/ 241 | 242 | # Visual Studio 6 build log 243 | *.plg 244 | 245 | # Visual Studio 6 workspace options file 246 | *.opt 247 | 248 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 249 | *.vbw 250 | 251 | # Visual Studio LightSwitch build output 252 | **/*.HTMLClient/GeneratedArtifacts 253 | **/*.DesktopClient/GeneratedArtifacts 254 | **/*.DesktopClient/ModelManifest.xml 255 | **/*.Server/GeneratedArtifacts 256 | **/*.Server/ModelManifest.xml 257 | _Pvt_Extensions 258 | 259 | # Paket dependency manager 260 | .paket/paket.exe 261 | paket-files/ 262 | 263 | # FAKE - F# Make 264 | .fake/ 265 | 266 | # JetBrains Rider 267 | .idea/ 268 | *.sln.iml 269 | 270 | # CodeRush 271 | .cr/ 272 | 273 | # Python Tools for Visual Studio (PTVS) 274 | __pycache__/ 275 | *.pyc 276 | 277 | # Cake - Uncomment if you are using it 278 | # tools/** 279 | # !tools/packages.config 280 | 281 | # Telerik's JustMock configuration file 282 | *.jmconfig 283 | 284 | # BizTalk build output 285 | *.btp.cs 286 | *.btm.cs 287 | *.odx.cs 288 | *.xsd.cs 289 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Python", 9 | "type": "python", 10 | "request": "launch", 11 | "stopOnEntry": true, 12 | "pythonPath": "${config:python.pythonPath}", 13 | "program": "${file}", 14 | "cwd": "${workspaceFolder}", 15 | "env": {}, 16 | "envFile": "${workspaceFolder}/.env", 17 | "debugOptions": [ 18 | "RedirectOutput" 19 | ] 20 | }, 21 | { 22 | "name": "Python: Attach", 23 | "type": "python", 24 | "request": "attach", 25 | "localRoot": "${workspaceFolder}", 26 | "remoteRoot": "${workspaceFolder}", 27 | "port": 3000, 28 | "secret": "my_secret", 29 | "host": "localhost" 30 | }, 31 | { 32 | "name": "Python: Terminal (integrated)", 33 | "type": "python", 34 | "request": "launch", 35 | "stopOnEntry": true, 36 | "pythonPath": "${config:python.pythonPath}", 37 | "program": "${file}", 38 | "cwd": "", 39 | "console": "integratedTerminal", 40 | "env": {}, 41 | "envFile": "${workspaceFolder}/.env", 42 | "debugOptions": [] 43 | }, 44 | { 45 | "name": "Python: Terminal (external)", 46 | "type": "python", 47 | "request": "launch", 48 | "stopOnEntry": true, 49 | "pythonPath": "${config:python.pythonPath}", 50 | "program": "${file}", 51 | "cwd": "", 52 | "console": "externalTerminal", 53 | "env": {}, 54 | "envFile": "${workspaceFolder}/.env", 55 | "debugOptions": [] 56 | }, 57 | { 58 | "name": "Python: Django", 59 | "type": "python", 60 | "request": "launch", 61 | "stopOnEntry": true, 62 | "pythonPath": "${config:python.pythonPath}", 63 | "program": "${workspaceFolder}/manage.py", 64 | "cwd": "${workspaceFolder}", 65 | "args": [ 66 | "runserver", 67 | "--noreload", 68 | "--nothreading" 69 | ], 70 | "env": {}, 71 | "envFile": "${workspaceFolder}/.env", 72 | "debugOptions": [ 73 | "RedirectOutput", 74 | "DjangoDebugging" 75 | ] 76 | }, 77 | { 78 | "name": "Python: Flask (0.11.x or later)", 79 | "type": "python", 80 | "request": "launch", 81 | "stopOnEntry": false, 82 | "pythonPath": "${config:python.pythonPath}", 83 | "program": "fully qualified path fo 'flask' executable. Generally located along with python interpreter", 84 | "cwd": "${workspaceFolder}", 85 | "env": { 86 | "FLASK_APP": "${workspaceFolder}/quickstart/app.py" 87 | }, 88 | "args": [ 89 | "run", 90 | "--no-debugger", 91 | "--no-reload" 92 | ], 93 | "envFile": "${workspaceFolder}/.env", 94 | "debugOptions": [ 95 | "RedirectOutput" 96 | ] 97 | }, 98 | { 99 | "name": "Python: Flask (0.10.x or earlier)", 100 | "type": "python", 101 | "request": "launch", 102 | "stopOnEntry": false, 103 | "pythonPath": "${config:python.pythonPath}", 104 | "program": "${workspaceFolder}/run.py", 105 | "cwd": "${workspaceFolder}", 106 | "args": [], 107 | "env": {}, 108 | "envFile": "${workspaceFolder}/.env", 109 | "debugOptions": [ 110 | "RedirectOutput" 111 | ] 112 | }, 113 | { 114 | "name": "Python: PySpark", 115 | "type": "python", 116 | "request": "launch", 117 | "stopOnEntry": true, 118 | "osx": { 119 | "pythonPath": "${env:SPARK_HOME}/bin/spark-submit" 120 | }, 121 | "windows": { 122 | "pythonPath": "${env:SPARK_HOME}/bin/spark-submit.cmd" 123 | }, 124 | "linux": { 125 | "pythonPath": "${env:SPARK_HOME}/bin/spark-submit" 126 | }, 127 | "program": "${file}", 128 | "cwd": "${workspaceFolder}", 129 | "env": {}, 130 | "envFile": "${workspaceFolder}/.env", 131 | "debugOptions": [ 132 | "RedirectOutput" 133 | ] 134 | }, 135 | { 136 | "name": "Python: Module", 137 | "type": "python", 138 | "request": "launch", 139 | "stopOnEntry": true, 140 | "pythonPath": "${config:python.pythonPath}", 141 | "module": "module.name", 142 | "cwd": "${workspaceFolder}", 143 | "env": {}, 144 | "envFile": "${workspaceFolder}/.env", 145 | "debugOptions": [ 146 | "RedirectOutput" 147 | ] 148 | }, 149 | { 150 | "name": "Python: Pyramid", 151 | "type": "python", 152 | "request": "launch", 153 | "stopOnEntry": true, 154 | "pythonPath": "${config:python.pythonPath}", 155 | "cwd": "${workspaceFolder}", 156 | "env": {}, 157 | "envFile": "${workspaceFolder}/.env", 158 | "args": [ 159 | "${workspaceFolder}/development.ini" 160 | ], 161 | "debugOptions": [ 162 | "RedirectOutput", 163 | "Pyramid" 164 | ] 165 | }, 166 | { 167 | "name": "Python: Watson", 168 | "type": "python", 169 | "request": "launch", 170 | "stopOnEntry": true, 171 | "pythonPath": "${config:python.pythonPath}", 172 | "program": "${workspaceFolder}/console.py", 173 | "cwd": "${workspaceFolder}", 174 | "args": [ 175 | "dev", 176 | "runserver", 177 | "--noreload=True" 178 | ], 179 | "env": {}, 180 | "envFile": "${workspaceFolder}/.env", 181 | "debugOptions": [ 182 | "RedirectOutput" 183 | ] 184 | } 185 | ] 186 | } -------------------------------------------------------------------------------- /FiniteStateMachine.Example/FiniteStateMachine.Example.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp2.0 6 | Furkan Türkal 7 | FiniteStateMachine.Example 8 | FiniteStateMachine.Example 9 | FiniteStateMachine.Example 10 | FiniteStateMachine.Example 11 | FiniteStateMachine.Example 12 | FiniteStateMachine.Example 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /FiniteStateMachine.Example/Program.cs: -------------------------------------------------------------------------------- 1 | #region License 2 | // ==================================================== 3 | // FiniteStateMachine Copyright(C) 2018 Furkan Türkal 4 | // This program comes with ABSOLUTELY NO WARRANTY; This is free software, 5 | // and you are welcome to redistribute it under certain conditions; See 6 | // file LICENSE, which is part of this source code package, for details. 7 | // ==================================================== 8 | #endregion 9 | 10 | using System; 11 | using System.Reflection; 12 | 13 | namespace FiniteStateMachine.Example 14 | { 15 | 16 | #region States 17 | 18 | public sealed class Example1State : StateBase { 19 | 20 | public Example1State(FiniteStateMachine fsm, StateType stateKey) : base(fsm, stateKey) { 21 | 22 | } 23 | 24 | public override void Begin(FiniteStateChangeEventArgs eventArgs, StateType previousStateKey) { 25 | Console.WriteLine("[ExampleState::Begin()] -> EXAMPLE 1"); 26 | } 27 | 28 | public override void End() { 29 | Console.WriteLine("[ExampleState::End()] -> EXAMPLE 1"); 30 | } 31 | 32 | public override void Load() { 33 | Console.WriteLine("[ExampleState::Load()] -> EXAMPLE 1"); 34 | } 35 | 36 | public override void Update(float deltaTime) { 37 | Console.WriteLine("[ExampleState::Update()] -> EXAMPLE 1"); 38 | } 39 | } 40 | 41 | public sealed class Example2State : StateBase { 42 | 43 | public Example2State(FiniteStateMachine fsm, StateType stateKey) : base(fsm, stateKey) { 44 | 45 | } 46 | 47 | public override void Begin(FiniteStateChangeEventArgs eventArgs, StateType previousStateKey) { 48 | Console.WriteLine("[ExampleState::Begin()] -> EXAMPLE 2"); 49 | } 50 | 51 | public override void End() { 52 | Console.WriteLine("[ExampleState::End()] -> EXAMPLE 2"); 53 | } 54 | 55 | public override void Load() { 56 | Console.WriteLine("[ExampleState::Load()] -> EXAMPLE 2"); 57 | } 58 | 59 | public override void Update(float deltaTime) { 60 | Console.WriteLine("[ExampleState::Update()] -> EXAMPLE 2"); 61 | } 62 | 63 | } 64 | 65 | public sealed class Example3State : StateBase { 66 | 67 | public Example3State(FiniteStateMachine fsm, StateType stateKey) : base(fsm, stateKey) { 68 | 69 | } 70 | 71 | public override void Begin(FiniteStateChangeEventArgs eventArgs, StateType previousStateKey) { 72 | Console.WriteLine("[ExampleState::Begin()] -> EXAMPLE 3"); 73 | } 74 | 75 | public override void End() { 76 | Console.WriteLine("[ExampleState::End()] -> EXAMPLE 3"); 77 | } 78 | 79 | public override void Load() { 80 | Console.WriteLine("[ExampleState::Load()] -> EXAMPLE 3"); 81 | } 82 | 83 | public override void Update(float deltaTime) { 84 | Console.WriteLine("[ExampleState::Update()] -> EXAMPLE 1"); 85 | } 86 | } 87 | 88 | #endregion 89 | 90 | public sealed class ExampleStateInfo : StateInfo { 91 | public override string ToString() { 92 | return string.Format("{0}", "Test State Info"); 93 | } 94 | } 95 | 96 | class Program 97 | { 98 | static void Main(string[] args) 99 | { 100 | Program.SetupConsole(); 101 | 102 | Console.WriteLine("\nNon-Deterministic FiniteStateMachine Engine\n"); 103 | 104 | new Program().Start(); 105 | 106 | Console.Read(); 107 | } 108 | 109 | public void Start() { 110 | FiniteStateMachine fsm = FiniteStateMachine.Instance; 111 | fsm.Initialize(); 112 | fsm.AddState(new Example1State(fsm, StateType.EXAMPLE1)); 113 | fsm.AddState(new Example2State(fsm, StateType.EXAMPLE2)); 114 | fsm.AddState(new Example3State(fsm, StateType.EXAMPLE3)); 115 | 116 | fsm.OnStateBegan += new Action(this.OnFiniteStateBegan); 117 | fsm.OnStateEnded += new Action(this.OnFiniteStateEnded); 118 | fsm.OnStateChange += new Action(this.OnFiniteStateChange); 119 | 120 | fsm.MoveTo(StateType.EXAMPLE1, new FiniteStateChangeEventArgs(StateType.EXAMPLE1, new ExampleStateInfo())); 121 | fsm.MoveTo(StateType.EXAMPLE2, new FiniteStateChangeEventArgs(StateType.EXAMPLE2, new ExampleStateInfo())); 122 | fsm.MoveTo(StateType.EXAMPLE3, new FiniteStateChangeEventArgs(StateType.EXAMPLE3, new ExampleStateInfo())); 123 | } 124 | 125 | public void OnFiniteStateBegan(FiniteStateBeganEventArgs e) { 126 | Console.ForegroundColor = ConsoleColor.Red; 127 | Console.WriteLine("[EventRequest::OnFiniteStateBegan()] -> " + "Began: " + e.Type); 128 | Console.ForegroundColor = ConsoleColor.White; 129 | } 130 | 131 | public void OnFiniteStateChange(FiniteStateChangeEventArgs e) { 132 | Console.ForegroundColor = ConsoleColor.Red; 133 | Console.WriteLine("[EventRequest::OnFiniteStateChange()] -> " + "RequestedType: " + e.RequestedType + " - StateInfo: " + e.StateInfo); 134 | Console.ForegroundColor = ConsoleColor.White; 135 | } 136 | 137 | public void OnFiniteStateEnded(FiniteStateEndedEventArgs e) { 138 | Console.ForegroundColor = ConsoleColor.Red; 139 | Console.WriteLine("[EventRequest::OnFiniteStateEnded()] -> " + "End: " + e.Type); 140 | Console.ForegroundColor = ConsoleColor.White; 141 | } 142 | 143 | private static void SetupConsole() { 144 | 145 | #region GetAssemblyInformation 146 | 147 | var asm = Assembly.GetExecutingAssembly(); 148 | var title = asm.GetCustomAttribute()?.Title; 149 | var version = asm.GetCustomAttribute()?.Version; 150 | var configuration = asm.GetCustomAttribute()?.Configuration; 151 | var informationalVersion = asm.GetCustomAttribute()?.InformationalVersion; 152 | var copyright = asm.GetCustomAttribute()?.Copyright; 153 | 154 | //Display 155 | Console.WindowWidth = 140; 156 | Console.BufferHeight = 5000; 157 | Console.Title = string.Format("{0} {1} ({2}) [{3}] {4}", 158 | title, 159 | version, 160 | System.IO.File.GetLastWriteTime(asm.Location), 161 | string.IsNullOrEmpty(configuration) ? "Undefined" : string.Format("{0}", configuration), 162 | string.IsNullOrEmpty(informationalVersion) ? "" : string.Format("<{0}>", informationalVersion)); 163 | 164 | Console.ForegroundColor = ConsoleColor.DarkRed; 165 | Console.WriteLine(string.Format("Copyright (C) {0}", copyright)); 166 | Console.ForegroundColor = ConsoleColor.White; 167 | 168 | #endregion GetAssemblyInformation 169 | } 170 | 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /FiniteStateMachine.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27130.2026 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FiniteStateMachine", "FiniteStateMachine\FiniteStateMachine.csproj", "{CF17F740-39AE-489B-B600-523C4C894729}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FiniteStateMachine.Example", "FiniteStateMachine.Example\FiniteStateMachine.Example.csproj", "{01E66BAD-7F11-4894-A086-2D6C70B72A60}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {CF17F740-39AE-489B-B600-523C4C894729}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {CF17F740-39AE-489B-B600-523C4C894729}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {CF17F740-39AE-489B-B600-523C4C894729}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {CF17F740-39AE-489B-B600-523C4C894729}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {01E66BAD-7F11-4894-A086-2D6C70B72A60}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {01E66BAD-7F11-4894-A086-2D6C70B72A60}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {01E66BAD-7F11-4894-A086-2D6C70B72A60}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {01E66BAD-7F11-4894-A086-2D6C70B72A60}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {20F264AD-613D-44D8-9FFC-06E853ED86AC} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /FiniteStateMachine/EventHandler/StateMachineEventHandler.cs: -------------------------------------------------------------------------------- 1 | #region License 2 | // ==================================================== 3 | // FiniteStateMachine Copyright(C) 2018 Furkan Türkal 4 | // This program comes with ABSOLUTELY NO WARRANTY; This is free software, 5 | // and you are welcome to redistribute it under certain conditions; See 6 | // file LICENSE, which is part of this source code package, for details. 7 | // ==================================================== 8 | #endregion 9 | 10 | using System; 11 | 12 | namespace FiniteStateMachine 13 | { 14 | public sealed class FiniteStateBeganEventArgs : EventArgs 15 | { 16 | public StateType Type { get; private set; } 17 | 18 | public FiniteStateBeganEventArgs(StateType beganState) 19 | { 20 | this.Type = beganState; 21 | } 22 | } 23 | 24 | public sealed class FiniteStateEndedEventArgs : EventArgs 25 | { 26 | public StateType Type { get; private set; } 27 | 28 | public FiniteStateEndedEventArgs(StateType endedState) 29 | { 30 | this.Type = endedState; 31 | } 32 | } 33 | 34 | public sealed class FiniteStateChangeEventArgs : EventArgs 35 | { 36 | public StateType RequestedType { get; private set; } 37 | public StateInfo StateInfo { get; private set; } 38 | 39 | public FiniteStateChangeEventArgs(StateType requestedState) 40 | { 41 | this.RequestedType = requestedState; 42 | } 43 | 44 | public FiniteStateChangeEventArgs(StateType requestedState, StateInfo stateInfo) 45 | { 46 | this.RequestedType = requestedState; 47 | this.StateInfo = stateInfo; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /FiniteStateMachine/FiniteStateMachine.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.0 5 | Furkan Türkal 6 | FiniteStateMachine 7 | FiniteStateMachine 8 | FiniteStateMachine 9 | FiniteStateMachine 10 | FiniteStateMachine 11 | FiniteStateMachine 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /FiniteStateMachine/State/FiniteStateMachine.cs: -------------------------------------------------------------------------------- 1 | #region License 2 | // ==================================================== 3 | // FiniteStateMachine Copyright(C) 2018 Furkan Türkal 4 | // This program comes with ABSOLUTELY NO WARRANTY; This is free software, 5 | // and you are welcome to redistribute it under certain conditions; See 6 | // file LICENSE, which is part of this source code package, for details. 7 | // ==================================================== 8 | #endregion 9 | 10 | using System; 11 | using System.Collections.Generic; 12 | 13 | namespace FiniteStateMachine 14 | { 15 | public sealed class FiniteStateMachine : StateMachine 16 | { 17 | public static readonly FiniteStateMachine Instance = new FiniteStateMachine(); 18 | 19 | public FiniteStateMachine() { 20 | } 21 | 22 | public override void Initialize() { 23 | base.Initialize(); 24 | } 25 | 26 | public override void Update(float deltaTime) { 27 | base.Update(deltaTime); 28 | } 29 | 30 | public override StateType MoveTo(StateType targetStateKey, FiniteStateChangeEventArgs eventArgs = null) { 31 | this.OnStateChange?.Invoke(eventArgs); 32 | return base.MoveTo(targetStateKey, eventArgs); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /FiniteStateMachine/State/IState.cs: -------------------------------------------------------------------------------- 1 | #region License 2 | // ==================================================== 3 | // FiniteStateMachine Copyright(C) 2018 Furkan Türkal 4 | // This program comes with ABSOLUTELY NO WARRANTY; This is free software, 5 | // and you are welcome to redistribute it under certain conditions; See 6 | // file LICENSE, which is part of this source code package, for details. 7 | // ==================================================== 8 | #endregion 9 | 10 | namespace FiniteStateMachine 11 | { 12 | public interface IState { 13 | 14 | void Begin(FiniteStateChangeEventArgs eventArgs, T previousStateKey); 15 | 16 | void Update(float deltaTime); 17 | 18 | void End(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /FiniteStateMachine/State/State.cs: -------------------------------------------------------------------------------- 1 | #region License 2 | // ==================================================== 3 | // FiniteStateMachine Copyright(C) 2018 Furkan Türkal 4 | // This program comes with ABSOLUTELY NO WARRANTY; This is free software, 5 | // and you are welcome to redistribute it under certain conditions; See 6 | // file LICENSE, which is part of this source code package, for details. 7 | // ==================================================== 8 | #endregion 9 | 10 | using System; 11 | 12 | namespace FiniteStateMachine 13 | { 14 | public abstract class State where T : struct, IConvertible 15 | { 16 | public StateMachine StateMachine { get; private set; } 17 | 18 | public T StateKey { get; private set; } 19 | 20 | public State(StateMachine fsm, T stateKey) 21 | { 22 | this.StateMachine = fsm; 23 | this.StateKey = stateKey; 24 | } 25 | 26 | public abstract void Load(); 27 | 28 | public virtual void _Begin(FiniteStateChangeEventArgs eventArgs, T previousStateKey) 29 | { 30 | this.Begin(eventArgs, previousStateKey); 31 | } 32 | 33 | public abstract void Begin(FiniteStateChangeEventArgs eventArgs, T previousStateKey); 34 | 35 | public virtual void _Update(float deltaTime) 36 | { 37 | this.Update(deltaTime); 38 | } 39 | 40 | public abstract void Update(float deltaTime); 41 | 42 | public virtual void _End() 43 | { 44 | this.End(); 45 | } 46 | 47 | public abstract void End(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /FiniteStateMachine/State/StateBase.cs: -------------------------------------------------------------------------------- 1 | #region License 2 | // ==================================================== 3 | // FiniteStateMachine Copyright(C) 2018 Furkan Türkal 4 | // This program comes with ABSOLUTELY NO WARRANTY; This is free software, 5 | // and you are welcome to redistribute it under certain conditions; See 6 | // file LICENSE, which is part of this source code package, for details. 7 | // ==================================================== 8 | #endregion 9 | 10 | namespace FiniteStateMachine 11 | { 12 | public abstract class StateBase : State, IState { 13 | 14 | public StateBase(FiniteStateMachine fsm, StateType stateKey) : base(fsm, stateKey) { } 15 | 16 | public sealed override void _Begin(FiniteStateChangeEventArgs eventArgs, StateType previousStateKey) { 17 | FiniteStateMachine.Instance.OnStateBegan?.Invoke(new FiniteStateBeganEventArgs(base.StateKey)); 18 | this.Begin(eventArgs, previousStateKey); 19 | } 20 | 21 | public sealed override void _Update(float dt) { 22 | this.Update(dt); 23 | } 24 | 25 | public sealed override void _End() { 26 | this.End(); 27 | FiniteStateMachine.Instance.OnStateEnded?.Invoke(new FiniteStateEndedEventArgs(base.StateKey)); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /FiniteStateMachine/State/StateInfo.cs: -------------------------------------------------------------------------------- 1 | #region License 2 | // ==================================================== 3 | // FiniteStateMachine Copyright(C) 2018 Furkan Türkal 4 | // This program comes with ABSOLUTELY NO WARRANTY; This is free software, 5 | // and you are welcome to redistribute it under certain conditions; See 6 | // file LICENSE, which is part of this source code package, for details. 7 | // ==================================================== 8 | #endregion 9 | 10 | using System; 11 | using System.Collections.Generic; 12 | using System.Text; 13 | 14 | namespace FiniteStateMachine 15 | { 16 | public abstract class StateInfo 17 | { 18 | //TODO: Your base StateInfo codes... 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /FiniteStateMachine/State/StateMachine.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace FiniteStateMachine 6 | { 7 | public abstract class StateMachine where T : struct, IConvertible { 8 | 9 | public Action OnStateBegan; 10 | public Action OnStateEnded; 11 | public Action OnStateChange; 12 | 13 | private Dictionary> m_states; 14 | 15 | private State m_currentState; 16 | 17 | public T CurrentState { 18 | get { return this.m_currentState.StateKey; } 19 | } 20 | 21 | public StateMachine() { 22 | this.m_states = new Dictionary>(); 23 | } 24 | 25 | public virtual void Initialize() { 26 | //TODO: Your base Initialize codes... 27 | } 28 | 29 | public virtual void Update(float deltaTime) { 30 | if (this.m_currentState != null) { 31 | this.m_currentState._Update(deltaTime); 32 | } 33 | } 34 | 35 | public void AddState(State state) { 36 | if (state.StateMachine != this) { 37 | throw new Exception("[FiniteStateMachine::AddState()] -> The State can only be added to the State Machine that was used to create it."); 38 | } 39 | this.m_states.Add(state.StateKey, state); 40 | } 41 | 42 | public virtual T MoveTo(T targetStateKey, FiniteStateChangeEventArgs eventArgs = null) { 43 | if (!this.m_states.ContainsKey(targetStateKey)) { 44 | throw new Exception("[FiniteStateMachine::MoveTo()] -> Target state did not exist. Please add the State for key: '" + targetStateKey); 45 | } 46 | T previousStateKey = targetStateKey; 47 | if (this.m_currentState != null) { 48 | previousStateKey = this.m_currentState.StateKey; 49 | this.m_currentState._End(); 50 | } 51 | this.m_currentState = this.m_states[targetStateKey]; 52 | this.m_currentState._Begin(eventArgs, previousStateKey); 53 | return this.m_currentState.StateKey; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /FiniteStateMachine/State/StateType.cs: -------------------------------------------------------------------------------- 1 | #region License 2 | // ==================================================== 3 | // FiniteStateMachine Copyright(C) 2018 Furkan Türkal 4 | // This program comes with ABSOLUTELY NO WARRANTY; This is free software, 5 | // and you are welcome to redistribute it under certain conditions; See 6 | // file LICENSE, which is part of this source code package, for details. 7 | // ==================================================== 8 | #endregion 9 | 10 | namespace FiniteStateMachine 11 | { 12 | public enum StateType 13 | { 14 | EXAMPLE1, 15 | EXAMPLE2, 16 | EXAMPLE3 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Furkan Türkal 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Finite State Machine Public Source Repository

2 | 3 | [What It Is](#what-it-is) 4 | 5 | [How To Use](#how-to-use) 6 | 7 | [Requirements](#requirements) 8 | 9 | [About](#about) 10 | 11 | [Collaborators](#collaborators) 12 | 13 | [Branches](#branches) 14 | 15 | [Copyright & Licensing](#copyright--licensing) 16 | 17 | [Contributing](#contributing) 18 | 19 | [Contact](#contact) 20 | 21 | ## What It Is 22 | 23 | **Finite State Machine with .NET Core** 24 | 25 | Finite State Machine guide for .NET Core language is an easy and advanced way to learn how algorithms works in theory. 26 | 27 | **Uses : `.NET Core`** -> **[Official .NET Core](https://dotnet.github.io/)** 28 | 29 | **Finite State Machine** 30 | 31 | A finite-state machine, or FSM for short, is a model of computation based on a hypothetical machine made of one or more states. Only a single state can be active at the same time, so the machine must transition from one state to another in order to perform different actions. 32 | 33 | FSMs are commonly used to organize and represent an execution flow, which is useful to implement AI in games. The "brain" of an enemy, for instance, can be implemented using a FSM. 34 | 35 | ![Preview Thumbnail](https://cdn.tutsplus.com/gamedev/uploads/2013/10/fsm_enemy_brain.png) 36 | 37 | ![Preview Thumbnail](http://www.i-programmer.info/images/stories/BabBag/FiniteState/fig2.PNG) 38 | 39 | ![Preview Thumbnail](https://praveenthomasln.files.wordpress.com/2012/04/figure-1-state-machines.png) 40 | 41 | ![Preview Thumbnail](https://cdn.tutsplus.com/gamedev/uploads/2013/12/fsm_steering_enemy_brain.png) 42 | 43 | Reference: https://gamedevelopment.tutsplus.com/tutorials/finite-state-machines-theory-and-implementation--gamedev-11867 44 | 45 | **Who is the target audience?** 46 | 47 | This course is meant for anyone who wants to learn Finite State Machine algorithm and theory in C#. The examples are made with C# using .NET Core. 48 | 49 | * Warning : This course assumes you have some C# knowledge, and `does not teach C# itself.` 50 | 51 | * Warning : These example tutorials are not a "How to make State Machine" or "How State Machines works" and will not teach "State Machine techniques" 52 | 53 | ## How To Use 54 | 55 | Example Usage 56 | -------------------------- 57 | 58 | ![Preview Thumbnail](https://raw.githubusercontent.com/Dentrax/Finite-State-Machine/master/images/console.png) 59 | 60 | `StateType` -> Main states (like Booting, Launching, Initializing, etc.) 61 | 62 | Classes 63 | -------------------------- 64 | 65 | | Class | Access Modifier | Explanation | 66 | | ------------- |:-----------------:|:-------------------------------------------------------------------------:| 67 | | `StateBase` | Abstract | Main state base. When creating a new state, you need to inheritance this | 68 | | `StateInfo` | Abstract | Use this to move information between states. But not mandatory | 69 | 70 | 71 | StateBase 72 | -------------------------- 73 | 74 | | Function | Access Modifier | Explanation | 75 | | --------- |:-----------------:|:-------------------------------------------------------------:| 76 | | `Begin` | Public Override | Trigger when a state is initializing | 77 | | `Load` | Public Override | Need to call manually, after state was initialized | 78 | | `Update` | Public Override | Need to call manually, if you want the update with deltaTime | 79 | | `End` | Public Override | Trigger when a state is terminating | 80 | 81 | Events 82 | -------------------------- 83 | 84 | | Event | Type | Explanation | 85 | | ----------------------------- |:------:|:------------------------------------------------:| 86 | | `FiniteStateBeganEventArgs` | Action | Trigger when a state is initialized with Begin() | 87 | | `FiniteStateChangeEventArgs` | Action | Trigger when a state is changed to another | 88 | | `FiniteStateEndedEventArgs` | Action | Trigger when a state is terminated with End() | 89 | 90 | State Machine 91 | -------------------------- 92 | 93 | | Function | Args | Explanation | 94 | | ------------- |:------------------:|:----------------------------------------:| 95 | | `Initialize` | - | Initialize the FSM | 96 | | `AddState` | - | Add a State to FSM | 97 | | `MoveTo` | StateType, OnEvent | Change the current State to given State | 98 | 99 | Example State 100 | -------------------------- 101 | 102 | ```csharp 103 | 104 | public sealed class ExampleState : StateBase { 105 | 106 | public ExampleState(FiniteStateMachine fsm, StateType stateKey) : base(fsm, stateKey) { 107 | //Your Constructor() codes 108 | } 109 | 110 | public override void Begin(FiniteStateChangeEventArgs eventArgs, StateType previousStateKey) { 111 | //Your Begin() codes 112 | } 113 | 114 | public override void End() { 115 | //Your End() codes 116 | } 117 | 118 | public override void Load() { 119 | //Your Load() codes 120 | } 121 | 122 | public override void Update(float deltaTime) { 123 | //Your Update() codes 124 | } 125 | } 126 | 127 | ``` 128 | 129 | Example StateInfo 130 | -------------------------- 131 | 132 | ```csharp 133 | 134 | public sealed class ExampleStateInfo : StateInfo { 135 | 136 | //Your variables, events, functions, etc. 137 | 138 | public override string ToString() { 139 | //Example ToString() 140 | } 141 | } 142 | 143 | ``` 144 | 145 | Example Usage 146 | -------------------------- 147 | 148 | ```csharp 149 | 150 | FiniteStateMachine.Instance.Initialize(); 151 | FiniteStateMachine.Instance.AddState(new Example1State(FiniteStateMachine.Instance, StateType.EXAMPLE1)); 152 | FiniteStateMachine.Instance.AddState(new Example2State(FiniteStateMachine.Instance, StateType.EXAMPLE2)); 153 | FiniteStateMachine.Instance.AddState(new Example3State(FiniteStateMachine.Instance, StateType.EXAMPLE3)); 154 | 155 | 156 | FiniteStateMachine.Instance.MoveTo(StateType.EXAMPLE1, new FiniteStateChangeEventArgs(StateType.EXAMPLE1, new ExampleStateInfo())); 157 | FiniteStateMachine.Instance.MoveTo(StateType.EXAMPLE2, new FiniteStateChangeEventArgs(StateType.EXAMPLE2, new ExampleStateInfo())); 158 | FiniteStateMachine.Instance.MoveTo(StateType.EXAMPLE3, new FiniteStateChangeEventArgs(StateType.EXAMPLE3, new ExampleStateInfo())); 159 | 160 | ``` 161 | 162 | Example Event Handling 163 | -------------------------- 164 | 165 | ```csharp 166 | 167 | FiniteStateMachine.Instance.OnStateBegan += new Action(this.OnFiniteStateBegan); 168 | FiniteStateMachine.Instance.OnStateEnded += new Action(this.OnFiniteStateEnded); 169 | FiniteStateMachine.Instance.OnStateChange += new Action(this.OnFiniteStateChange); 170 | 171 | public void OnFiniteStateBegan(FiniteStateBeganEventArgs e) { 172 | //Trigger when OnFiniteStateBegan 173 | //Began: e.Type 174 | } 175 | 176 | public void OnFiniteStateChange(FiniteStateChangeEventArgs e) { 177 | //Trigger when OnFiniteStateChange 178 | //RequestedType: e.RequestedType 179 | //StateInfo: e.StateInfo (Returns null, if no parameters are given) 180 | } 181 | 182 | public void OnFiniteStateEnded(FiniteStateEndedEventArgs e) { 183 | //Trigger when OnFiniteStateEnded 184 | //End: e.Type 185 | } 186 | 187 | ``` 188 | 189 | 190 | ## Requirements 191 | 192 | * You should be familiar with .NET Core family 193 | * You will need a text editor (like VSCode) or IDE (Visual Studio) 194 | * You will need a computer on which you have the rights to install .NET Core 195 | 196 | ## About 197 | 198 | Finite State Machine was created to serve three purposes: 199 | 200 | **Finite State Machine is a basically State Machine learning repository which base state-machine library coded in C# language** 201 | 202 | 1. To act as a guide to learn Finite State Machine with enhanced and rich content using `.NET Core`. 203 | 204 | 2. To act as a guide to exemplary and educational purpose. 205 | 206 | 3. To create an advanced State-Machine with few lines. 207 | 208 | ## Collaborators 209 | 210 | **Project Manager** - Furkan Türkal (GitHub: **[dentrax](https://github.com/dentrax)**) 211 | 212 | ## Branches 213 | 214 | We publish source for the **[Finite-State-Machine]** in single rolling branch: 215 | 216 | The **[master branch](https://github.com/dentrax/Finite-State-Machine/tree/master)** is extensively tested by our QA team and makes a great starting point for learning the algorithms. Also tracks [live changes](https://github.com/dentrax/Finite-State-Machine/commits/master) by our team. 217 | 218 | ## Copyright & Licensing 219 | 220 | The base project code is copyrighted by Furkan 'Dentrax' Türkal and is covered by single licence. 221 | 222 | All program code (i.e. C#) is licensed under MIT License unless otherwise specified. Please see the **[LICENSE.md](https://github.com/Dentrax/Finite-State-Machine/blob/master/LICENSE)** file for more information. 223 | 224 | **References** 225 | 226 | While this repository is being prepared, it may have been quoted from some sources. 227 | If there is an unspecified source, please contact me. 228 | 229 | ## Contributing 230 | 231 | Please check the [CONTRIBUTING.md](CONTRIBUTING.md) file for contribution instructions and naming guidelines. 232 | 233 | ## Contact 234 | 235 | Finite-State-Machine was created by Furkan 'Dentrax' Türkal 236 | 237 | * 238 | 239 | You can contact by URL: 240 | **[CONTACT](https://github.com/dentrax)** 241 | 242 | Best Regards -------------------------------------------------------------------------------- /images/console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dentrax/Finite-State-Machine/9eb86c4374dfacbfa23c5230dc452245d044be7f/images/console.png --------------------------------------------------------------------------------