Free cookie consent management tool by TermsFeed Policy Generator

source: branches/SimulationCore/HeuristicLab.SimulationCore.Samples/3.3/GameOfLifeDiscreteEventSimulation.cs @ 10450

Last change on this file since 10450 was 10450, checked in by abeham, 10 years ago

#1610: Added a base infrastructure for discrete event simulation

File size: 8.1 KB
Line 
1using System;
2using System.Collections.Generic;
3using HeuristicLab.Analysis;
4using HeuristicLab.Common;
5using HeuristicLab.Core;
6using HeuristicLab.Optimization;
7using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
8
9namespace HeuristicLab.SimulationCore.Samples {
10  [Item("Game of Life (discrete event)", "A discrete event based implementation of the game of life simulation.")]
11  [Creatable("Simulations")]
12  public class GameOfLifeDiscreteEventSimulation : DiscreteEventSimulation<GameOfLifeModel> {
13    private GameOfLifeScenario Scenario {
14      get { return Problem as GameOfLifeScenario; }
15      set { Problem = value; }
16    }
17
18    private GameOfLifeDiscreteEventSimulation(GameOfLifeDiscreteEventSimulation original, Cloner cloner)
19      : base(original, cloner) { }
20    public GameOfLifeDiscreteEventSimulation() {
21      Scenario = new GameOfLifeScenario();
22      InitialAction = new InitializeGameOfLifeBoardAction() { AliveRate = Scenario.AliveRateParameter.Value.Value };
23      Activities = new IActivity<GameOfLifeModel>[] { new CurrentTimeMonitor() };
24      Reporters = new IReporter<GameOfLifeModel>[] { new GameOfLifeStateReporter() };
25      Initialize();
26    }
27
28    private void Initialize() {
29      Scenario.WidthParameter.ValueChanged += ValueChanged;
30      if (Scenario.WidthParameter.Value != null) Scenario.WidthParameter.Value.ValueChanged += ParametersChanged;
31      Scenario.HeightParameter.ValueChanged += ValueChanged;
32      if (Scenario.HeightParameter.Value != null) Scenario.HeightParameter.Value.ValueChanged += ParametersChanged;
33      Scenario.AliveRateParameter.ValueChanged += ValueChanged;
34      if (Scenario.AliveRateParameter.Value != null) Scenario.AliveRateParameter.Value.ValueChanged += ParametersChanged;
35    }
36
37
38    private void ValueChanged(object sender, EventArgs e) {
39      if (Scenario.WidthParameter.Value != null) Scenario.WidthParameter.Value.ValueChanged += ParametersChanged;
40      if (Scenario.HeightParameter.Value != null) Scenario.HeightParameter.Value.ValueChanged += ParametersChanged;
41      if (Scenario.AliveRateParameter.Value != null) Scenario.AliveRateParameter.Value.ValueChanged += ParametersChanged;
42      ParametersChanged(sender, e);
43    }
44
45    private void ParametersChanged(object sender, EventArgs e) {
46      Model = new GameOfLifeModel(Scenario.WidthParameter.Value.Value, Scenario.HeightParameter.Value.Value);
47      ((InitializeGameOfLifeBoardAction)InitialAction).AliveRate = Scenario.AliveRateParameter.Value.Value;
48    }
49
50    protected override void OnPrepared() {
51      Model = new GameOfLifeModel(Scenario.WidthParameter.Value.Value, Scenario.HeightParameter.Value.Value);
52      base.OnPrepared();
53    }
54
55    public override IDeepCloneable Clone(Cloner cloner) {
56      return new GameOfLifeDiscreteEventSimulation(this, cloner);
57    }
58  }
59
60  [StorableClass]
61  public sealed class GameOfLifeModel : IModel {
62    [Storable]
63    public double CurrentTime { get; set; }
64    [Storable]
65    public bool[,] Grid { get; set; }
66
67    private GameOfLifeModel(GameOfLifeModel original, Cloner cloner) {
68      cloner.RegisterClonedObject(original, this);
69      CurrentTime = original.CurrentTime;
70      Grid = (bool[,])original.Grid.Clone();
71    }
72    public GameOfLifeModel(int width, int height) {
73      Grid = new bool[height, width];
74    }
75
76    public object Clone() { return Clone(new Cloner()); }
77    public IDeepCloneable Clone(Cloner cloner) {
78      return new GameOfLifeModel(this, cloner);
79    }
80  }
81
82  [StorableClass]
83  sealed class CurrentTimeMonitor : Activity<GameOfLifeModel> {
84    public override IEnumerable<Guid> MonitoredActionIds {
85      get { return new[] { InitializeGameOfLifeBoardAction.Id, ModelTimeUpdateAction<GameOfLifeModel>.Id }; }
86    }
87
88    [StorableConstructor]
89    private CurrentTimeMonitor(bool deserializing) : base(deserializing) { }
90    private CurrentTimeMonitor(CurrentTimeMonitor original, Cloner cloner) : base(original, cloner) { }
91    public CurrentTimeMonitor() : base(new SortedListEventQueue<GameOfLifeModel>()) { }
92
93    public override void ManageEvents(GameOfLifeModel model, IAction<GameOfLifeModel> lastAction) {
94      EventQueue.Push(new Event<GameOfLifeModel>(model.CurrentTime + 1, new UpdateGameOfLifeBoardAction()));
95    }
96
97    public override IDeepCloneable Clone(Cloner cloner) {
98      return new CurrentTimeMonitor(this, cloner);
99    }
100  }
101
102  [StorableClass]
103  sealed class GameOfLifeStateReporter : Reporter<GameOfLifeModel> {
104
105    [StorableConstructor]
106    private GameOfLifeStateReporter(bool deserializing) : base(deserializing) { }
107    private GameOfLifeStateReporter(GameOfLifeStateReporter original, Cloner cloner) : base(original, cloner) { }
108    public GameOfLifeStateReporter() { }
109
110    public override void UpdateReporting(GameOfLifeModel model, ResultCollection results) {
111      var heatmap = new HeatMap(model.Grid.GetLength(0), model.Grid.GetLength(1));
112      for (var i = 0; i < heatmap.Rows; i++)
113        for (var j = 0; j < heatmap.Columns; j++)
114          heatmap[i, j] = model.Grid[i, j] ? 1 : 0;
115
116      if (!results.ContainsKey("Visualization"))
117        results.Add(new Result("Visualization", heatmap));
118      else results["Visualization"].Value = heatmap;
119    }
120
121    public override IDeepCloneable Clone(Cloner cloner) {
122      return new GameOfLifeStateReporter(this, cloner);
123    }
124  }
125
126  [StorableClass]
127  sealed class InitializeGameOfLifeBoardAction : Action<GameOfLifeModel> {
128    public static readonly Guid Id = new Guid("a6d37f71-ccef-4c2a-b11b-793fda0f9f4f");
129    public override Guid ActionId {
130      get { return Id; }
131    }
132
133    [Storable]
134    public double AliveRate { get; set; }
135
136    [StorableConstructor]
137    private InitializeGameOfLifeBoardAction(bool deserializing) : base(deserializing) { }
138    private InitializeGameOfLifeBoardAction(InitializeGameOfLifeBoardAction original, Cloner cloner)
139      : base(original, cloner) {
140      AliveRate = original.AliveRate;
141    }
142    public InitializeGameOfLifeBoardAction() {
143      AliveRate = 0.2;
144    }
145
146    public override void Execute(GameOfLifeModel model) {
147      var random = new Random();
148      var rows = model.Grid.GetLength(0);
149      var cols = model.Grid.GetLength(1);
150      for (var i = 0; i < rows; i++)
151        for (var j = 0; j < cols; j++) {
152          if (random.NextDouble() < AliveRate) model.Grid[i, j] = true;
153        }
154    }
155
156    public override IDeepCloneable Clone(Cloner cloner) {
157      return new InitializeGameOfLifeBoardAction(this, cloner);
158    }
159  }
160
161  [StorableClass]
162  sealed class UpdateGameOfLifeBoardAction : Action<GameOfLifeModel> {
163    public static readonly Guid Id = new Guid("323bb2ef-bc66-488f-ac88-798b91565e62");
164    public override Guid ActionId {
165      get { return Id; }
166    }
167
168    [StorableConstructor]
169    private UpdateGameOfLifeBoardAction(bool deserializing) : base(deserializing) { }
170    private UpdateGameOfLifeBoardAction(UpdateGameOfLifeBoardAction original, Cloner cloner) : base(original, cloner) { }
171    public UpdateGameOfLifeBoardAction() { }
172
173    public override void Execute(GameOfLifeModel model) {
174      var rows = model.Grid.GetLength(0);
175      var cols = model.Grid.GetLength(1);
176      var newGrid = new bool[rows, cols];
177      for (var i = 0; i < rows; i++)
178        for (var j = 0; j < cols; j++) {
179          var neighbors = 0;
180          if (i > 0 && j > 0 && model.Grid[i - 1, j - 1]) neighbors++;
181          if (i > 0 && model.Grid[i - 1, j]) neighbors++;
182          if (i > 0 && j < cols - 1 && model.Grid[i - 1, j + 1]) neighbors++;
183          if (j > 0 && model.Grid[i, j - 1]) neighbors++;
184          if (j < cols - 1 && model.Grid[i, j + 1]) neighbors++;
185          if (i < rows - 1 && j > 0 && model.Grid[i + 1, j - 1]) neighbors++;
186          if (i < rows - 1 && model.Grid[i + 1, j]) neighbors++;
187          if (i < rows - 1 && j < cols - 1 && model.Grid[i + 1, j + 1]) neighbors++;
188          if ((model.Grid[i, j] && neighbors == 2) || neighbors == 3) newGrid[i, j] = true;
189        }
190      model.Grid = newGrid;
191    }
192
193    public override IDeepCloneable Clone(Cloner cloner) {
194      return new UpdateGameOfLifeBoardAction(this, cloner);
195    }
196  }
197}
Note: See TracBrowser for help on using the repository browser.