//public static T GetTypedValue<T>(CAProperty property) //{ // dynamic value = property.value; // return value; //} public static Bitmap MakeImage(CA ca) { CAGraph graph = ca.Graph; CASettings settings = ca.Settings; // needs to be SVG that returns various types if (graph.Shape == GridShape.Square) { int x = graph.Cells.GetLength(0); int y = graph.Cells.GetLength(1); int z = graph.Cells.GetLength(2); Bitmap bmp = new Bitmap(x, y); using (Graphics g = Graphics.FromImage(bmp)) { for (ushort i = 0; i < z; i++) { Bitmap layer = new Bitmap(x, y); for (ushort j = 0; j < x; j++) { for (ushort k = 0; k < y; k++) { var cell = graph.GetCell(new ValueTuple <ushort, ushort, ushort>(j, k, i)); Color color = Color.Black; if (cell != null) { if (cell.ContainsAgent()) { int state = cell.Agent.GetStateProperty(); if (settings.StateColorMap.Count >= state) { color = settings.StateColorMap[state]; } } } layer.SetPixel(j, k, color); } } g.DrawImage(layer, new Point(0, 0)); } } return(bmp); } else { throw new Exception("Graph shape not expected."); } }
public static void ChemicalEquilibrium(ValueTuple <ushort, ushort, ushort> dimensions, List <List <double> > probabilities, string savePath, ValueTuple <ulong, double, double> convergeanceConditions, CASettings settings = null) { List <(string, dynamic)> stateProperties = new List <(string, dynamic)>(); for (int i = 0; i < probabilities.Count; i++) { if (probabilities[i].Count != (probabilities.Count - 1)) { throw new Exception("Each state must include a probability of conversion to every other state (NOT its own)"); } stateProperties.Add(("state", (ushort)i)); } var noneNeighborhood = new CANeighborhood(CANeighborhoodType.None); var localTarget = new CATarget(CAScale.Local, CAEntityType.Agent, noneNeighborhood); CA ca = new CA(dimensions, GridShape.Square); if (settings != null) { ca.Settings = settings; } else { ca.Settings = new CASettings { CopyFormat = CACopyFormat.Reference, StateColorMap = StaticMethods.GetColors(probabilities.Count), /*StoreChangeCounts = true,*/ StoreCounts = true, Subprocessing = false, StoreTransitions = true }; } ca.Settings.States = (ushort)probabilities.Count; for (int i = 0; i < probabilities.Count; i++) { ca.AddAgents((1.0 / probabilities.Count), (ushort)i, true); int val = 0; CAIf stateif = new CAIf("state", CATargetType.All, localTarget, CAEquality.Equal_to, stateProperties[i]); for (int j = 0; j < probabilities.Count; j++) { if (i == j) { continue; } CAThenChange changeThen = new CAThenChange(localTarget, "state", CAOperator.Equal, (ushort)j, probabilities[i][val]); CARule changeRule = new CARule(new List <CAIf> { stateif }, new List <CAThen> { changeThen }); ca.AddRule(changeRule); val++; } } CAExitCondition exit = new CAExitConditionConvergeance(convergeanceConditions.Item1, convergeanceConditions.Item2, convergeanceConditions.Item3); ca.CreateExitCondition(exit); DateTime start = DateTime.Now; //bool alive = true; Console.WriteLine("Every iteration, the CA will check that the population counts have changed by less than " + (convergeanceConditions.Item2 > 1? ((int)convergeanceConditions.Item2).ToString() + " cells":(convergeanceConditions.Item2 * 100).ToString() + "%") + " (for a single state)."); Console.WriteLine("It will then check for >" + convergeanceConditions.Item1 + " iterations, then " + (convergeanceConditions.Item3 > 1 ? ((int)convergeanceConditions.Item3).ToString() + " iterations" : (convergeanceConditions.Item3 * 100).ToString() + "%") + " of the total iterations, where the previous predicate is true (consecutively)."); Console.WriteLine("It will automatically end at that time, but you can exit early by pressing Escape. Your data up to that point will be saved."); Console.WriteLine("Press Enter to begin."); Console.ReadKey(); DateTime now = DateTime.Now; Task output = Task.Factory.StartNew(() => { while (!ca.Exit && !(Console.KeyAvailable && Console.ReadKey(true).Key == ConsoleKey.Escape)) { ca.Run(); Console.Write("\rIteration {0}, Counts: {1}", ca.Iteration, String.Join(", ", ca.CurrentCounts) + " "); } Console.WriteLine(""); }); output.Wait(); Console.WriteLine("Task complete after: " + (DateTime.Now - now).TotalSeconds + " seconds"); var probString = probabilities.Select(x => x.Select(y => y.ToString()).ToList()).ToList(); for (int i = 0; i < probString.Count; i++) { probString[i].Insert(0, i.ToString()); } // save data List <List <string> > header = new List <List <string> >() { new List <string> { now.ToString("o") }, new List <string> { "Chemical Equilibrium" }, new List <string> { "Probabilities" } }; header.AddRange(probString); ca.Save(header, ca.ListSaveProperties(), savePath + System.IO.Path.DirectorySeparatorChar + start.ToString("o").Replace(':', '.') + " Iteration " + ca.Iteration + " Data.csv"); Console.WriteLine("Data saved to: " + savePath + System.IO.Path.DirectorySeparatorChar + start.ToString("o").Replace(':', '.') + " Iteration " + ca.Iteration + " Data.csv"); Console.WriteLine(); Console.WriteLine("Enter Y to save image, and anything else to skip."); bool saveImage = false; var key = Console.ReadLine(); if (key.ToLower().Equals("y")) { saveImage = true; } else { Console.WriteLine("Are you sure? Enter Y to save image, and anything else to skip."); key = Console.ReadLine(); if (key.ToLower().Equals("y")) { saveImage = true; } } if (saveImage) { var image = StaticMethods.MakeImage(ca); string filename = savePath + System.IO.Path.DirectorySeparatorChar + start.ToString("o").Replace(':', '.') + " Iteration " + ca.Iteration + " Image.bmp"; image.Save(filename, System.Drawing.Imaging.ImageFormat.Bmp); Console.WriteLine("Saved to {0}.", filename); } Console.WriteLine("Complete. Press any key to exit."); Console.ReadKey(); }