├── .gitattributes ├── .gitignore ├── CellLifeGame1 ├── App.ico ├── AssemblyInfo.cs ├── CellLifeGame1.csproj ├── Model.cs ├── Model │ ├── Link.cs │ ├── Node.cs │ └── Position.cs ├── Modeling.cs ├── Pasted.cs ├── SaveFile.cs ├── StateRule.cs ├── StateRule.resx ├── StatesOutput.cs ├── StatesOutput.resx ├── UIForm.cs ├── UIForm.resx └── UniqueID.cs ├── ClassLibrary1 ├── AssemblyInfo.cs ├── ClassLibrary1.csproj └── Historical.cs ├── Command ├── AssemblyInfo.cs ├── Command.cs └── Command.csproj ├── Modeling.sln ├── NNModel ├── AssemblyInfo.cs ├── NNModel.csproj ├── NeuralNet.cs ├── Neuron.cs └── UniqueID.cs ├── README.md ├── Recording ├── AssemblyInfo.cs ├── Recording.cs └── Recording.csproj ├── ThesisAaronShumaker.pdf └── ThreadSafe ├── AssemblyInfo.cs ├── ThreadSafe.cs └── ThreadSafe.csproj /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | 46 | [Dd]ebug/ 47 | [Rr]elease/ 48 | x64/ 49 | build/ 50 | [Bb]in/ 51 | [Oo]bj/ 52 | 53 | # MSTest test Results 54 | [Tt]est[Rr]esult*/ 55 | [Bb]uild[Ll]og.* 56 | 57 | *_i.c 58 | *_p.c 59 | *.ilk 60 | *.meta 61 | *.obj 62 | *.pch 63 | *.pdb 64 | *.pgc 65 | *.pgd 66 | *.rsp 67 | *.sbr 68 | *.tlb 69 | *.tli 70 | *.tlh 71 | *.tmp 72 | *.tmp_proj 73 | *.log 74 | *.vspscc 75 | *.vssscc 76 | .builds 77 | *.pidb 78 | *.log 79 | *.scc 80 | 81 | # Visual C++ cache files 82 | ipch/ 83 | *.aps 84 | *.ncb 85 | *.opensdf 86 | *.sdf 87 | *.cachefile 88 | 89 | # Visual Studio profiler 90 | *.psess 91 | *.vsp 92 | *.vspx 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | 101 | # TeamCity is a build add-in 102 | _TeamCity* 103 | 104 | # DotCover is a Code Coverage Tool 105 | *.dotCover 106 | 107 | # NCrunch 108 | *.ncrunch* 109 | .*crunch*.local.xml 110 | 111 | # Installshield output folder 112 | [Ee]xpress/ 113 | 114 | # DocProject is a documentation generator add-in 115 | DocProject/buildhelp/ 116 | DocProject/Help/*.HxT 117 | DocProject/Help/*.HxC 118 | DocProject/Help/*.hhc 119 | DocProject/Help/*.hhk 120 | DocProject/Help/*.hhp 121 | DocProject/Help/Html2 122 | DocProject/Help/html 123 | 124 | # Click-Once directory 125 | publish/ 126 | 127 | # Publish Web Output 128 | *.Publish.xml 129 | *.pubxml 130 | 131 | # NuGet Packages Directory 132 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 133 | #packages/ 134 | 135 | # Windows Azure Build Output 136 | csx 137 | *.build.csdef 138 | 139 | # Windows Store app package directory 140 | AppPackages/ 141 | 142 | # Others 143 | sql/ 144 | *.Cache 145 | ClientBin/ 146 | [Ss]tyle[Cc]op.* 147 | ~$* 148 | *~ 149 | *.dbmdl 150 | *.[Pp]ublish.xml 151 | *.pfx 152 | *.publishsettings 153 | 154 | # RIA/Silverlight projects 155 | Generated_Code/ 156 | 157 | # Backup & report files from converting an old project file to a newer 158 | # Visual Studio version. Backup files are not needed, because we have git ;-) 159 | _UpgradeReport_Files/ 160 | Backup*/ 161 | UpgradeLog*.XML 162 | UpgradeLog*.htm 163 | 164 | # SQL Server files 165 | App_Data/*.mdf 166 | App_Data/*.ldf 167 | 168 | ############# 169 | ## Windows detritus 170 | ############# 171 | 172 | # Windows image file caches 173 | Thumbs.db 174 | ehthumbs.db 175 | 176 | # Folder config file 177 | Desktop.ini 178 | 179 | # Recycle Bin used on file shares 180 | $RECYCLE.BIN/ 181 | 182 | # Mac crap 183 | .DS_Store 184 | 185 | 186 | ############# 187 | ## Python 188 | ############# 189 | 190 | *.py[co] 191 | 192 | # Packages 193 | *.egg 194 | *.egg-info 195 | dist/ 196 | build/ 197 | eggs/ 198 | parts/ 199 | var/ 200 | sdist/ 201 | develop-eggs/ 202 | .installed.cfg 203 | 204 | # Installer logs 205 | pip-log.txt 206 | 207 | # Unit test / coverage reports 208 | .coverage 209 | .tox 210 | 211 | #Translations 212 | *.mo 213 | 214 | #Mr Developer 215 | .mr.developer.cfg 216 | -------------------------------------------------------------------------------- /CellLifeGame1/App.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AaronLS/CellularAutomataAsNeuralNetwork/fe9e6b950e5e28d2c99350cb8ff3157720555e14/CellLifeGame1/App.ico -------------------------------------------------------------------------------- /CellLifeGame1/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | 4 | // 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | // 9 | [assembly: AssemblyTitle("")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("")] 14 | [assembly: AssemblyCopyright("")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | 18 | // 19 | // Version information for an assembly consists of the following four values: 20 | // 21 | // Major Version 22 | // Minor Version 23 | // Build Number 24 | // Revision 25 | // 26 | // You can specify all the values or you can default the Revision and Build Numbers 27 | // by using the '*' as shown below: 28 | 29 | [assembly: AssemblyVersion("1.0.*")] 30 | 31 | // 32 | // In order to sign your assembly you must specify a key to use. Refer to the 33 | // Microsoft .NET Framework documentation for more information on assembly signing. 34 | // 35 | // Use the attributes below to control which key is used for signing. 36 | // 37 | // Notes: 38 | // (*) If no key is specified, the assembly is not signed. 39 | // (*) KeyName refers to a key that has been installed in the Crypto Service 40 | // Provider (CSP) on your machine. KeyFile refers to a file which contains 41 | // a key. 42 | // (*) If the KeyFile and the KeyName values are both specified, the 43 | // following processing occurs: 44 | // (1) If the KeyName can be found in the CSP, that key is used. 45 | // (2) If the KeyName does not exist and the KeyFile does exist, the key 46 | // in the KeyFile is installed into the CSP and used. 47 | // (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. 48 | // When specifying the KeyFile, the location of the KeyFile should be 49 | // relative to the project output directory which is 50 | // %Project Directory%\obj\. For example, if your KeyFile is 51 | // located in the project directory, you would specify the AssemblyKeyFile 52 | // attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] 53 | // (*) Delay Signing is an advanced option - see the Microsoft .NET Framework 54 | // documentation for more information on this. 55 | // 56 | [assembly: AssemblyDelaySign(false)] 57 | [assembly: AssemblyKeyFile("")] 58 | [assembly: AssemblyKeyName("")] 59 | -------------------------------------------------------------------------------- /CellLifeGame1/CellLifeGame1.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Local 5 | 8.0.50727 6 | 2.0 7 | {F2D678D5-E7D3-483A-90B3-A2A4019098DA} 8 | Debug 9 | AnyCPU 10 | App.ico 11 | 12 | 13 | CellLifeGame1 14 | 15 | 16 | JScript 17 | Grid 18 | IE50 19 | false 20 | Exe 21 | CellLifeGame1 22 | OnBuildSuccess 23 | 24 | 25 | 26 | 27 | 28 | 29 | v2.0 30 | 2.0 31 | 32 | 33 | bin\Debug\ 34 | false 35 | 285212672 36 | false 37 | 38 | 39 | DEBUG;TRACE 40 | 41 | 42 | true 43 | 4096 44 | false 45 | 46 | 47 | false 48 | false 49 | false 50 | false 51 | 4 52 | full 53 | prompt 54 | 55 | 56 | bin\Release\ 57 | false 58 | 285212672 59 | false 60 | 61 | 62 | TRACE 63 | 64 | 65 | false 66 | 4096 67 | false 68 | 69 | 70 | true 71 | false 72 | false 73 | false 74 | 4 75 | none 76 | prompt 77 | 78 | 79 | 80 | System 81 | 82 | 83 | System.Data 84 | 85 | 86 | System.Drawing 87 | 88 | 89 | System.Windows.Forms 90 | 91 | 92 | System.XML 93 | 94 | 95 | 96 | 97 | 98 | Code 99 | 100 | 101 | Code 102 | 103 | 104 | 105 | 106 | 107 | 108 | UserControl 109 | 110 | 111 | Form 112 | 113 | 114 | Form 115 | 116 | 117 | StateRule.cs 118 | 119 | 120 | StatesOutput.cs 121 | 122 | 123 | UIForm.cs 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /CellLifeGame1/Model.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | 4 | 5 | namespace ErsatzAcumen 6 | { 7 | 8 | 9 | 10 | /// 11 | /// Summary description for Model. 12 | /// 13 | public class Model 14 | { 15 | private System.Threading.Thread thread; 16 | 17 | private Queue updates; 18 | 19 | public object GetNextUpdate() 20 | { 21 | return updates.Dequeue(); 22 | } 23 | 24 | private class Item 25 | { 26 | public UniqueID ID; 27 | 28 | 29 | 30 | } 31 | 32 | public Model() 33 | { 34 | Item item = new Item(); 35 | //item 36 | } 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | // 45 | // TODO: Add constructor logic here 46 | // 47 | 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /CellLifeGame1/Model/Link.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace CellLifeGame1.Model 6 | { 7 | 8 | [Serializable] 9 | public class Link 10 | { 11 | public Node Destin;//Destination, where the link points to 12 | 13 | //an optional weight for use in applications such as neural nets 14 | private double weight; 15 | 16 | public double Weight 17 | { 18 | get 19 | { 20 | return this.weight; 21 | } 22 | set 23 | { 24 | this.weight = value; 25 | } 26 | } 27 | 28 | public Link(Node node, double initWeight) 29 | { 30 | this.Weight = initWeight; 31 | this.Destin = node; 32 | } 33 | 34 | public Link(Node node) : this(node, 1) { } 35 | 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /CellLifeGame1/Model/Node.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace CellLifeGame1.Model 7 | { 8 | [Serializable] 9 | public class Node : IComparable 10 | { 11 | 12 | public double inputSum; 13 | 14 | //on or off, firing or not-firing 15 | private bool active; 16 | public bool IsActive 17 | { 18 | get 19 | { 20 | return active; 21 | } 22 | set 23 | { 24 | active = value; 25 | } 26 | } 27 | 28 | //position of node on an X/Y plane 29 | public Position position; 30 | 31 | //list of nodes to which this one connects 32 | public ArrayList links; 33 | 34 | /// 35 | /// Creates a link from this to node. 36 | /// 37 | /// The Node to link to. 38 | public void AddLink(Link link) 39 | { 40 | if (links == null) 41 | { 42 | links = new ArrayList(); 43 | } 44 | 45 | links.Add(link); 46 | } 47 | 48 | public Node(int positionX, int positionY) 49 | { 50 | position = new Position(); 51 | 52 | this.position.x = positionX; 53 | this.position.y = positionY; 54 | inputSum = 0; 55 | } 56 | 57 | #region IComparable Members 58 | /// 59 | /// Performs lexigraphical comparison based on position. 60 | /// 61 | /// Node or position 62 | /// to compare this instance to. 63 | /// Returns result of position comparison. 64 | public int CompareTo(object obj) 65 | { 66 | 67 | if (obj is Node) 68 | { 69 | Node node = (Node)obj; 70 | return this.position.CompareTo(node.position); 71 | } 72 | else//let Position try to compare the type 73 | { 74 | try 75 | { 76 | return this.position.CompareTo(obj); 77 | } 78 | catch (ArgumentException e) 79 | { 80 | throw new ArgumentException(e + "and object is not a Node"); 81 | } 82 | } 83 | } 84 | #endregion 85 | 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /CellLifeGame1/Model/Position.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace CellLifeGame1.Model 6 | { 7 | [Serializable] 8 | public class Position : IComparable 9 | { 10 | //position on an X/Y plane 11 | public int x; 12 | public int y; 13 | 14 | public Position() 15 | { } 16 | 17 | public Position(int x, int y) 18 | { 19 | this.x = x; 20 | this.y = y; 21 | } 22 | 23 | #region IComparable Members 24 | 25 | /// 26 | /// Performs lexicographical comparison of a position, with 27 | /// Position.x being the primary comparison, and Position.y 28 | /// the secondary comparison. 29 | /// 30 | /// Position to compare this instance to. 31 | /// 32 | /// Returns less than 0 if this instance is less than 33 | /// obj, greater than 0 for greater than, and 0 for equality. 34 | /// 35 | public int CompareTo(object obj) 36 | { 37 | if (obj is Position) 38 | { 39 | Position position = (Position)obj; 40 | int xResult = this.x.CompareTo(position.x); 41 | if (xResult != 0) 42 | { 43 | return xResult; 44 | } 45 | //else x is equal, thus we use y comparison 46 | return this.y.CompareTo(position.y); 47 | } 48 | throw new ArgumentException("object is not a Position"); 49 | } 50 | 51 | #endregion 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /CellLifeGame1/Modeling.cs: -------------------------------------------------------------------------------- 1 | //Begin file Modeling.cs 2 | using System; 3 | using System.IO; 4 | using System.Threading; 5 | using System.Collections; 6 | using System.Runtime.Serialization; 7 | using System.Runtime.Serialization.Formatters.Binary; 8 | using CellLifeGame1.Model; 9 | 10 | 11 | namespace CellLifeGame1 12 | { 13 | 14 | 15 | 16 | /// 17 | /// Maintains a representation of the game modeled in internal data. 18 | /// 19 | /// A Modeling object maintains the data model through its own thread. 20 | /// 21 | /// Requests are made from client objects, which are queued, and 22 | /// the Modeling object will process those requests in a loop. 23 | /// 24 | /// When the modeling thread is TimeStepping the data model, any 25 | /// changes made to the model are queued to an updates object, which 26 | /// the client can access and consume. 27 | /// 28 | /// When this thread initially starts, it will load an initial default 29 | /// model, and then wait for some sort of signal 30 | /// from the UIForm which will prompt ModelThread to load a model by 31 | /// some means, from a file, etc., or respond to user editing of the 32 | /// displayed UI model by updating the internal model. At some point 33 | /// the user may signal the model to begin function of time 34 | /// computations. 35 | /// 36 | public class Modeling 37 | { 38 | /// 39 | /// A queue of updates available for the UI to consume. 40 | /// Each item in the queue is itself a collection listing nodes or 41 | /// properties of the model that have changed during an iteration of 42 | /// modeling computation. 43 | /// 44 | /// The client must take care not to modify objects in the Q, as they 45 | /// are references to actual objects in the data model. 46 | /// 47 | public Queue updates; 48 | 49 | /// 50 | /// Minimum time to complete a processing loop, in milliseconds 51 | /// 52 | private int loopMin; 53 | 54 | private Thread modelingThread; 55 | 56 | #region Operational State Management 57 | /// 58 | /// OpStateFlag defines the possible states that the 59 | /// ModelThread can operate in. Either TimeStepping 60 | /// when the model is being updated through each time step, 61 | /// Paused when the ModelThread is blocked awaiting commands, 62 | /// or UpdatePaused or UpdateTimeStepping when the 63 | /// model is processing a request to update the model recieved while, 64 | /// respectively, Paused or TimeStepping. 65 | [Flags()] 66 | public enum OpStateFlag 67 | { 68 | Paused = 1, TimeStepping = 2, Updating = 4, Starting = 8, 69 | Exiting = 16, UpdateTimeStepping = TimeStepping | Updating, 70 | UpdatePaused = Paused | Updating 71 | }; 72 | 73 | /// 74 | /// opState defines the current operational state. 75 | /// 76 | private OpStateFlag opState; 77 | //locking object since value types cannot be locked. 78 | private object opStateLock; 79 | 80 | /// 81 | /// OpState indicates the current operational state that 82 | /// Modeling is in. 83 | /// 84 | public OpStateFlag OpState 85 | { 86 | get 87 | { 88 | lock(opStateLock) 89 | { 90 | return opState; 91 | } 92 | } 93 | } 94 | 95 | private void OpStateChange(OpStateFlag newOpState) 96 | { 97 | lock(opStateLock) 98 | { 99 | opState=newOpState; 100 | } 101 | } 102 | 103 | private Queue requests; 104 | 105 | /// 106 | /// RequestTimeStepping will set Modeling to change 107 | /// OpState at the next most convenient point. 108 | /// 109 | public void RequestTimeStepping() 110 | { 111 | lock(requests) 112 | { 113 | requests.Enqueue(OpStateFlag.TimeStepping); 114 | Monitor.Pulse(requests); 115 | } 116 | } 117 | 118 | public void RequestPause() 119 | { 120 | lock(requests) 121 | { 122 | requests.Enqueue(OpStateFlag.Paused); 123 | } 124 | } 125 | 126 | public void RequestExit() 127 | { 128 | lock(requests) 129 | { 130 | requests.Enqueue(OpStateFlag.Exiting); 131 | } 132 | } 133 | 134 | //sets activation state of node at position p 135 | public void RequestUpdate(Position p, bool a) 136 | { 137 | lock(requests) 138 | { 139 | requests.Enqueue(OpStateFlag.Updating); 140 | requests.Enqueue(p); 141 | requests.Enqueue(a); 142 | Monitor.Pulse(requests); 143 | } 144 | Console.WriteLine("after pulse"); 145 | 146 | } 147 | 148 | private void ProcessUpdate() 149 | { 150 | Position p; 151 | if(requests.Peek() is Position) 152 | { 153 | p = (Position)requests.Dequeue(); 154 | } 155 | else 156 | { 157 | Console.WriteLine("Error, not position"); 158 | return; 159 | } 160 | 161 | bool a; 162 | if(! (requests.Peek() is bool) ) 163 | { 164 | Console.WriteLine("Error, not bool"); 165 | return; 166 | } 167 | else 168 | { 169 | a = (bool)requests.Dequeue(); 170 | } 171 | 172 | int nodeIndex = nodes.BinarySearch( p ); 173 | 174 | if(nodeIndex >= 0)//if found 175 | { 176 | Node node = ( (Node) nodes[nodeIndex] ); 177 | node.IsActive = a; 178 | updates.Enqueue(node); 179 | OnUpdate(EventArgs.Empty);//fire event 180 | } 181 | else 182 | { 183 | Console.WriteLine("\nError, node not found for RequestUpdate\n"); 184 | return; 185 | } 186 | } 187 | 188 | private void ProcessRequests() 189 | { 190 | lock(requests) 191 | { 192 | //while OpState request has not been satisfied, it is possible 193 | //that while waiting in paused mode, we may be awoken to find 194 | //a new request or multiple requests may be made before 195 | //ProcessRequests is called. 196 | 197 | while( requests.Count>0 ) 198 | { 199 | if( requests.Peek() is OpStateFlag ) 200 | { 201 | OpStateFlag request = (OpStateFlag)requests.Dequeue(); 202 | switch (request) 203 | { 204 | case OpStateFlag.Paused: 205 | opState=OpStateFlag.Paused; 206 | 207 | //if there are still requests remaining, then 208 | //we should set state to pause, but continue 209 | //processing requests since there will likely 210 | //be requests for TimeStepping or Updating which 211 | //would normally cancel a pause. 212 | if( requests.Count == 0 ) 213 | { 214 | Monitor.Wait(requests); 215 | } 216 | break; 217 | 218 | case OpStateFlag.Updating: 219 | opState=OpStateFlag.Updating | opState; 220 | ProcessUpdate(); 221 | if(requests.Count==0) 222 | { 223 | requests.Enqueue( 224 | (~OpStateFlag.Updating) & opState ); 225 | break; 226 | } 227 | else 228 | { 229 | opState = ( (~OpStateFlag.Updating) & opState ); 230 | } 231 | break; 232 | 233 | case OpStateFlag.TimeStepping: 234 | opState=OpStateFlag.TimeStepping; 235 | break; 236 | 237 | case OpStateFlag.Exiting: 238 | opState=OpStateFlag.Exiting; 239 | break; 240 | 241 | default: 242 | Console.WriteLine 243 | ("Error, default reached in ProcessRequest"); 244 | break; 245 | } 246 | } 247 | //add else if statement for other object types in queue 248 | } 249 | } 250 | } 251 | #endregion 252 | 253 | /// 254 | /// The model data as a collection of Node objects. 255 | /// 256 | private ArrayList nodes; 257 | 258 | /// 259 | /// List of values on which nodes should fire. 260 | /// 261 | private ArrayList activationValues; 262 | 263 | public ArrayList ActivationValues 264 | { 265 | get 266 | { 267 | return activationValues; 268 | } 269 | } 270 | 271 | #region Update event fields and methods. 272 | /// 273 | /// Update is fired when new data has been flipped to public. 274 | /// 275 | public event EventHandler Update; 276 | 277 | protected virtual void OnUpdate(EventArgs e) 278 | { 279 | if (Update != null) 280 | Update(this,e); 281 | } 282 | #endregion 283 | 284 | /// 285 | /// Loads square grid model into nodes collection. 286 | /// 287 | /// 288 | 289 | /// 290 | /// Loads a grid of nodes and builds links between adjacent and 291 | /// diagonally adjacent nodes(the nearest 8). Most applicable for 292 | /// John Conway's "Game of Life." 293 | /// 294 | /// Minimum (x,y) origin of grid 295 | /// construction 296 | /// Width of grid in x direction. 297 | /// Height of grid in y direction 298 | /// IsActive state to initialize each 299 | /// node at. 300 | private void LoadNodesGrid(Position initPosition, 301 | int width, int height, bool initialActivity) 302 | { 303 | for( int i = initPosition.x; i= 0)//if found 356 | { 357 | node.AddLink( new Link( 358 | (Node) nodes[adjacentNodeIndex], .12D ) ); 359 | } 360 | else 361 | { 362 | Console.WriteLine("Error, adjacent node not found"); 363 | } 364 | } 365 | } 366 | } 367 | node.AddLink( new Link((Node) node, .04D) ); 368 | node.IsActive = initialActivity;//set initial state 369 | } 370 | 371 | 372 | #if DEBUG 373 | foreach (Node node in nodes) 374 | { 375 | foreach (Link link in node.links) 376 | { 377 | Console.WriteLine("Node at ({0},{1}) linked to ({2},{3})", 378 | node.position.x, node.position.y, 379 | link.Destin.position.x, link.Destin.position.y); 380 | } 381 | } 382 | #endif 383 | 384 | } 385 | 386 | /// 387 | /// Loads a (0,0) origin grid. 388 | /// 389 | /// Width of grid in x direction. 390 | /// Height of grid in y direction 391 | /// IsActive state to initialize each 392 | /// node at. 393 | private void LoadNodesGrid(int width, int height, bool initialActivity) 394 | { 395 | LoadNodesGrid(new Position(0,0), width, height, initialActivity); 396 | } 397 | 398 | /// 399 | /// Loads a (0,0) origin grid with random activities for cells. 400 | /// 401 | /// Width of grid in x direction. 402 | /// Height of grid in y direction 403 | private void LoadNodesGrid(int width, int height) 404 | { 405 | LoadNodesGrid(new Position(0,0), width, height, true); 406 | } 407 | 408 | //requests a new NN to simulate a CA 409 | public void RequestAutomaton( 410 | ArrayList neighborhood, ArrayList activationValues, 411 | double neighborWeight, double centerWeight) 412 | { 413 | this.activationValues = (ArrayList)activationValues.Clone(); 414 | RedoLinks(neighborhood, neighborWeight, centerWeight); 415 | } 416 | 417 | /// 418 | /// Returns(via update Q) and sets active a list of nodes that 419 | /// link to the node at pos 420 | /// 421 | public void RequestActivateNeighbors(Position pos) 422 | { 423 | int nodeIndex = nodes.BinarySearch(pos); 424 | 425 | if(nodeIndex >= 0)//if found 426 | { 427 | foreach(Node node in nodes) 428 | { 429 | foreach(Link link in node.links) 430 | { 431 | if( link.Destin.Equals((Node)nodes[nodeIndex]) ) 432 | { 433 | node.IsActive = true; 434 | updates.Enqueue(node); 435 | } 436 | } 437 | } 438 | 439 | OnUpdate(EventArgs.Empty);//fire event 440 | } 441 | else 442 | { 443 | Console.WriteLine("\nError, node not found!\n"); 444 | } 445 | } 446 | 447 | public void RedoLinks(ArrayList neighborhood, double neighborWeight, 448 | double centerWeight) 449 | { 450 | foreach(Node node in nodes) 451 | { 452 | node.links = new ArrayList(); 453 | 454 | if(centerWeight != 0.0D) 455 | { 456 | node.AddLink( new Link((Node) node, centerWeight) ); 457 | } 458 | 459 | foreach(Position pos in neighborhood) 460 | { 461 | int width = 1 + ( (Node)(nodes[nodes.Count-1]) ).position.x; 462 | int height = 1 + ( (Node)(nodes[nodes.Count-1]) ).position.y; 463 | 464 | int relX = (node.position.x - pos.x)%width; 465 | int relY = (node.position.y - pos.y)%height; 466 | 467 | if(relX < 0) 468 | { 469 | relX += width; 470 | } 471 | 472 | if(relY < 0) 473 | { 474 | relY += height; 475 | } 476 | 477 | int adjacentNodeIndex = nodes.BinarySearch( 478 | new Position(relX, relY) 479 | ); 480 | 481 | if(adjacentNodeIndex >= 0)//if found 482 | { 483 | node.AddLink( new Link( 484 | (Node) nodes[adjacentNodeIndex], neighborWeight ) ); 485 | } 486 | else 487 | { 488 | Console.WriteLine("\nError, adjacent node not found!\n"); 489 | } 490 | } 491 | } 492 | } 493 | 494 | 495 | private void CalculateWeightedSum() 496 | { 497 | foreach (Node node in nodes) 498 | { 499 | if(node.IsActive) 500 | { 501 | foreach (Link link in node.links) 502 | { 503 | link.Destin.inputSum += link.Weight; 504 | } 505 | } 506 | } 507 | } 508 | 509 | 510 | public void RequestLoopTime(int loopTime) 511 | { 512 | loopMin = loopTime; 513 | } 514 | 515 | private void CalculateActivation() 516 | { 517 | foreach (Node node in nodes) 518 | { 519 | 520 | bool deactivate = true; 521 | foreach(double dble in activationValues) 522 | { 523 | //if input sum == activationvalue, with tolerance 0.0001 524 | if( Math.Abs(dble - node.inputSum) <= (0.0001D)) 525 | { 526 | //for efficiency we only change node state 527 | //if it is not already that state 528 | if( !node.IsActive ) 529 | { 530 | node.IsActive = true; 531 | updates.Enqueue(node); 532 | } 533 | deactivate = false; 534 | break; 535 | } 536 | } 537 | 538 | //if we are active, and did not find activationValue in loop 539 | if(node.IsActive && deactivate) 540 | {//then deactivate 541 | node.IsActive = false; 542 | updates.Enqueue(node); 543 | } 544 | 545 | //reset input to 0 so that totals can begin accumulating again 546 | node.inputSum = 0; 547 | } 548 | 549 | } 550 | 551 | private void TimeStep() 552 | { 553 | this.CalculateWeightedSum(); 554 | this.CalculateActivation(); 555 | } 556 | 557 | public void ProcessSave(String filename) 558 | { 559 | using( FileStream fileStream = new FileStream(filename, 560 | FileMode.Create, FileAccess.Write, FileShare.None) ) 561 | { 562 | IFormatter formatter = new BinaryFormatter(); 563 | formatter.Serialize( 564 | fileStream, new SaveFile(nodes, activationValues) ); 565 | } 566 | } 567 | 568 | public void ProcessLoad(String filename) 569 | { 570 | using( FileStream fileStream = new FileStream(filename, 571 | FileMode.Open, FileAccess.Read, FileShare.Read) ) 572 | { 573 | IFormatter formatter = new BinaryFormatter(); 574 | 575 | Object loaded = formatter.Deserialize(fileStream); 576 | if(loaded is ArrayList) 577 | { 578 | nodes = (ArrayList)loaded; 579 | } 580 | else 581 | { 582 | SaveFile loadedDual = (SaveFile)loaded; 583 | nodes = loadedDual.nodes; 584 | activationValues = loadedDual.activationValues; 585 | } 586 | } 587 | 588 | foreach(Node node in nodes) 589 | { 590 | updates.Enqueue(node); 591 | } 592 | OnUpdate(EventArgs.Empty); 593 | } 594 | 595 | public void RequestSteps(int steps) 596 | { 597 | this.RequestPause(); 598 | //wait for pause 599 | while(OpState != OpStateFlag.Paused){} 600 | 601 | bool updatesCleared = false; 602 | for(int i = 0; i < steps; ++i) 603 | { 604 | TimeStep(); 605 | 606 | //to prevent emory being overused, we clear updates 607 | if(updates.Count > 2*nodes.Count) 608 | { 609 | updatesCleared = true; 610 | updates.Clear(); 611 | } 612 | } 613 | 614 | //if we cleared updates, then we need to add all cells to updates 615 | if(updatesCleared) 616 | { 617 | updates.Clear(); 618 | foreach(Node node in nodes) 619 | { 620 | updates.Enqueue(node); 621 | } 622 | } 623 | 624 | OnUpdate(EventArgs.Empty);//fire event 625 | } 626 | 627 | public Modeling():this(40,40) 628 | {} 629 | 630 | public Modeling(int height, int width) 631 | { 632 | requests = new Queue(); 633 | opStateLock = new object(); 634 | nodes = new ArrayList(); 635 | updates = new Queue(); 636 | loopMin = 100; 637 | 638 | LoadNodesGrid(height,width); 639 | 640 | System.Random randGen = 641 | new Random( unchecked((int)System.DateTime.Now.Ticks) ); 642 | 643 | foreach (Node node in nodes) 644 | { 645 | //random activity 646 | node.IsActive = Convert.ToBoolean(randGen.Next(2)); 647 | } 648 | 649 | //activation values corresponding to Conway's Life 650 | this.activationValues = 651 | new ArrayList( new double[3] {0.28D, 0.36D, 0.40D} ); 652 | 653 | foreach (Node node in nodes) 654 | { 655 | updates.Enqueue(node); 656 | } 657 | 658 | modelingThread = new Thread( 659 | new ThreadStart(this.ModelingThreadEntryPoint) 660 | ); 661 | 662 | modelingThread.Name = "modelingThread"; 663 | 664 | opState = OpStateFlag.Starting; 665 | RequestPause(); 666 | 667 | modelingThread.Start(); 668 | } 669 | 670 | public void ModelingThreadEntryPoint() 671 | { 672 | DateTime timed = DateTime.Now; 673 | DateTime timed2 = DateTime.Now; 674 | OnUpdate(EventArgs.Empty); 675 | 676 | while(opState != OpStateFlag.Exiting) 677 | { 678 | Console.Write("while loop took: "); 679 | timed2 = DateTime.Now; 680 | Console.WriteLine("{0}",timed2-timed); 681 | timed = DateTime.Now; 682 | 683 | ProcessRequests(); 684 | #if DEBUG 685 | timed2 = DateTime.Now; 686 | Console.WriteLine("{0}",timed2-timed); 687 | timed = DateTime.Now; 688 | Console.WriteLine("Entering TimeStep"); 689 | #endif 690 | TimeStep(); 691 | 692 | #if DEBUG 693 | 694 | timed2 = DateTime.Now; 695 | Console.WriteLine("{0}",timed2-timed); 696 | timed = DateTime.Now; 697 | 698 | Console.WriteLine("Entering OnUpdate"); 699 | #endif 700 | OnUpdate(EventArgs.Empty);//fire event 701 | 702 | #if DEBUG 703 | timed2 = DateTime.Now; 704 | Console.WriteLine("{0}",timed2-timed); 705 | timed = DateTime.Now; 706 | Console.WriteLine("Sleeping"); 707 | #endif 708 | //loopMin milliseconds later 709 | timed2 = timed.AddMilliseconds(loopMin); 710 | 711 | //only if less than loopMin milliseconds have passed do we sleep 712 | if(DateTime.Now<=timed2) 713 | { 714 | Thread.Sleep(timed2-DateTime.Now); 715 | } 716 | 717 | #if DEBUG 718 | timed2 = DateTime.Now; 719 | Console.WriteLine("{0}",timed2-timed); 720 | timed = DateTime.Now; 721 | #endif 722 | 723 | 724 | } 725 | } 726 | 727 | public Node GetNode(int index) 728 | { 729 | return (Node)nodes[index]; 730 | 731 | } 732 | 733 | }//class 734 | }//namespace 735 | //End file Modeling.cs 736 | -------------------------------------------------------------------------------- /CellLifeGame1/SaveFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace CellLifeGame1 7 | { 8 | [Serializable] 9 | class SaveFile 10 | { 11 | internal ArrayList nodes; 12 | internal ArrayList activationValues; 13 | 14 | public SaveFile(ArrayList nodes, ArrayList activationValues) 15 | { 16 | this.nodes = nodes; 17 | this.activationValues = activationValues; 18 | } 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /CellLifeGame1/StateRule.cs: -------------------------------------------------------------------------------- 1 | //Begin file StateRule.cs 2 | using System; 3 | using System.Collections; 4 | using System.ComponentModel; 5 | using System.Drawing; 6 | using System.Data; 7 | using System.Windows.Forms; 8 | 9 | namespace CellLifeGame1 10 | { 11 | /// 12 | /// A case in a set of rules with a checkbox for the user to 13 | /// specify whether the result in that case is dead or alive. 14 | /// 15 | public class StateRule : System.Windows.Forms.UserControl 16 | { 17 | internal System.Windows.Forms.CheckBox result; 18 | 19 | private System.Windows.Forms.Label lblNeighborsAlive; 20 | private System.Windows.Forms.Label lblCenterAlive; 21 | /// 22 | /// Required designer variable. 23 | /// 24 | private System.ComponentModel.Container components = null; 25 | 26 | public readonly int NeighborsAlive; 27 | public readonly bool CenterIsAlive; 28 | public readonly bool IsOuter; 29 | //public readonly double ActivationValue; 30 | 31 | public StateRule(int neighborsCnt, bool isOuter, bool centerIsAlive) 32 | { 33 | // This call is required by the Windows.Forms Form Designer. 34 | InitializeComponent(); 35 | 36 | this.NeighborsAlive = neighborsCnt; 37 | this.CenterIsAlive = centerIsAlive; 38 | this.IsOuter = isOuter; 39 | 40 | lblNeighborsAlive.Text += neighborsCnt; 41 | 42 | if(isOuter == false) 43 | { 44 | lblCenterAlive.Visible = false; 45 | } 46 | else 47 | { 48 | if(centerIsAlive == true) 49 | { 50 | lblCenterAlive.Text += "Yes"; 51 | } 52 | else 53 | { 54 | lblCenterAlive.Text += "No"; 55 | } 56 | } 57 | } 58 | 59 | public bool ResultIsAlive 60 | { 61 | get 62 | { 63 | return result.Checked; 64 | } 65 | set 66 | { 67 | result.Checked = value; 68 | } 69 | } 70 | 71 | /// 72 | /// Clean up any resources being used. 73 | /// 74 | protected override void Dispose( bool disposing ) 75 | { 76 | if( disposing ) 77 | { 78 | if(components != null) 79 | { 80 | components.Dispose(); 81 | } 82 | } 83 | base.Dispose( disposing ); 84 | } 85 | 86 | #region Component Designer generated code 87 | /// 88 | /// Required method for Designer support - do not modify 89 | /// the contents of this method with the code editor. 90 | /// 91 | private void InitializeComponent() 92 | { 93 | this.result = new System.Windows.Forms.CheckBox(); 94 | this.lblNeighborsAlive = new System.Windows.Forms.Label(); 95 | this.lblCenterAlive = new System.Windows.Forms.Label(); 96 | this.SuspendLayout(); 97 | // 98 | // result 99 | // 100 | this.result.CheckAlign = 101 | System.Drawing.ContentAlignment.MiddleRight; 102 | this.result.Location = new System.Drawing.Point(256, 8); 103 | this.result.Name = "result"; 104 | this.result.Size = new System.Drawing.Size(104, 16); 105 | this.result.TabIndex = 0; 106 | this.result.Text = "Results in life?"; 107 | this.result.TextAlign = 108 | System.Drawing.ContentAlignment.MiddleRight; 109 | // 110 | // lblNeighborsAlive 111 | // 112 | this.lblNeighborsAlive.Location = new System.Drawing.Point(8, 8); 113 | this.lblNeighborsAlive.Name = "lblNeighborsAlive"; 114 | this.lblNeighborsAlive.Size = new System.Drawing.Size(128, 16); 115 | this.lblNeighborsAlive.TabIndex = 1; 116 | this.lblNeighborsAlive.Text = "Neighbors alive: "; 117 | // 118 | // lblCenterAlive 119 | // 120 | this.lblCenterAlive.Location = new System.Drawing.Point(144, 8); 121 | this.lblCenterAlive.Name = "lblCenterAlive"; 122 | this.lblCenterAlive.Size = new System.Drawing.Size(112, 16); 123 | this.lblCenterAlive.TabIndex = 0; 124 | this.lblCenterAlive.Text = "Center is alive? "; 125 | // 126 | // StateRule 127 | // 128 | this.Controls.Add(this.lblCenterAlive); 129 | this.Controls.Add(this.lblNeighborsAlive); 130 | this.Controls.Add(this.result); 131 | this.Name = "StateRule"; 132 | this.Size = new System.Drawing.Size(368, 32); 133 | this.ResumeLayout(false); 134 | 135 | } 136 | #endregion 137 | } 138 | } 139 | //End file StateRule.cs -------------------------------------------------------------------------------- /CellLifeGame1/StateRule.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | text/microsoft-resx 90 | 91 | 92 | 1.3 93 | 94 | 95 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 96 | 97 | 98 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 99 | 100 | 101 | False 102 | 103 | 104 | Private 105 | 106 | 107 | Private 108 | 109 | 110 | False 111 | 112 | 113 | Private 114 | 115 | 116 | Private 117 | 118 | 119 | False 120 | 121 | 122 | Private 123 | 124 | 125 | Private 126 | 127 | 128 | False 129 | 130 | 131 | False 132 | 133 | 134 | True 135 | 136 | 137 | True 138 | 139 | 140 | 80 141 | 142 | 143 | (Default) 144 | 145 | 146 | False 147 | 148 | 149 | StateRule 150 | 151 | 152 | Private 153 | 154 | 155 | 8, 8 156 | 157 | -------------------------------------------------------------------------------- /CellLifeGame1/StatesOutput.cs: -------------------------------------------------------------------------------- 1 | //Begin file StatesOutput.cs 2 | using System; 3 | using System.Drawing; 4 | using System.Collections; 5 | using System.ComponentModel; 6 | using System.Windows.Forms; 7 | 8 | namespace CellLifeGame1 9 | { 10 | /// 11 | /// Summary description for StatesOutput. 12 | /// 13 | 14 | public class StatesOutput : System.Windows.Forms.Form 15 | { 16 | private ArrayList stateRules; 17 | double neighborWeight; 18 | double centerWeight; 19 | private System.Windows.Forms.Panel panel1; 20 | private System.Windows.Forms.Button btnDone; 21 | /// 22 | /// Required designer variable. 23 | /// 24 | private System.ComponentModel.Container components = null; 25 | private System.Windows.Forms.Label labelNWeight; 26 | private System.Windows.Forms.Label labelCWeight; 27 | private System.Windows.Forms.TextBox textNWeight; 28 | private System.Windows.Forms.TextBox textCWeight; 29 | private System.Windows.Forms.Panel pnlActivationVals; 30 | private System.Windows.Forms.Label lblActivationValues; 31 | private System.Windows.Forms.TextBox textActivationValues; 32 | 33 | private ArrayList activationValues; 34 | 35 | public ArrayList ActivationValues 36 | { 37 | get 38 | { 39 | return activationValues; 40 | } 41 | } 42 | 43 | public double NeighborWeight 44 | { 45 | get 46 | { 47 | return neighborWeight; 48 | } 49 | set 50 | { 51 | neighborWeight = value; 52 | textNWeight.Text = value.ToString(); 53 | } 54 | } 55 | public double CenterWeight 56 | { 57 | get 58 | { 59 | return centerWeight; 60 | } 61 | set 62 | { 63 | centerWeight = value; 64 | textCWeight.Text = value.ToString(); 65 | } 66 | } 67 | 68 | public StatesOutput(int neighborhoodSize, 69 | double nWeight, double cWeight, ArrayList activationValues) 70 | { 71 | this.activationValues = activationValues; 72 | 73 | Console.WriteLine( 74 | "neighborhoodsize in StatesOutput constructor: {0}", 75 | neighborhoodSize); 76 | 77 | // 78 | // Required for Windows Form Designer support 79 | // 80 | InitializeComponent(); 81 | 82 | stateRules = new ArrayList(); 83 | 84 | NeighborWeight = nWeight; 85 | CenterWeight = cWeight; 86 | 87 | bool isOuter = false; 88 | if(cWeight == .04D) 89 | { 90 | isOuter = true; 91 | } 92 | 93 | for(int i=0; i<=neighborhoodSize; ++i) 94 | { 95 | StateRule stateRule = new StateRule(i,isOuter,false); 96 | stateRules.Add(stateRule); 97 | 98 | foreach(double actVal in activationValues) 99 | { 100 | if( 101 | Math.Abs(actVal - ( ((double)i) * this.NeighborWeight )) 102 | <= (0.0001D)) 103 | { 104 | stateRule.ResultIsAlive = true; 105 | } 106 | } 107 | 108 | if(Math.Abs(CenterWeight - .04D ) <= (0.0001D)) 109 | { 110 | stateRule = new StateRule(i,isOuter,true); 111 | stateRules.Add(stateRule); 112 | 113 | foreach(double actVal in activationValues) 114 | { 115 | double linksSummation = 116 | ((double)i) * this.NeighborWeight + this.CenterWeight; 117 | 118 | if( Math.Abs(actVal - linksSummation ) <= (0.00001D)) 119 | { 120 | stateRule.ResultIsAlive = true; 121 | } 122 | } 123 | } 124 | Console.WriteLine("i in States add is {0}",i); 125 | Console.WriteLine( 126 | "neighborhoodsize in States add: {0}",neighborhoodSize); 127 | } 128 | 129 | this.SuspendLayout(); 130 | 131 | int j=0; 132 | foreach(StateRule stateRule in stateRules) 133 | { 134 | Console.WriteLine("j in States attributes is {0}",j); 135 | stateRule.Location = new System.Drawing.Point(0, 32*j); 136 | stateRule.Name = "stateRule" + 1; 137 | //stateRule.Size = new System.Drawing.Size(400, 32); 138 | stateRule.TabIndex = j; 139 | panel1.Controls.Add(stateRule); 140 | stateRule.result.CheckedChanged += 141 | new EventHandler(outputChange); 142 | ++j; 143 | } 144 | 145 | int calculatedHeight = 146 | ((StateRule)stateRules[1]).Size.Height* 147 | (neighborhoodSize+1)* 148 | (isOuter?2:1); 149 | 150 | if(calculatedHeight < 600) 151 | { 152 | panel1.Size = new Size(416, calculatedHeight); 153 | } 154 | else 155 | { 156 | panel1.Size = new Size(416, 600); 157 | } 158 | 159 | this.ClientSize = new System.Drawing.Size( 160 | panel1.Size.Width + panel1.Location.X*2, 161 | panel1.Size.Height + panel1.Location.Y); 162 | 163 | this.ResumeLayout(false); 164 | } 165 | 166 | 167 | public StatesOutput(int neighborhoodSize) 168 | { 169 | 170 | Console.WriteLine( 171 | "neighborhoodsize in StatesOutput constructor: {0}" 172 | ,neighborhoodSize); 173 | // 174 | // Required for Windows Form Designer support 175 | // 176 | InitializeComponent(); 177 | 178 | stateRules = new ArrayList(); 179 | 180 | // Initializes the variables to pass to the MessageBox.Show method. 181 | string message = "Is your automaton Outer Totalistic?"; 182 | string caption = "Outer"; 183 | MessageBoxButtons buttons = MessageBoxButtons.YesNo; 184 | DialogResult outerResult; 185 | 186 | // Displays the MessageBox. 187 | outerResult = MessageBox.Show(this, message, caption, buttons, 188 | MessageBoxIcon.Question, MessageBoxDefaultButton.Button1); 189 | 190 | bool isOuter; 191 | DialogResult centerResult; 192 | 193 | if(outerResult == DialogResult.Yes) 194 | { 195 | isOuter = true; 196 | CenterWeight = .04D; 197 | } 198 | else 199 | { 200 | isOuter = false; 201 | message = "Is the center cell part of the neighborhood?"; 202 | caption = "Center Cell"; 203 | 204 | centerResult = MessageBox.Show(this, message, caption, buttons, 205 | MessageBoxIcon.Question, MessageBoxDefaultButton.Button1); 206 | 207 | if(centerResult == DialogResult.Yes) 208 | { 209 | CenterWeight = .12D; 210 | neighborhoodSize += 1; 211 | } 212 | else 213 | { 214 | CenterWeight = .0D; 215 | } 216 | } 217 | 218 | NeighborWeight = .12D; 219 | 220 | for(int i=0; i<=neighborhoodSize; ++i) 221 | { 222 | stateRules.Add(new StateRule(i,isOuter,false)); 223 | if(isOuter) 224 | { 225 | stateRules.Add(new StateRule(i,isOuter,true)); 226 | } 227 | Console.WriteLine("i in States add is {0}",i); 228 | Console.WriteLine("neighborhoodsize in States add: {0}", 229 | neighborhoodSize); 230 | } 231 | 232 | this.SuspendLayout(); 233 | 234 | int j=0; 235 | foreach(StateRule stateRule in stateRules) 236 | { 237 | Console.WriteLine("j in States attributes is {0}",j); 238 | stateRule.Location = new System.Drawing.Point(0, 32*j); 239 | stateRule.Name = "stateRule" + 1; 240 | //stateRule.Size = new System.Drawing.Size(400, 32); 241 | stateRule.TabIndex = j; 242 | panel1.Controls.Add(stateRule); 243 | stateRule.result.CheckedChanged += 244 | new EventHandler(outputChange); 245 | ++j; 246 | } 247 | 248 | int calculatedHeight = 249 | ((StateRule)stateRules[1]).Size.Height* 250 | (neighborhoodSize+1)* 251 | (isOuter?2:1); 252 | 253 | if(calculatedHeight < 600) 254 | { 255 | panel1.Size = new Size(416, calculatedHeight); 256 | } 257 | else 258 | { 259 | panel1.Size = new Size(416, 600); 260 | } 261 | 262 | this.ClientSize = new System.Drawing.Size( 263 | panel1.Size.Width + panel1.Location.X*2, 264 | panel1.Size.Height + panel1.Location.Y); 265 | 266 | this.ResumeLayout(false); 267 | } 268 | 269 | public StatesOutput() 270 | { 271 | int neighborhoodSize = 8; 272 | 273 | Console.WriteLine( 274 | "neighborhoodsize in StatesOutput constructor: {0}", 275 | neighborhoodSize); 276 | // 277 | // Required for Windows Form Designer support 278 | // 279 | InitializeComponent(); 280 | 281 | stateRules = new ArrayList(); 282 | 283 | bool isOuter = true; 284 | 285 | for(int i=0; i<=neighborhoodSize; ++i) 286 | { 287 | StateRule stateRule = new StateRule(i,isOuter,false); 288 | 289 | if(i == 3) 290 | { 291 | stateRule.ResultIsAlive = true; 292 | } 293 | 294 | stateRules.Add(stateRule); 295 | 296 | if(isOuter) 297 | { 298 | stateRule = new StateRule(i,isOuter,true); 299 | if(i == 2 || i == 3) 300 | { 301 | stateRule.ResultIsAlive = true; 302 | } 303 | stateRules.Add(stateRule); 304 | 305 | 306 | } 307 | Console.WriteLine("i in States add is {0}",i); 308 | Console.WriteLine("neighborhoodsize in States add: {0}", 309 | neighborhoodSize); 310 | } 311 | 312 | if(isOuter) 313 | { 314 | CenterWeight = .04D; 315 | } 316 | else 317 | { 318 | CenterWeight = .0D; 319 | } 320 | 321 | NeighborWeight = .12D; 322 | 323 | this.SuspendLayout(); 324 | 325 | int j=0; 326 | 327 | foreach(StateRule stateRule in stateRules) 328 | { 329 | Console.WriteLine("j in States attributes is {0}",j); 330 | stateRule.Location = new System.Drawing.Point(0, 32*j); 331 | stateRule.Name = "stateRule" + 1; 332 | stateRule.TabIndex = j; 333 | panel1.Controls.Add(stateRule); 334 | 335 | stateRule.result.CheckedChanged += 336 | new EventHandler(outputChange); 337 | 338 | ++j; 339 | } 340 | 341 | int calculatedHeight = 342 | ((StateRule)stateRules[1]).Size.Height* 343 | (neighborhoodSize+1)* 344 | (isOuter?2:1); 345 | 346 | if(calculatedHeight < 600) 347 | { 348 | panel1.Size = new Size(416, calculatedHeight); 349 | } 350 | else 351 | { 352 | panel1.Size = new Size(416, 600); 353 | } 354 | 355 | this.ClientSize = new System.Drawing.Size( 356 | panel1.Size.Width + panel1.Location.X*2, 357 | panel1.Size.Height + panel1.Location.Y); 358 | 359 | this.ResumeLayout(false); 360 | } 361 | 362 | /// 363 | /// Clean up any resources being used. 364 | /// 365 | protected override void Dispose( bool disposing ) 366 | { 367 | if( disposing ) 368 | { 369 | if(components != null) 370 | { 371 | components.Dispose(); 372 | } 373 | } 374 | base.Dispose( disposing ); 375 | } 376 | 377 | #region Windows Form Designer generated code 378 | /// 379 | /// Required method for Designer support - do not modify 380 | /// the contents of this method with the code editor. 381 | /// 382 | private void InitializeComponent() 383 | { 384 | this.panel1 = new System.Windows.Forms.Panel(); 385 | this.btnDone = new System.Windows.Forms.Button(); 386 | this.labelNWeight = new System.Windows.Forms.Label(); 387 | this.labelCWeight = new System.Windows.Forms.Label(); 388 | this.textNWeight = new System.Windows.Forms.TextBox(); 389 | this.textCWeight = new System.Windows.Forms.TextBox(); 390 | this.pnlActivationVals = new System.Windows.Forms.Panel(); 391 | this.lblActivationValues = new System.Windows.Forms.Label(); 392 | this.textActivationValues = new System.Windows.Forms.TextBox(); 393 | this.pnlActivationVals.SuspendLayout(); 394 | this.SuspendLayout(); 395 | // 396 | // panel1 397 | // 398 | this.panel1.AutoScroll = true; 399 | this.panel1.Location = new System.Drawing.Point(0, 64); 400 | this.panel1.Name = "panel1"; 401 | this.panel1.Size = new System.Drawing.Size(448, 32); 402 | this.panel1.TabIndex = 0; 403 | // 404 | // btnDone 405 | // 406 | this.btnDone.Location = new System.Drawing.Point(8, 8); 407 | this.btnDone.Name = "btnDone"; 408 | this.btnDone.Size = new System.Drawing.Size(56, 24); 409 | this.btnDone.TabIndex = 1; 410 | this.btnDone.Text = "Done"; 411 | this.btnDone.Click += new System.EventHandler(this.btnDone_Click); 412 | // 413 | // labelNWeight 414 | // 415 | this.labelNWeight.Location = new System.Drawing.Point(72, 8); 416 | this.labelNWeight.Name = "labelNWeight"; 417 | this.labelNWeight.Size = new System.Drawing.Size(120, 16); 418 | this.labelNWeight.TabIndex = 2; 419 | this.labelNWeight.Text = "Neighbor Link Weight: "; 420 | this.labelNWeight.TextAlign = 421 | System.Drawing.ContentAlignment.TopRight; 422 | // 423 | // labelCWeight 424 | // 425 | this.labelCWeight.Location = new System.Drawing.Point(264, 8); 426 | this.labelCWeight.Name = "labelCWeight"; 427 | this.labelCWeight.Size = new System.Drawing.Size(108, 16); 428 | this.labelCWeight.TabIndex = 3; 429 | this.labelCWeight.Text = "Center Link Weight: "; 430 | this.labelCWeight.TextAlign = 431 | System.Drawing.ContentAlignment.TopRight; 432 | // 433 | // textNWeight 434 | // 435 | this.textNWeight.Location = new System.Drawing.Point(192, 8); 436 | this.textNWeight.Name = "textNWeight"; 437 | this.textNWeight.ReadOnly = true; 438 | this.textNWeight.Size = new System.Drawing.Size(64, 20); 439 | this.textNWeight.TabIndex = 4; 440 | this.textNWeight.Text = ""; 441 | // 442 | // textCWeight 443 | // 444 | this.textCWeight.Location = new System.Drawing.Point(376, 8); 445 | this.textCWeight.Name = "textCWeight"; 446 | this.textCWeight.ReadOnly = true; 447 | this.textCWeight.Size = new System.Drawing.Size(64, 20); 448 | this.textCWeight.TabIndex = 5; 449 | this.textCWeight.Text = ""; 450 | // 451 | // pnlActivationVals 452 | // 453 | this.pnlActivationVals.AutoScroll = true; 454 | this.pnlActivationVals.Controls.Add(this.textActivationValues); 455 | this.pnlActivationVals.Controls.Add(this.lblActivationValues); 456 | this.pnlActivationVals.Location = new System.Drawing.Point(0, 32); 457 | this.pnlActivationVals.Name = "pnlActivationVals"; 458 | this.pnlActivationVals.Size = new System.Drawing.Size(448, 32); 459 | this.pnlActivationVals.TabIndex = 6; 460 | // 461 | // lblActivationValues 462 | // 463 | this.lblActivationValues.Location = new System.Drawing.Point(8, 8); 464 | this.lblActivationValues.Name = "lblActivationValues"; 465 | this.lblActivationValues.Size = new System.Drawing.Size(96, 16); 466 | this.lblActivationValues.TabIndex = 0; 467 | this.lblActivationValues.Text = "Activation Values:"; 468 | // 469 | // textActivationValues 470 | // 471 | this.textActivationValues.Location = 472 | new System.Drawing.Point(104, 8); 473 | this.textActivationValues.Name = "textActivationValues"; 474 | this.textActivationValues.ReadOnly = true; 475 | this.textActivationValues.Size = new System.Drawing.Size(336, 20); 476 | this.textActivationValues.TabIndex = 1; 477 | this.textActivationValues.Text = ""; 478 | // 479 | // StatesOutput 480 | // 481 | this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); 482 | this.ClientSize = new System.Drawing.Size(448, 405); 483 | this.Controls.Add(this.pnlActivationVals); 484 | this.Controls.Add(this.textCWeight); 485 | this.Controls.Add(this.textNWeight); 486 | this.Controls.Add(this.labelCWeight); 487 | this.Controls.Add(this.labelNWeight); 488 | this.Controls.Add(this.btnDone); 489 | this.Controls.Add(this.panel1); 490 | this.Name = "StatesOutput"; 491 | this.Text = "StatesOutput"; 492 | this.Load += new System.EventHandler(this.load); 493 | this.pnlActivationVals.ResumeLayout(false); 494 | this.ResumeLayout(false); 495 | 496 | } 497 | #endregion 498 | 499 | private void btnDone_Click(object sender, System.EventArgs e) 500 | { 501 | activationValues = new ArrayList(); 502 | foreach(StateRule stateRule in stateRules) 503 | { 504 | if(stateRule.ResultIsAlive) 505 | { 506 | activationValues.Add( 507 | ( ((double)stateRule.NeighborsAlive) * 508 | this.NeighborWeight ) + 509 | (stateRule.CenterIsAlive?this.CenterWeight:0.0D) 510 | ); 511 | } 512 | } 513 | this.Close(); 514 | } 515 | 516 | private void outputChange(object sender, System.EventArgs e) 517 | { 518 | textActivationValues.Text = ""; 519 | foreach(StateRule stateRule in stateRules) 520 | { 521 | if(stateRule.ResultIsAlive) 522 | { 523 | double activationValue = 524 | ( ((double)stateRule.NeighborsAlive) * 525 | this.NeighborWeight ) + 526 | (stateRule.CenterIsAlive?this.CenterWeight:0.0D); 527 | 528 | textActivationValues.Text += 529 | activationValue.ToString() + ';'; 530 | } 531 | } 532 | } 533 | 534 | private void load(object sender, System.EventArgs e) 535 | { 536 | textActivationValues.Text = ""; 537 | foreach(StateRule stateRule in stateRules) 538 | { 539 | if(stateRule.ResultIsAlive) 540 | { 541 | double activationValue = 542 | ( ((double)stateRule.NeighborsAlive) * 543 | this.NeighborWeight ) + 544 | (stateRule.CenterIsAlive?this.CenterWeight:0.0D); 545 | 546 | textActivationValues.Text += activationValue.ToString() + ';'; 547 | } 548 | } 549 | } 550 | } 551 | } 552 | //End file StatesOutput.cs -------------------------------------------------------------------------------- /CellLifeGame1/StatesOutput.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | text/microsoft-resx 90 | 91 | 92 | 1.3 93 | 94 | 95 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 96 | 97 | 98 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 99 | 100 | 101 | False 102 | 103 | 104 | True 105 | 106 | 107 | Private 108 | 109 | 110 | 8, 8 111 | 112 | 113 | True 114 | 115 | 116 | Private 117 | 118 | 119 | False 120 | 121 | 122 | Private 123 | 124 | 125 | Private 126 | 127 | 128 | False 129 | 130 | 131 | Private 132 | 133 | 134 | Private 135 | 136 | 137 | False 138 | 139 | 140 | Private 141 | 142 | 143 | Private 144 | 145 | 146 | Private 147 | 148 | 149 | False 150 | 151 | 152 | Private 153 | 154 | 155 | Private 156 | 157 | 158 | False 159 | 160 | 161 | Private 162 | 163 | 164 | False 165 | 166 | 167 | True 168 | 169 | 170 | Private 171 | 172 | 173 | 8, 8 174 | 175 | 176 | True 177 | 178 | 179 | Private 180 | 181 | 182 | False 183 | 184 | 185 | Private 186 | 187 | 188 | Private 189 | 190 | 191 | Private 192 | 193 | 194 | False 195 | 196 | 197 | Private 198 | 199 | 200 | False 201 | 202 | 203 | StatesOutput 204 | 205 | 206 | (Default) 207 | 208 | 209 | False 210 | 211 | 212 | False 213 | 214 | 215 | 8, 8 216 | 217 | 218 | True 219 | 220 | 221 | 80 222 | 223 | 224 | True 225 | 226 | 227 | Private 228 | 229 | -------------------------------------------------------------------------------- /CellLifeGame1/UIForm.cs: -------------------------------------------------------------------------------- 1 | //Begin file UIForm.cs 2 | using System; 3 | using System.Drawing; 4 | using System.Drawing.Drawing2D; 5 | using System.Collections; 6 | using System.ComponentModel; 7 | using System.Windows.Forms; 8 | using System.Data; 9 | using System.Threading; 10 | using CellLifeGame1.Model; 11 | 12 | 13 | namespace CellLifeGame1 14 | { 15 | 16 | /// 17 | /// Summary description for Form1. 18 | /// 19 | public class UIForm : System.Windows.Forms.Form 20 | { 21 | public class RectGrid : System.Windows.Forms.Panel 22 | { 23 | private void InitializeComponent() 24 | {} 25 | 26 | protected override void OnPaintBackground(PaintEventArgs pevent) 27 | { 28 | //disable background painting by not calling base 29 | } 30 | } 31 | 32 | /// 33 | /// Programmer Added Declarations 34 | /// 35 | private Modeling modeling;//computation and data model 36 | 37 | /// 38 | /// Form Designer Generated Declarations 39 | /// 40 | private RectGrid panel1; 41 | private StatesOutput crntStatesOutput; 42 | 43 | private Cell[,] cells; 44 | private System.Windows.Forms.Button StartStop; 45 | 46 | /// 47 | /// Required designer variable. 48 | /// 49 | private System.ComponentModel.Container components = null; 50 | 51 | private int cellSize=8; 52 | private int cellsWide=64; 53 | private System.Windows.Forms.Button btnClear; 54 | private System.Windows.Forms.Button btnSave; 55 | private System.Windows.Forms.Button btnLoad; 56 | private System.Windows.Forms.Button btnDone; 57 | private System.Windows.Forms.Button automaton; 58 | private System.Windows.Forms.TrackBar sldrSpeed; 59 | private System.Windows.Forms.NumericUpDown numSteps; 60 | private System.Windows.Forms.Button btnStep; 61 | private System.Windows.Forms.Button btnCurrentAuto; 62 | private System.Windows.Forms.GroupBox groupAutomaton; 63 | private int cellsHigh=64; 64 | 65 | public UIForm() 66 | { 67 | // 68 | // Required for Windows Form Designer support 69 | // 70 | InitializeComponent(); 71 | 72 | ProgrammaticInit(); 73 | } 74 | 75 | /// 76 | /// Clean up any resources being used. 77 | /// 78 | protected override void Dispose( bool disposing ) 79 | { 80 | if( disposing ) 81 | { 82 | if (components != null) 83 | { 84 | components.Dispose(); 85 | } 86 | } 87 | base.Dispose( disposing ); 88 | } 89 | 90 | private void ProgrammaticInit() 91 | { 92 | SetStyle(ControlStyles.UserPaint, true); 93 | SetStyle(ControlStyles.AllPaintingInWmPaint, true); 94 | SetStyle(ControlStyles.DoubleBuffer, true); 95 | 96 | crntStatesOutput = new StatesOutput(); 97 | 98 | cells= new Cell[cellsWide, cellsHigh]; 99 | 100 | for(int i=0;i0) 122 | { 123 | Node node = (Node)modeling.updates.Dequeue(); 124 | 125 | Cell cell = cells[node.position.x, node.position.y]; 126 | 127 | if(node.IsActive) 128 | { 129 | cell.Color = Color.Crimson; 130 | } 131 | else 132 | { 133 | cell.Color = Color.DarkBlue; 134 | } 135 | 136 | cell.X = node.position.x*cellSize; 137 | cell.Y = node.position.y*cellSize; 138 | cell.Size = cellSize; 139 | } 140 | 141 | if(this.StartStop.Text == "Stop") 142 | { 143 | modeling.RequestPause(); 144 | } 145 | this.panel1.Invalidate(); 146 | } 147 | 148 | 149 | #region Windows Form Designer generated code 150 | /// 151 | /// Required method for Designer support - do not modify 152 | /// the contents of this method with the code editor. 153 | /// 154 | private void InitializeComponent() 155 | { 156 | this.panel1 = new CellLifeGame1.UIForm.RectGrid(); 157 | this.StartStop = new System.Windows.Forms.Button(); 158 | this.btnClear = new System.Windows.Forms.Button(); 159 | this.btnSave = new System.Windows.Forms.Button(); 160 | this.btnLoad = new System.Windows.Forms.Button(); 161 | this.automaton = new System.Windows.Forms.Button(); 162 | this.btnDone = new System.Windows.Forms.Button(); 163 | this.sldrSpeed = new System.Windows.Forms.TrackBar(); 164 | this.numSteps = new System.Windows.Forms.NumericUpDown(); 165 | this.btnStep = new System.Windows.Forms.Button(); 166 | this.btnCurrentAuto = new System.Windows.Forms.Button(); 167 | this.groupAutomaton = new System.Windows.Forms.GroupBox(); 168 | ((System.ComponentModel.ISupportInitialize) 169 | (this.sldrSpeed)).BeginInit(); 170 | ((System.ComponentModel.ISupportInitialize) 171 | (this.numSteps)).BeginInit(); 172 | this.groupAutomaton.SuspendLayout(); 173 | this.SuspendLayout(); 174 | // 175 | // panel1 176 | // 177 | this.panel1.Location = new System.Drawing.Point(56, 40); 178 | this.panel1.Name = "panel1"; 179 | this.panel1.Size = new System.Drawing.Size(512, 512); 180 | this.panel1.TabIndex = 0; 181 | this.panel1.MouseUp += new 182 | System.Windows.Forms.MouseEventHandler(this.panel1_MouseUp); 183 | this.panel1.Paint += new 184 | System.Windows.Forms.PaintEventHandler(this.panel1_Paint); 185 | this.panel1.DragLeave += new 186 | System.EventHandler(this.panel1_DragLeave); 187 | this.panel1.MouseMove += new 188 | System.Windows.Forms.MouseEventHandler(this.panel1_MouseMove); 189 | this.panel1.MouseDown += new 190 | System.Windows.Forms.MouseEventHandler(this.panel1_MouseDown); 191 | // 192 | // StartStop 193 | // 194 | this.StartStop.Location = new System.Drawing.Point(72, 8); 195 | this.StartStop.Name = "StartStop"; 196 | this.StartStop.Size = new System.Drawing.Size(40, 24); 197 | this.StartStop.TabIndex = 2; 198 | this.StartStop.Text = "Start"; 199 | this.StartStop.Click += new 200 | System.EventHandler(this.StartStop_Click); 201 | // 202 | // btnClear 203 | // 204 | this.btnClear.Location = new System.Drawing.Point(256, 8); 205 | this.btnClear.Name = "btnClear"; 206 | this.btnClear.Size = new System.Drawing.Size(40, 24); 207 | this.btnClear.TabIndex = 3; 208 | this.btnClear.Text = "Clear"; 209 | this.btnClear.Click += new System.EventHandler(this.btnClear_Click); 210 | // 211 | // btnSave 212 | // 213 | this.btnSave.Location = new System.Drawing.Point(304, 8); 214 | this.btnSave.Name = "btnSave"; 215 | this.btnSave.Size = new System.Drawing.Size(40, 24); 216 | this.btnSave.TabIndex = 4; 217 | this.btnSave.Text = "Save"; 218 | this.btnSave.Click += new System.EventHandler(this.btnSave_Click); 219 | // 220 | // btnLoad 221 | // 222 | this.btnLoad.Location = new System.Drawing.Point(352, 8); 223 | this.btnLoad.Name = "btnLoad"; 224 | this.btnLoad.Size = new System.Drawing.Size(40, 24); 225 | this.btnLoad.TabIndex = 5; 226 | this.btnLoad.Text = "Load"; 227 | this.btnLoad.Click += new System.EventHandler(this.btnLoad_Click); 228 | // 229 | // automaton 230 | // 231 | this.automaton.Location = new System.Drawing.Point(4, 16); 232 | this.automaton.Name = "automaton"; 233 | this.automaton.Size = new System.Drawing.Size(36, 20); 234 | this.automaton.TabIndex = 6; 235 | this.automaton.Text = "New"; 236 | this.automaton.Click += new 237 | System.EventHandler(this.automaton_Click); 238 | // 239 | // btnDone 240 | // 241 | this.btnDone.Enabled = false; 242 | this.btnDone.Location = new System.Drawing.Point(108, 16); 243 | this.btnDone.Name = "btnDone"; 244 | this.btnDone.Size = new System.Drawing.Size(40, 20); 245 | this.btnDone.TabIndex = 7; 246 | this.btnDone.Text = "Done"; 247 | this.btnDone.Click += new 248 | System.EventHandler(this.btnDone_Click); 249 | // 250 | // sldrSpeed 251 | // 252 | this.sldrSpeed.Location = new System.Drawing.Point(8, 8); 253 | this.sldrSpeed.Maximum = 1000; 254 | this.sldrSpeed.Minimum = 1; 255 | this.sldrSpeed.Name = "sldrSpeed"; 256 | this.sldrSpeed.Orientation = 257 | System.Windows.Forms.Orientation.Vertical; 258 | this.sldrSpeed.Size = new System.Drawing.Size(45, 544); 259 | this.sldrSpeed.TabIndex = 9; 260 | this.sldrSpeed.TickStyle = System.Windows.Forms.TickStyle.None; 261 | this.sldrSpeed.Value = 200; 262 | this.sldrSpeed.ValueChanged += new 263 | System.EventHandler(this.sldSpeed_Changed); 264 | // 265 | // numSteps 266 | // 267 | this.numSteps.Location = new System.Drawing.Point(168, 8); 268 | this.numSteps.Maximum = new System.Decimal(new int[] { 269 | 5000, 270 | 0, 271 | 0, 272 | 0}); 273 | this.numSteps.Minimum = new System.Decimal(new int[] { 274 | 1, 275 | 0, 276 | 0, 277 | 0}); 278 | this.numSteps.Name = "numSteps"; 279 | this.numSteps.Size = new System.Drawing.Size(80, 20); 280 | this.numSteps.TabIndex = 10; 281 | this.numSteps.Value = new System.Decimal(new int[] { 282 | 1, 283 | 0, 284 | 0, 285 | 0}); 286 | // 287 | // btnStep 288 | // 289 | this.btnStep.Location = new System.Drawing.Point(120, 8); 290 | this.btnStep.Name = "btnStep"; 291 | this.btnStep.Size = new System.Drawing.Size(40, 24); 292 | this.btnStep.TabIndex = 8; 293 | this.btnStep.Text = "Step"; 294 | this.btnStep.Click += new System.EventHandler(this.btnStep_Click); 295 | // 296 | // btnCurrentAuto 297 | // 298 | this.btnCurrentAuto.Location = new System.Drawing.Point(48, 16); 299 | this.btnCurrentAuto.Name = "btnCurrentAuto"; 300 | this.btnCurrentAuto.Size = new System.Drawing.Size(52, 20); 301 | this.btnCurrentAuto.TabIndex = 11; 302 | this.btnCurrentAuto.Text = "Current"; 303 | this.btnCurrentAuto.Click += new 304 | System.EventHandler(this.btnCurrentAuto_Click); 305 | // 306 | // groupAutomaton 307 | // 308 | this.groupAutomaton.Controls.Add(this.btnDone); 309 | this.groupAutomaton.Controls.Add(this.btnCurrentAuto); 310 | this.groupAutomaton.Controls.Add(this.automaton); 311 | this.groupAutomaton.Location = new System.Drawing.Point(400, 0); 312 | this.groupAutomaton.Name = "groupAutomaton"; 313 | this.groupAutomaton.Size = new System.Drawing.Size(152, 40); 314 | this.groupAutomaton.TabIndex = 13; 315 | this.groupAutomaton.TabStop = false; 316 | this.groupAutomaton.Text = "Automaton"; 317 | // 318 | // UIForm 319 | // 320 | this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); 321 | this.ClientSize = new System.Drawing.Size(576, 557); 322 | this.Controls.Add(this.groupAutomaton); 323 | this.Controls.Add(this.numSteps); 324 | this.Controls.Add(this.sldrSpeed); 325 | this.Controls.Add(this.btnStep); 326 | this.Controls.Add(this.btnLoad); 327 | this.Controls.Add(this.btnSave); 328 | this.Controls.Add(this.btnClear); 329 | this.Controls.Add(this.StartStop); 330 | this.Controls.Add(this.panel1); 331 | this.FormBorderStyle = 332 | System.Windows.Forms.FormBorderStyle.FixedToolWindow; 333 | this.Name = "UIForm"; 334 | this.RightToLeft = System.Windows.Forms.RightToLeft.No; 335 | this.Text = 336 | "Cellular Automata Computer Aided Design and Conversion (CACADAC)"; 337 | ((System.ComponentModel.ISupportInitialize) 338 | (this.sldrSpeed)).EndInit(); 339 | ((System.ComponentModel.ISupportInitialize) 340 | (this.numSteps)).EndInit(); 341 | this.groupAutomaton.ResumeLayout(false); 342 | this.ResumeLayout(false); 343 | 344 | } 345 | #endregion 346 | 347 | /// 348 | /// The main entry point for the application. 349 | /// 350 | [STAThread] 351 | static void Main() 352 | { 353 | Application.Run(new UIForm()); 354 | Application.ExitThread();//allow other threads to continue 355 | } 356 | 357 | private bool tempPause = false; 358 | 359 | private void panel1_MouseDown( 360 | object sender, System.Windows.Forms.MouseEventArgs e) 361 | { 362 | if(this.StartStop.Text == "Stop") 363 | { 364 | this.StartStop.Text = "Start"; 365 | tempPause = true; 366 | modeling.RequestPause(); 367 | } 368 | 369 | if(e.Button == MouseButtons.Left) 370 | { 371 | Position position = new Position(e.X/cellSize,e.Y/cellSize); 372 | modeling.RequestUpdate(position,true); 373 | } 374 | else if(e.Button == MouseButtons.Right) 375 | { 376 | Position position = new Position(e.X/cellSize,e.Y/cellSize); 377 | modeling.RequestUpdate(position,false); 378 | } 379 | } 380 | 381 | private void panel1_MouseUp( 382 | object sender, System.Windows.Forms.MouseEventArgs e) 383 | { 384 | if(this.StartStop.Text == "Start" && tempPause==true) 385 | { 386 | this.StartStop.Text = "Stop"; 387 | tempPause = false; 388 | modeling.RequestTimeStepping(); 389 | } 390 | 391 | if(e.Button == MouseButtons.Left) 392 | { 393 | Position position = new Position(e.X/cellSize,e.Y/cellSize); 394 | modeling.RequestUpdate(position,true); 395 | } 396 | else if(e.Button == MouseButtons.Right) 397 | { 398 | Position position = new Position(e.X/cellSize,e.Y/cellSize); 399 | modeling.RequestUpdate(position,false); 400 | } 401 | 402 | } 403 | 404 | private void panel1_Paint( 405 | object sender, System.Windows.Forms.PaintEventArgs a) 406 | { 407 | for(int i=0;i 2 | 3 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | text/microsoft-resx 90 | 91 | 92 | 1.3 93 | 94 | 95 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 96 | 97 | 98 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 99 | 100 | 101 | 8, 8 102 | 103 | 104 | True 105 | 106 | 107 | False 108 | 109 | 110 | Private 111 | 112 | 113 | True 114 | 115 | 116 | Private 117 | 118 | 119 | False 120 | 121 | 122 | Private 123 | 124 | 125 | Private 126 | 127 | 128 | False 129 | 130 | 131 | Private 132 | 133 | 134 | Private 135 | 136 | 137 | False 138 | 139 | 140 | Private 141 | 142 | 143 | Private 144 | 145 | 146 | False 147 | 148 | 149 | Private 150 | 151 | 152 | Private 153 | 154 | 155 | False 156 | 157 | 158 | Private 159 | 160 | 161 | Private 162 | 163 | 164 | False 165 | 166 | 167 | Private 168 | 169 | 170 | Private 171 | 172 | 173 | False 174 | 175 | 176 | Private 177 | 178 | 179 | Private 180 | 181 | 182 | False 183 | 184 | 185 | Private 186 | 187 | 188 | Private 189 | 190 | 191 | False 192 | 193 | 194 | Private 195 | 196 | 197 | Private 198 | 199 | 200 | False 201 | 202 | 203 | Private 204 | 205 | 206 | Private 207 | 208 | 209 | Private 210 | 211 | 212 | 4, 4 213 | 214 | 215 | True 216 | 217 | 218 | False 219 | 220 | 221 | True 222 | 223 | 224 | Private 225 | 226 | 227 | False 228 | 229 | 230 | (Default) 231 | 232 | 233 | False 234 | 235 | 236 | False 237 | 238 | 239 | 8, 8 240 | 241 | 242 | True 243 | 244 | 245 | 80 246 | 247 | 248 | True 249 | 250 | 251 | UIForm 252 | 253 | 254 | Private 255 | 256 | -------------------------------------------------------------------------------- /CellLifeGame1/UniqueID.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ErsatzAcumen 4 | { 5 | 6 | /* 7 | /// 8 | /// UniqueID was an idea to provide IDs that were unique. 9 | /// But the default hashcodes of references are sufficient 10 | /// for most applications. 11 | /// 12 | public class UniqueID 13 | { 14 | /// 15 | /// A list of IDs available previously used IDs 16 | /// This is to avoid an object ID value from overflowing 17 | /// an integer when many objects are created and destroyed, 18 | /// which would result in new objects getting higher and 19 | /// higher ID values. 20 | /// 21 | private static Queue recycledIDs; 22 | 23 | /// 24 | /// The value of the next node ID to be issued, if 25 | /// there are none available in recycledIDs. 26 | /// 27 | private static int nextID=0; 28 | 29 | private static int getNextID() 30 | { 31 | 32 | if(recycledIDs==null) 33 | { 34 | int useID = this.nextID; 35 | ++this.nextID; 36 | return useID; 37 | } 38 | //else there are recylcedIDs to be used 39 | return (int) recycledIDs.Dequeue(); 40 | } 41 | 42 | private readonly int id; 43 | 44 | public int ID 45 | { 46 | get 47 | { 48 | return id; 49 | } 50 | } 51 | 52 | public UniqueID() 53 | { 54 | this.id = getNextID(); 55 | } 56 | 57 | public override int GetHashCode() 58 | { 59 | return ID; 60 | } 61 | }*/ 62 | } 63 | -------------------------------------------------------------------------------- /ClassLibrary1/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | 4 | // 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | // 9 | [assembly: AssemblyTitle("")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("")] 14 | [assembly: AssemblyCopyright("")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | 18 | // 19 | // Version information for an assembly consists of the following four values: 20 | // 21 | // Major Version 22 | // Minor Version 23 | // Build Number 24 | // Revision 25 | // 26 | // You can specify all the values or you can default the Revision and Build Numbers 27 | // by using the '*' as shown below: 28 | 29 | [assembly: AssemblyVersion("1.0.*")] 30 | 31 | // 32 | // In order to sign your assembly you must specify a key to use. Refer to the 33 | // Microsoft .NET Framework documentation for more information on assembly signing. 34 | // 35 | // Use the attributes below to control which key is used for signing. 36 | // 37 | // Notes: 38 | // (*) If no key is specified, the assembly is not signed. 39 | // (*) KeyName refers to a key that has been installed in the Crypto Service 40 | // Provider (CSP) on your machine. KeyFile refers to a file which contains 41 | // a key. 42 | // (*) If the KeyFile and the KeyName values are both specified, the 43 | // following processing occurs: 44 | // (1) If the KeyName can be found in the CSP, that key is used. 45 | // (2) If the KeyName does not exist and the KeyFile does exist, the key 46 | // in the KeyFile is installed into the CSP and used. 47 | // (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. 48 | // When specifying the KeyFile, the location of the KeyFile should be 49 | // relative to the project output directory which is 50 | // %Project Directory%\obj\. For example, if your KeyFile is 51 | // located in the project directory, you would specify the AssemblyKeyFile 52 | // attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] 53 | // (*) Delay Signing is an advanced option - see the Microsoft .NET Framework 54 | // documentation for more information on this. 55 | // 56 | [assembly: AssemblyDelaySign(false)] 57 | [assembly: AssemblyKeyFile("")] 58 | [assembly: AssemblyKeyName("")] 59 | -------------------------------------------------------------------------------- /ClassLibrary1/ClassLibrary1.csproj: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 25 | 45 | 65 | 66 | 67 | 72 | 77 | 82 | 83 | 84 | 85 | 86 | 91 | 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /ClassLibrary1/Historical.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ClassLibrary1 4 | { 5 | /// 6 | /// Summary description for Class1. 7 | /// 8 | public class Class1 9 | { 10 | public Class1() 11 | { 12 | // 13 | // TODO: Add constructor logic here 14 | // 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Command/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | 4 | // 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | // 9 | [assembly: AssemblyTitle("")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("")] 14 | [assembly: AssemblyCopyright("")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | 18 | // 19 | // Version information for an assembly consists of the following four values: 20 | // 21 | // Major Version 22 | // Minor Version 23 | // Build Number 24 | // Revision 25 | // 26 | // You can specify all the values or you can default the Revision and Build Numbers 27 | // by using the '*' as shown below: 28 | 29 | [assembly: AssemblyVersion("1.0.*")] 30 | 31 | // 32 | // In order to sign your assembly you must specify a key to use. Refer to the 33 | // Microsoft .NET Framework documentation for more information on assembly signing. 34 | // 35 | // Use the attributes below to control which key is used for signing. 36 | // 37 | // Notes: 38 | // (*) If no key is specified, the assembly is not signed. 39 | // (*) KeyName refers to a key that has been installed in the Crypto Service 40 | // Provider (CSP) on your machine. KeyFile refers to a file which contains 41 | // a key. 42 | // (*) If the KeyFile and the KeyName values are both specified, the 43 | // following processing occurs: 44 | // (1) If the KeyName can be found in the CSP, that key is used. 45 | // (2) If the KeyName does not exist and the KeyFile does exist, the key 46 | // in the KeyFile is installed into the CSP and used. 47 | // (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. 48 | // When specifying the KeyFile, the location of the KeyFile should be 49 | // relative to the project output directory which is 50 | // %Project Directory%\obj\. For example, if your KeyFile is 51 | // located in the project directory, you would specify the AssemblyKeyFile 52 | // attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] 53 | // (*) Delay Signing is an advanced option - see the Microsoft .NET Framework 54 | // documentation for more information on this. 55 | // 56 | [assembly: AssemblyDelaySign(false)] 57 | [assembly: AssemblyKeyFile("")] 58 | [assembly: AssemblyKeyName("")] 59 | -------------------------------------------------------------------------------- /Command/Command.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ErsatzAcumen 4 | { 5 | /// 6 | /// Summary description for Class1. 7 | /// 8 | public class Command 9 | { 10 | public Command() 11 | { 12 | // 13 | // TODO: Add constructor logic here 14 | // 15 | } 16 | } 17 | 18 | public interface ICommandable 19 | { 20 | } 21 | 22 | 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /Command/Command.csproj: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 25 | 45 | 65 | 66 | 67 | 72 | 77 | 82 | 83 | 84 | 85 | 86 | 91 | 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /Modeling.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio 2012 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CellLifeGame1", "CellLifeGame1\CellLifeGame1.csproj", "{F2D678D5-E7D3-483A-90B3-A2A4019098DA}" 4 | EndProject 5 | Global 6 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 7 | Debug|Any CPU = Debug|Any CPU 8 | Release|Any CPU = Release|Any CPU 9 | EndGlobalSection 10 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 11 | {F2D678D5-E7D3-483A-90B3-A2A4019098DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 12 | {F2D678D5-E7D3-483A-90B3-A2A4019098DA}.Debug|Any CPU.Build.0 = Debug|Any CPU 13 | {F2D678D5-E7D3-483A-90B3-A2A4019098DA}.Release|Any CPU.ActiveCfg = Release|Any CPU 14 | {F2D678D5-E7D3-483A-90B3-A2A4019098DA}.Release|Any CPU.Build.0 = Release|Any CPU 15 | EndGlobalSection 16 | GlobalSection(SolutionProperties) = preSolution 17 | HideSolutionNode = FALSE 18 | EndGlobalSection 19 | EndGlobal 20 | -------------------------------------------------------------------------------- /NNModel/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | 4 | // 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | // 9 | [assembly: AssemblyTitle("")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("")] 14 | [assembly: AssemblyCopyright("")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | 18 | // 19 | // Version information for an assembly consists of the following four values: 20 | // 21 | // Major Version 22 | // Minor Version 23 | // Build Number 24 | // Revision 25 | // 26 | // You can specify all the values or you can default the Revision and Build Numbers 27 | // by using the '*' as shown below: 28 | 29 | [assembly: AssemblyVersion("1.0.*")] 30 | 31 | // 32 | // In order to sign your assembly you must specify a key to use. Refer to the 33 | // Microsoft .NET Framework documentation for more information on assembly signing. 34 | // 35 | // Use the attributes below to control which key is used for signing. 36 | // 37 | // Notes: 38 | // (*) If no key is specified, the assembly is not signed. 39 | // (*) KeyName refers to a key that has been installed in the Crypto Service 40 | // Provider (CSP) on your machine. KeyFile refers to a file which contains 41 | // a key. 42 | // (*) If the KeyFile and the KeyName values are both specified, the 43 | // following processing occurs: 44 | // (1) If the KeyName can be found in the CSP, that key is used. 45 | // (2) If the KeyName does not exist and the KeyFile does exist, the key 46 | // in the KeyFile is installed into the CSP and used. 47 | // (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. 48 | // When specifying the KeyFile, the location of the KeyFile should be 49 | // relative to the project output directory which is 50 | // %Project Directory%\obj\. For example, if your KeyFile is 51 | // located in the project directory, you would specify the AssemblyKeyFile 52 | // attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] 53 | // (*) Delay Signing is an advanced option - see the Microsoft .NET Framework 54 | // documentation for more information on this. 55 | // 56 | [assembly: AssemblyDelaySign(false)] 57 | [assembly: AssemblyKeyFile("")] 58 | [assembly: AssemblyKeyName("")] 59 | -------------------------------------------------------------------------------- /NNModel/NNModel.csproj: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 25 | 45 | 65 | 66 | 67 | 72 | 77 | 82 | 83 | 84 | 85 | 86 | 91 | 96 | 101 | 106 | 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /NNModel/NeuralNet.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | 4 | 5 | namespace ErsatzAcumen 6 | { 7 | 8 | /* 9 | * pseudo code: 10 | * 11 | * public neuron collection 12 | * 13 | * private queue of collections of updated nuerons, one collection per timestep 14 | * accessable through method for getting updates that prevents client from changing queue 15 | * 16 | * time granularity 17 | * 18 | * subscribe to each neuron's onneuronupdate event 19 | * 20 | * onneuronupdatehandler will add senderobject to clientupdatedneurons collection 21 | * NNModel should wake if sleeping, or immedietely halt processing and make updates 22 | * determine if procesing should be backed out due to being made obselete by a user 23 | * update 24 | * 25 | * 26 | * 27 | * history stack or deque of historycollections 28 | * each collection showing the pre-updated values of neurons that were 29 | * updated during a timestep, any user editing done between timesteps 30 | * is stored as a collection between the appropriate timesteps 31 | * 32 | * each history item is a shallow copy of the object at the beginning of the timestep 33 | * algorithm for adding item to history 34 | * 35 | * 36 | * class historycollection 37 | * { 38 | * timeframe 39 | * collection of historyitems 40 | * } 41 | * 42 | * public delegate void HistoryAction(object obj); 43 | * class HistoryItem 44 | * { 45 | * object Do;//delegate 46 | * object DoParams;//collection or array of parameters, or null if none needed 47 | * object Undo;//if null, then use Do with UndoParams 48 | * object UndoParams;//if null, then use DoParams for Undo 49 | * } 50 | * 51 | * objects that are historical have an event that is fired when an archivable state change 52 | * has occured, which passes through the event a HistoryItem that the object produces 53 | * the handler for the event can use the history item for stepping backwards in time 54 | * through the objects state and then forward again. Undo/Do. 55 | * Any state defining fields should be private, and the methods/properties through which 56 | * they are accessed should 57 | * Historyitems should be serilizable, but are not valid if the object they are for 58 | * no longer exists. This shouldn't be a problem since delegates maintain a reference 59 | * to the underlying object 60 | * 61 | * stepping back in history can only take you as far as when you first subscribed to the 62 | * state changed event 63 | * it is not practical to have a historyitem that indicates the creation or desctruction 64 | * of an object, as the object won't really be garbage collected as long as a history item 65 | * exists for it due to the fact that delegates maintain a reference to the object 66 | * 67 | * collections will need historical overloads that subscribers can track their state with. 68 | * With many apps, you will have some collection holding objects, and when you no longer 69 | * need an object, then you will remove it from the collection, if that is the only 70 | * reference to the object, then it will get garbage collected(GCed). Keeping a historyitem 71 | * for an object will prevent it from being GCed, or keeping a historyitem for that collection 72 | * in which a param of the history item is a reference to that object will also prevent the 73 | * object from being GCed. For example, if the history item is to undo the removal of an 74 | * item from a collection, then the undo delegate will likely be a call to Add on the 75 | * collection, with the object as the param. 76 | * 77 | * 78 | * 79 | * 80 | 81 | 82 | */ 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | } -------------------------------------------------------------------------------- /NNModel/Neuron.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | 4 | 5 | 6 | 7 | namespace ErsatzAcumen 8 | { 9 | /// 10 | /// Stores and provides threadsafe access 11 | /// to the properties of neurons. 12 | /// 13 | public class Neuron 14 | { 15 | 16 | 17 | 18 | 19 | 20 | public Neuron() 21 | { 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | // 30 | // TODO: Add constructor logic here 31 | // 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /NNModel/UniqueID.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ErsatzAcumen 4 | { 5 | 6 | /* 7 | /// 8 | /// UniqueID was an idea to provide IDs that were unique. 9 | /// But the default hashcodes of references are sufficient 10 | /// for most applications. 11 | /// 12 | public class UniqueID 13 | { 14 | /// 15 | /// A list of IDs available previously used IDs 16 | /// This is to avoid an object ID value from overflowing 17 | /// an integer when many objects are created and destroyed, 18 | /// which would result in new objects getting higher and 19 | /// higher ID values. 20 | /// 21 | private static Queue recycledIDs; 22 | 23 | /// 24 | /// The value of the next node ID to be issued, if 25 | /// there are none available in recycledIDs. 26 | /// 27 | private static int nextID=0; 28 | 29 | private static int getNextID() 30 | { 31 | 32 | if(recycledIDs==null) 33 | { 34 | int useID = this.nextID; 35 | ++this.nextID; 36 | return useID; 37 | } 38 | //else there are recylcedIDs to be used 39 | return (int) recycledIDs.Dequeue(); 40 | } 41 | 42 | private readonly int id; 43 | 44 | public int ID 45 | { 46 | get 47 | { 48 | return id; 49 | } 50 | } 51 | 52 | public UniqueID() 53 | { 54 | this.id = getNextID(); 55 | } 56 | 57 | public override int GetHashCode() 58 | { 59 | return ID; 60 | } 61 | }*/ 62 | } 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Source: See Github "Download Zip" link on the right. 2 | 3 | Program(already compiled EXE): https://github.com/AaronLS/CellularAutomataAsNeuralNetwork/releases 4 | 5 | CellularAutomataAsNeuralNetwork 6 | =============================== 7 | This was the project I wrote while learning C# for the first time, many years ago, and I also wrote an undergraduate thesis on the mathematics of converting outer totalistic cellular automata into a neural network. It is pretty common to convert one computational system into another, for various reasons(perhaps the tools you have at hand are better at processing the second computational system), therefore it is potentially useful to know how to convert one system to another. Whether this particular conversion has practical applications is unknown to me. One possible application would be if you had a system that you were able to model satisfactorily with a cellular automata, but wanted to use a specialized neural network chip(a chip specialized for processing neural networks which would perform many times faster than a conventional chip at the same task) or perhaps in the future a similar memristor chip. This is pure speculation on my part, as the firing function my neural network uses is not a simple threshold. It has several thresholds firing zones. For Conway's Game of Life, the firing threshold is between .28 and .4, so the input neuron connections must be within that range, as opposed to a more traditional firing theshold of just bein grater than an amount. More complex cellular automata that you design with my program might have several zones. 8 | 9 | Runs John Conway's Game of Life or any other outer totalistic cellular automata you define, but internally cells states are represented as neuron firing states, and rules are converted to neuron waits and firing function thresholds. 10 | 11 | Disclaimer 12 | ========== 13 | This application was originally written against .NET 1.1, and therefore by today's standards might be considered poorly written, as there is a good bit of non-generic collections which aren't typesafe(I actually had an internal conflict about this, as I was remotely familiar with Java which at the time DID have generics, and I was frustrated by the lack in C#). It was also my very first C# application, and I am posting only because it 1) Is pretty fun to play with and make your own cellular automata 2) I spent alot of time optimizing it so it would run with exceptable performance 3) Many people who have seen it in action have asked for the source code. 14 | 15 | Additionally, modelling neural networks varies by a great degree in terms of both artificial vs natural modelling, as well as simplistic to complex/accurate modelling. Natural neurons usually do not have quite so distinct states as firing and not firing, My usage of the term neural network refers as at the simplistic artificial end of the spectrum. 16 | 17 | If you flame me for coding style or architecture, I will point you to this disclaimer and you must admit you are an idiot for basically flaming someone for something that any sane person would expect to have mistakes(given that it was my first C# application and also written before many of today's C# language constructs existed). 18 | 19 | Known Bug 20 | ========= 21 | The process often remains open when the window is closed. I never bothered to fix this as I wasn't planning to release to the public, and it is easy enough to Ctrl+Shift+Esc and close the process. 22 | 23 | Architecture 24 | ============ 25 | Platform: Windows 32bit/x86 26 | UI: Windows Forms 27 | IDE: Visual Studio, current *sln file opens in VS 2012 Express for Desktop or VS 2012 Standard or greater. I created the project originally under VS 2003 with .NET 1.1, so there is no reason you shouldn't be able to make a older sln and csproj files for an older VS. 28 | Language: C# 29 | Framework: Code is compatible with Microsoft .NET 1.1, in the current solution I have tested against both 2.0 and 4.5 30 | 31 | The main challenge was getting all those squares to update each time step in a smoothly and quickly. This was initially painfully slow on computer hardware 10 years ago. This simple architecture resolved this issue. 32 | 33 | A background thread(Modelling.cs) models the neural network and adds updates to a queue, while the UI(UIForm.cs) thread consumes that queue and displays the updates via double buffered GDI. Even though I had a single core processor at the time you might think multithreading would convey no benefits, but updating a UI thread from a background thread usually requires marshaling the calls, which degrades performance. Additionally, if this application were single threaded, the UI would often freeze while the neural network was updating(this can be mitigated in a *hackish* way by judicial use of DoWork). However, using a queue to communicate updates from one thread to another avoids making marshaled UI thread calls and allows the UI to remain responsive while the other thread performs neural network modelling. 34 | 35 | Both neural networks(see disclaimer on terminology) and simple cellular automata operate in 2 distinct state of alive/firing and dead/not-firing. Both also consist of many identical units, neurons and cells, which all operate simultaneously. Since a 64x64 grid of cells consists of over 4000 cells, we cannot have simultaneous execution of all 4000 cells without a 4000 core processor. In the absence of such a processor, we must simulate this simultaneous execution by maintaining two models of the system: the current time step, and the next time step(or previous and current depending on how you look at it). The current time step has the states of all 4000 cells, whether they are alive or dead. As we calculate the state of the cell in the next time step, we must use the states of neighbors in the current time step, but update the state of the cell only in the next time step. Otherwise, if we didn't have a next and current, imagine if 36 | -We must go cell by cell to update the states of all cells from timestep 1 to timestep 2. 37 | -Cell A in time step 1 is alive, but in timestep 2 we calculate that it is dead based on inputs from neighboring cells, and update its state. 38 | -Cell B in time step 1 is dead, and based on the inputs of its neighbors, we calculate its state in timestep 2. The states we use from its neighbors should all be their states in timestep 1, however, we already updated Cell A, and therefore are using an invalid future state for the calculation. 39 | Thus you see why it is so important to "buffer" these changes until you have processed all cells, then swap the next time step with the current. 40 | 41 | There are some thread synchronization techniques demonstrated in this project. Most of them I learned from reading articles at the time, so hopefully they are not poor examples. However, I will say in my many years of programming, while I have used background threads, I have usually designed my applications to avoid any need for this kind of low level thread synchronization *because it is painful, tedious, and error prone to write*. I generally avoid writing low level thread sync code by instead using constructs of background threads of the .NET framework and events like ProgressChanged/RunWorkercompleted, or the new async/await constructs added to C#. I'm not saying low level thread sync' is obsolete, but many common scenarios are more easily implemented using other techniques. Low level thread synchronization is probably still applicable where your needs don't fit one of those scenarios, and you feel you could *significantly improve performance*. This implies your that there is both a large potential performance gain to be had, *and* your skills make you capable of realizing those gains without also introducing thread safety bugs. For example, this application has a bug that causes the process to often remain open when the window is closed, which I suspect is related to the background thread. 42 | 43 | Binary serialization is demonstrated, showing how to save the state of the cells and rules to a file, and then later load that file to restore those cells/rules. It is generally a better practice to use some other serialization such as XML or JSON(my personal favorite) which is human readable. The reason this is favored over binary is because it allows others look at the file and easily see its structure, and thus create programs to read these files and modify them in an automated way, or even manually edit them in a text editor. Perhaps you wanted to make a HTML5 or java applet that can load rules created in my application, and display the cellular automata in a browser. If the file is in a human readable format, it makes it much easier for you to determine its structure and thus write code to load it. Additionally most other languages have libraries that support JSON and XML. A binary format, while not impossible to figure out, would be much more time consuming and error prone to reverse engineer. However, binary formats load/save generally faster and take up less space, but some of today's JSON processors are very fast and the performance benefits of binary are becoming negligible. 44 | 45 | Usage 46 | ===== 47 | Once you have compiled and run the program: 48 | Left click a blue square to turn it red. Right click to turn it back blue. Both left/right click support dragging to draw cells. Note that this is somewhat imperfect, and fast drags will miss cells, since it does not interpolate skipped cells(i.e. when you drag very quickly Windows does not trigger the event on some cells, and you would need to write code to calculate a line between previous cell to know which cells inbetween to update). 49 | 50 | **Start**: Begins stepping the neural network/cellular automata at a rate controlled by the slider on the left. Slider: Moving the slider all the way down attempts to process one step per millisecond, but it is unlikely to run quite that fast even on newer hardware(there are 4000 neurons and over 30000 neuron connections to process each timestep). 51 | 52 | **Stop**: Pauses processing until you click Start again. 53 | 54 | **Step**: Steps forward a number of steps in the box on the right. Since the UI is not updated during this processing, it allows faster processing to occur over a large number of steps. Or if you are wanting to study how a cellular automata progresses step by step, allows you to control stepping one step at a time. 55 | 56 | **Clear**: Clears the cells setting them to dead/not-firing, but leaves existing rules in place. 57 | 58 | **Save**: Saves the existing cell states and rules to a file. 59 | 60 | **Load**: Load a previously saved file. 61 | 62 | **New**: Clears current rules and allows you to define a new outer totalistic cellular automata. 63 | 64 | -Totalistic Automata basically have rules that are based on a count of the number of neighboring cells that are in a certain state. My program only supports 2 states: alive and dead("asleep" if you want to keep it G rated). 65 | 66 | -After clicking new, you will be in a totally different mode(although the UI does not change much to indicate this), presented with a single white square, and red squares define the *relative* position of neighbors. This allows you to define the neighborhood, where cells are counted for rules. For example, the Game of Life only counts the immediate neighbors of each cell, including those diagonal, so initially you will see that 8 red squares around the white square are selected, as this is the default for the Game of Life. You could define your own cellular automata that includes the next outer layer of neighbors by left clicking those blue squares to turn them red. (Tip: for some really odd behavior, try a lopsided/assymetric neighborhood). 67 | 68 | **Current**: Same as New, except it keeps existing neighborhood and rule definitions, instead of clearing them and resetting to the Game of Life definition. 69 | 70 | **Done**: Click this after you finish defining your neighborhood. You will then be asked one or two questions about your automata. 71 | 72 | -"Is your automata Outer Totalistic?" is asking whether you want seperate distinct rules based on whether the current cell(center) is alive. (I'm not sure my use of the term Outer Totalistic in this way is completely accurate). For the Game of Life you would choose Yes, as you need to be able to make the distinction that when 2 neighbors are alive, nothing changes, thus you need two different rules (If center is alive & two neighbors are alive, then result is alive) (If center is dead & two neighbors are alive, then result is dead). If you choose No to this question, then whether the center is alive or not is not a distinct condition, in other words the rule can be no more complicated than (If 2 neighboring cells are alive, then the cell is dead.) which doesn't provide enough complexity to model Conway's Game of Life. 73 | 74 | -"Is the center cell part of the neighborhood?" is asked only if you choose No to the above question, and is essentially asking if when counting up the total number of alive cells in the neighborhood, if the current center cell should contribute to that count. 75 | 76 | -You are then presented with a dialog that lists all the possible scenarios for a cell in your automata. For each, you select the checkbox on the right if that scenario should result in life for the cell. So checking the box next to "Neighbors alive: 3" indicates that if a cell has 3 cells in its neighborhood which are alive, then it to should be alive in the next time step(perhaps it was already alive, and hence the rule ensures it remains alive, or it was dead and will become alive in the next time step). 77 | 78 | -The three disabled box at the top simply show you the properties of the neural network that will be generated based on your selected rules. 79 | 80 | -"Neighbor Link Weight": The link weights between neighboring neurons in the generated neural network(neighboring being defined by the neighborhood you defined previously) 81 | 82 | -"Center Link Weight": If greater than 0, indicates that eveery neuron will have a link to itself, i.e. if it is in a firing state, then in the next time step it will contribute that much to it's own input signal. 83 | 84 | -"Activation Values": When calculating the next time step, all input signals must add to one of these amounts for the current neuron to fire. 85 | 86 | The magic of cellular automata is in the way that you get a system that appears to be relatively complex, from fairly simple rules. I liken this to the complexity of an ant colony, despite the relative simplicity of the individual ants(although in defense of the ant, it does have 250,000 neurons). 87 | 88 | 89 | -------------------------------------------------------------------------------- /Recording/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | 4 | // 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | // 9 | [assembly: AssemblyTitle("")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("")] 14 | [assembly: AssemblyCopyright("")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | 18 | // 19 | // Version information for an assembly consists of the following four values: 20 | // 21 | // Major Version 22 | // Minor Version 23 | // Build Number 24 | // Revision 25 | // 26 | // You can specify all the values or you can default the Revision and Build Numbers 27 | // by using the '*' as shown below: 28 | 29 | [assembly: AssemblyVersion("1.0.*")] 30 | 31 | // 32 | // In order to sign your assembly you must specify a key to use. Refer to the 33 | // Microsoft .NET Framework documentation for more information on assembly signing. 34 | // 35 | // Use the attributes below to control which key is used for signing. 36 | // 37 | // Notes: 38 | // (*) If no key is specified, the assembly is not signed. 39 | // (*) KeyName refers to a key that has been installed in the Crypto Service 40 | // Provider (CSP) on your machine. KeyFile refers to a file which contains 41 | // a key. 42 | // (*) If the KeyFile and the KeyName values are both specified, the 43 | // following processing occurs: 44 | // (1) If the KeyName can be found in the CSP, that key is used. 45 | // (2) If the KeyName does not exist and the KeyFile does exist, the key 46 | // in the KeyFile is installed into the CSP and used. 47 | // (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. 48 | // When specifying the KeyFile, the location of the KeyFile should be 49 | // relative to the project output directory which is 50 | // %Project Directory%\obj\. For example, if your KeyFile is 51 | // located in the project directory, you would specify the AssemblyKeyFile 52 | // attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] 53 | // (*) Delay Signing is an advanced option - see the Microsoft .NET Framework 54 | // documentation for more information on this. 55 | // 56 | [assembly: AssemblyDelaySign(false)] 57 | [assembly: AssemblyKeyFile("")] 58 | [assembly: AssemblyKeyName("")] 59 | -------------------------------------------------------------------------------- /Recording/Recording.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Recording 4 | { 5 | /// 6 | /// Summary description for Class1. 7 | /// 8 | public interface IRecordable 9 | { 10 | 11 | } 12 | 13 | public class Record 14 | { 15 | public Record() 16 | { 17 | // 18 | // TODO: Add constructor logic here 19 | // 20 | } 21 | 22 | /// 23 | /// Winds the record time forwards by timespan(or backwards if timespan is negative). 24 | /// 25 | /// 26 | /// 27 | public object WindForwards( TimeSpan timeSpan); 28 | 29 | /// 30 | /// Winds the record time backwards by timespan(or forwards if timespan is positive). 31 | /// 32 | /// Example: 33 | /// 34 | public object WindBackwards( TimeSpan timeSpan); 35 | 36 | public object WindForwards( TimeSpan timeSpan, object external); 37 | 38 | public object WindBackwards( TimeSpan timeSpan, object external); 39 | 40 | public object GetState( object external );//RETURN the state of the internal copy that correlates with the external object 41 | 42 | public object Do();//undoes the most recent undo 43 | 44 | public object Undo();//undoes the most recently performed action(s), performed either by a call to any of the Do methods or an action performed on an object by the client 45 | 46 | public object Do( object external );//steps an internal object forward by one action, returns a copy of internal 47 | 48 | public object Undo( object external );//steps an internal object backwards by one action, returns a copy of internal 49 | 50 | //Todo: add do and undo that operate on a collection of items 51 | 52 | public object DoAll();//steps all internal objects by one action 53 | //Todo: Return should be void or maybe some type of colletion 54 | 55 | public object UndoAll();//steps all internal objects backwards by one action 56 | //Todo: Return should be void or maybe some type of collection 57 | 58 | //+= operator 59 | //GetState and add object "+=" could be implemented with the indexer operator if appropriate. 60 | 61 | 62 | 63 | } 64 | } 65 | 66 | 67 | /* 68 | * 69 | * Usability Goals: 70 | *1.Allow the client to declare an object that will maintain a record of the changes of the state of a set of objects: 71 | * Record aRecord = new Record( ***TBD*** ); 72 | * 73 | *2.Allow the client to add objects to the record and have their state tracked from the point they were added forward until a point where they are removed: 74 | * objectType anObject = new objectType(); 75 | * myRecord += anObject;//add object to Record to be recorded, a snapshot of it's current state is copied into the record and the object referenced is marked to be watched for changes 76 | * anObject.DoSomething(someParams);//this call will be added to the entry in myRecord for the object referenced by anObject 77 | * Implementation Issues: 78 | * a. A member call that involves outparams may be difficult to record. 79 | * 80 | *3.Allow recording to be stopped for an object: 81 | * myRecord -= anObject; 82 | * 83 | *4.Allow the client to go back to a point in a records timeline by rewinding, and later set the record at current time again. 84 | * 85 | * Design Issues: 86 | * a. Two options: 87 | * I. Set the state of the client's objects to the past state. 88 | * Pro:Memory saved because we don't keep a copy of the objects in the record. 89 | * Con:Any instability or bug in our class or the client's implementation of IRecordable could corrupt the client object's state. 90 | * II.Set the state of a copy of the object to the past state and allow the client access to the past objects. 91 | * Pro:Avoid corruption of client data. 92 | * Con:The client object's state is not updated which the client may desire so that they can rewind the state of their application. 93 | * The second option better because a client can use a Record for not-critical purposes and not worry about data corruption. It also allows them to only stub out IRecordable implementations and put off full implementation if their application is not dependent on the Record, thus allowing easier incremental development. The con of the second option may be avoidable, and will be addressed if a viable implementation is found. The phrases internal object(s) and external object(s) refer respectively to the copy object internal to the Record and the external object of the client. 94 | * 95 | * 96 | * 97 | * 98 | * 99 | * 100 | * 101 | * 102 | * 103 | * 104 | * */ -------------------------------------------------------------------------------- /Recording/Recording.csproj: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 25 | 45 | 65 | 66 | 67 | 72 | 77 | 82 | 83 | 84 | 85 | 86 | 91 | 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /ThesisAaronShumaker.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AaronLS/CellularAutomataAsNeuralNetwork/fe9e6b950e5e28d2c99350cb8ff3157720555e14/ThesisAaronShumaker.pdf -------------------------------------------------------------------------------- /ThreadSafe/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | 4 | // 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | // 9 | [assembly: AssemblyTitle("")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("")] 14 | [assembly: AssemblyCopyright("")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | 18 | // 19 | // Version information for an assembly consists of the following four values: 20 | // 21 | // Major Version 22 | // Minor Version 23 | // Build Number 24 | // Revision 25 | // 26 | // You can specify all the values or you can default the Revision and Build Numbers 27 | // by using the '*' as shown below: 28 | 29 | [assembly: AssemblyVersion("1.0.*")] 30 | 31 | // 32 | // In order to sign your assembly you must specify a key to use. Refer to the 33 | // Microsoft .NET Framework documentation for more information on assembly signing. 34 | // 35 | // Use the attributes below to control which key is used for signing. 36 | // 37 | // Notes: 38 | // (*) If no key is specified, the assembly is not signed. 39 | // (*) KeyName refers to a key that has been installed in the Crypto Service 40 | // Provider (CSP) on your machine. KeyFile refers to a file which contains 41 | // a key. 42 | // (*) If the KeyFile and the KeyName values are both specified, the 43 | // following processing occurs: 44 | // (1) If the KeyName can be found in the CSP, that key is used. 45 | // (2) If the KeyName does not exist and the KeyFile does exist, the key 46 | // in the KeyFile is installed into the CSP and used. 47 | // (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. 48 | // When specifying the KeyFile, the location of the KeyFile should be 49 | // relative to the project output directory which is 50 | // %Project Directory%\obj\. For example, if your KeyFile is 51 | // located in the project directory, you would specify the AssemblyKeyFile 52 | // attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] 53 | // (*) Delay Signing is an advanced option - see the Microsoft .NET Framework 54 | // documentation for more information on this. 55 | // 56 | [assembly: AssemblyDelaySign(false)] 57 | [assembly: AssemblyKeyFile("")] 58 | [assembly: AssemblyKeyName("")] 59 | -------------------------------------------------------------------------------- /ThreadSafe/ThreadSafe.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | namespace ErsatzAcumen 5 | { 6 | /// 7 | /// Utilities for locking class types. 8 | /// Potential-deadlock checking is provided 9 | /// in debug mode, while release code does not. 10 | /// 11 | public class ThreadSafe 12 | { 13 | #if DEBUG 14 | 15 | static TimeSpan maxWaited; 16 | static long TimesWaited; 17 | 18 | static ThreadSafe() 19 | { 20 | maxWaited = TimeSpan.Zero; 21 | TimesWaited = 0; 22 | } 23 | 24 | static public void Enter(object obj) 25 | { 26 | try 27 | { 28 | bool isOk = true; 29 | for(TimeSpan Wait = new TimeSpan(0,0,1); 30 | isOk == true; 31 | Wait.Add(TimeSpan.FromSeconds(10)) ) 32 | { 33 | if(Monitor.TryEnter(obj, Wait) == true) 34 | {//lock acquired 35 | return; 36 | } 37 | else 38 | {//lock not acquired 39 | 40 | Interlocked.Increment(ref TimesWaited); 41 | lock(maxWaited) 42 | { 43 | if(maxWaited < Wait) 44 | { 45 | maxWaited = Wait; 46 | Console.Write("Potential deadlock, maxWaited is now {0} seconds. Waiting more...",maxWaited.Seconds); 47 | } 48 | } 49 | } 50 | } 51 | } 52 | catch 53 | { 54 | throw; 55 | } 56 | 57 | } 58 | 59 | static public void Exit(object obj) 60 | { 61 | Monitor.Exit(obj); 62 | } 63 | 64 | #else 65 | static public void Enter(object obj) 66 | { 67 | try 68 | { 69 | Monitor.Enter(obj); 70 | } 71 | catch 72 | { 73 | throw; 74 | } 75 | } 76 | 77 | static public void Exit(object obj) 78 | { 79 | try 80 | { 81 | Monitor.Exit(obj); 82 | } 83 | catch 84 | { 85 | throw; 86 | } 87 | } 88 | 89 | #endif 90 | 91 | } 92 | } 93 | 94 | -------------------------------------------------------------------------------- /ThreadSafe/ThreadSafe.csproj: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 25 | 45 | 65 | 66 | 67 | 72 | 77 | 82 | 83 | 84 | 85 | 86 | 91 | 96 | 97 | 98 | 99 | 100 | 101 | --------------------------------------------------------------------------------