diff --git a/.idea/.idea.Life/.idea/contentModel.xml b/.idea/.idea.Life/.idea/contentModel.xml
index bbb2548..c8da571 100644
--- a/.idea/.idea.Life/.idea/contentModel.xml
+++ b/.idea/.idea.Life/.idea/contentModel.xml
@@ -23,6 +23,7 @@
+
@@ -36,6 +37,7 @@
+
diff --git a/Life/Automaton/BasicField.cs b/Life/Automaton/BasicField.cs
index 745fa2e..100db3f 100644
--- a/Life/Automaton/BasicField.cs
+++ b/Life/Automaton/BasicField.cs
@@ -46,6 +46,11 @@ namespace Life.Automaton
_observers.ForEach(observer => observer.OnNext(this));
}
+ public void Notify()
+ {
+ _observers.ForEach(observer => observer.OnNext(this));
+ }
+
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
diff --git a/Life/Automaton/GameOfLife.cs b/Life/Automaton/GameOfLife.cs
index 76e2886..02a1f22 100644
--- a/Life/Automaton/GameOfLife.cs
+++ b/Life/Automaton/GameOfLife.cs
@@ -2,9 +2,14 @@
namespace Life.Automaton
{
- public static class GameOfLife
+ public class GameOfLife : IAutomaton
{
- public static Rule Rule(string born, string survive)
+ public GameOfLife(int width, int height)
+ {
+ Initialize(new MooreField(width, height));
+ }
+
+ public static Rule MakeRule(string born, string survive)
{
bool WillSurvive(int neighbours) => survive.Contains(neighbours.ToString());
bool WillBorn(int neighbours) => born.Contains(neighbours.ToString());
@@ -29,5 +34,22 @@ namespace Life.Automaton
return @new;
};
}
+
+ public Rule Rule { get; set; } = MakeRule("3", "32");
+
+ public int Iteration { get; private set; }
+
+ public IField Field { get; private set; }
+
+ public void Initialize(IField field)
+ {
+ Field = field;
+ }
+
+ public void Advance()
+ {
+ Field.Transform(Rule);
+ Iteration++;
+ }
}
}
\ No newline at end of file
diff --git a/Life/Automaton/IField.cs b/Life/Automaton/IField.cs
index 707ddce..de3905d 100644
--- a/Life/Automaton/IField.cs
+++ b/Life/Automaton/IField.cs
@@ -17,5 +17,6 @@ namespace Life.Automaton
IEnumerable Neighbours(int x, int y);
void Transform(Rule rule);
+ void Notify();
}
}
\ No newline at end of file
diff --git a/Life/AutomatonField.xaml b/Life/AutomatonField.xaml
index a51480c..baf9954 100644
--- a/Life/AutomatonField.xaml
+++ b/Life/AutomatonField.xaml
@@ -47,7 +47,7 @@
diff --git a/Life/AutomatonField.xaml.cs b/Life/AutomatonField.xaml.cs
index e635789..afe1d5a 100644
--- a/Life/AutomatonField.xaml.cs
+++ b/Life/AutomatonField.xaml.cs
@@ -1,9 +1,6 @@
-using System;
-using System.Collections.ObjectModel;
-using System.Windows;
+using System.Windows;
using System.Windows.Controls;
-using System.Windows.Media;
-using System.Windows.Shapes;
+using System.Windows.Input;
using Life.Automaton;
using Life.ViewModel;
@@ -29,6 +26,12 @@ namespace Life
get { return (IField) GetValue(FieldProperty); }
set { SetValue(FieldProperty, value); }
}
+
+ public ICommand ClickCommand
+ {
+ get { return (ICommand) GetValue(ClickCommandProperty); }
+ set { SetValue(ClickCommandProperty, value); }
+ }
#endregion
public FieldViewModel ViewModel { get; set; } = new FieldViewModel();
@@ -77,16 +80,12 @@ namespace Life
typeof(IField), typeof(AutomatonField),
new PropertyMetadata(OnFieldChanged)
);
+
+ public static readonly DependencyProperty ClickCommandProperty = DependencyProperty.Register(
+ nameof(ClickCommand),
+ typeof(ICommand), typeof(AutomatonField)
+ );
+
#endregion
-
- private void Cell_Click(object sender, RoutedEventArgs e)
- {
- var vm = (sender as Button).DataContext as CellViewModel;
- var cell = Field[vm.Position.X, vm.Position.Y];
-
- cell.IsAlive = !cell.IsAlive;
-
- ViewModel.Sync();
- }
}
}
\ No newline at end of file
diff --git a/Life/MainWindow.xaml b/Life/MainWindow.xaml
index 0c9c256..66d8836 100644
--- a/Life/MainWindow.xaml
+++ b/Life/MainWindow.xaml
@@ -4,17 +4,18 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Life"
+ xmlns:vm="clr-namespace:Life.ViewModel"
mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800" d:DataContext="{d:DesignInstance local:MainWindow}">
+ Title="MainWindow" Height="450" Width="800" d:DataContext="{d:DesignInstance vm:AutomatonViewModel}">
-
+
-
+
@@ -31,8 +32,7 @@
-
-
+
diff --git a/Life/MainWindow.xaml.cs b/Life/MainWindow.xaml.cs
index c54c3ab..c731db2 100644
--- a/Life/MainWindow.xaml.cs
+++ b/Life/MainWindow.xaml.cs
@@ -1,63 +1,28 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Runtime.CompilerServices;
-using System.Windows;
-using Life.Annotations;
+using System.Windows;
using Life.Automaton;
+using Life.ViewModel;
namespace Life
{
///
/// Interaction logic for MainWindow.xaml
///
- public partial class MainWindow : Window, INotifyPropertyChanged
+ public partial class MainWindow : Window
{
- private IField _field;
- private int _size;
- private Rule _rule = GameOfLife.Rule("3", "23");
-
- public IField Field
- {
- get => _field;
- set
- {
- _field = value;
- OnPropertyChanged(nameof(Field));
- }
- }
-
- public int Size
- {
- get => _size;
- set
- {
- _size = value;
- OnPropertyChanged(nameof(Size));
- }
- }
+ public AutomatonViewModel ViewModel;
public MainWindow()
{
- Size = 20;
- Field = new MooreField(20, 20);
- Field[5, 5].IsAlive = true;
- DataContext = this;
+ ViewModel = new AutomatonViewModel()
+ {
+ Automaton = new GameOfLife(20, 20),
+ Size = 16,
+ Separation = 2
+ };
+
+ DataContext = ViewModel;
InitializeComponent();
}
-
- private void Step_OnClick(object sender, RoutedEventArgs e)
- {
- Field.Transform(_rule);
- }
-
- public event PropertyChangedEventHandler PropertyChanged;
-
- [NotifyPropertyChangedInvocator]
- protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
- {
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
- }
}
}
\ No newline at end of file
diff --git a/Life/Misc/DelegateCommand.cs b/Life/Misc/DelegateCommand.cs
new file mode 100644
index 0000000..361d142
--- /dev/null
+++ b/Life/Misc/DelegateCommand.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Windows.Input;
+
+namespace Life.Misc
+{
+ public class DelegateCommand : ICommand
+ {
+ public Action Action { get; set; }
+ public Predicate Predicate { get; set; }
+
+ public bool CanExecute(object parameter)
+ {
+ if (Action == null)
+ return false;
+
+ return Predicate?.Invoke((T) parameter) ?? true;
+ }
+
+ public void Execute(object parameter)
+ {
+ Action?.Invoke((T)parameter);
+ }
+
+ public event EventHandler CanExecuteChanged;
+ }
+}
\ No newline at end of file
diff --git a/Life/ViewModel/AutomatonViewModel.cs b/Life/ViewModel/AutomatonViewModel.cs
new file mode 100644
index 0000000..7ac733e
--- /dev/null
+++ b/Life/ViewModel/AutomatonViewModel.cs
@@ -0,0 +1,70 @@
+using System;
+using System.Windows.Input;
+using Life.Automaton;
+using Life.Misc;
+
+namespace Life.ViewModel
+{
+ public class AutomatonViewModel : BaseViewModel
+ {
+
+ private int _size;
+ private int _separation;
+ private IAutomaton _automaton;
+
+ public int Size
+ {
+ get => _size;
+ set
+ {
+ _size = value;
+ OnPropertyChanged(nameof(Size));
+ }
+ }
+
+ public int Separation
+ {
+ get => _separation;
+ set
+ {
+ _separation = value;
+ OnPropertyChanged(nameof(Separation));
+ }
+ }
+
+ public IAutomaton Automaton
+ {
+ get => _automaton;
+ set
+ {
+ _automaton = value;
+ OnPropertyChanged(nameof(Field));
+ OnPropertyChanged(nameof(Iteration));
+ }
+ }
+
+ public IField Field => Automaton.Field;
+ public int Iteration => Automaton.Iteration;
+
+ public ICommand CellClicked => new DelegateCommand
+ {
+ Action = HandleCellClick
+ };
+
+ public ICommand StepCommand => new DelegateCommand |