Zapisywanie i wczytywanie pola

This commit is contained in:
Kacper Donat 2019-10-28 16:12:04 +01:00
parent 093b590ee4
commit 9b0313201b
15 changed files with 145 additions and 1224 deletions

View File

@ -5,7 +5,6 @@
<e p="C:\Users\Kacper\.Rider2019.2\system\resharper-host\local\Transient\ReSharperHost\v192\SolutionCaches\_Life.1627287830.00" t="ExcludeRecursive" /> <e p="C:\Users\Kacper\.Rider2019.2\system\resharper-host\local\Transient\ReSharperHost\v192\SolutionCaches\_Life.1627287830.00" t="ExcludeRecursive" />
<e p="C:\Users\Kacper\Studies\dotnet\Life" t="IncludeFlat"> <e p="C:\Users\Kacper\Studies\dotnet\Life" t="IncludeFlat">
<e p="Life" t="IncludeRecursive"> <e p="Life" t="IncludeRecursive">
<e p="Annotations.cs" t="Include" />
<e p="App.xaml" t="Include" /> <e p="App.xaml" t="Include" />
<e p="App.xaml.cs" t="Include" /> <e p="App.xaml.cs" t="Include" />
<e p="Automaton" t="Include"> <e p="Automaton" t="Include">

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,15 @@
xmlns:local="clr-namespace:Life" xmlns:local="clr-namespace:Life"
StartupUri="MainWindow.xaml"> StartupUri="MainWindow.xaml">
<Application.Resources> <Application.Resources>
<Style x:Key="Header" TargetType="TextBlock">
<Setter Property="FontSize" Value="16" />
<Setter Property="FontWeight" Value="Medium"/>
<Setter Property="Margin" Value="0 0 0 0"/>
</Style>
<Style x:Key="Value" TargetType="TextBlock">
<Setter Property="FontSize" Value="24" />
<Setter Property="FontWeight" Value="Black"/>
<Setter Property="Margin" Value="18 0 0 0"></Setter>
</Style>
</Application.Resources> </Application.Resources>
</Application> </Application>

View File

@ -1,15 +1,15 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.Serialization;
using Life.Annotations;
using Life.Misc; using Life.Misc;
namespace Life.Automaton namespace Life.Automaton
{ {
public abstract class BasicField : IField, INotifyPropertyChanged [Serializable]
public abstract class BasicField : IField, IDeserializationCallback
{ {
[NonSerialized]
List<IObserver<IField>> _observers = new List<IObserver<IField>>(); List<IObserver<IField>> _observers = new List<IObserver<IField>>();
protected BasicField(int width, int height) protected BasicField(int width, int height)
@ -29,7 +29,7 @@ namespace Life.Automaton
public Cell this[int x, int y] public Cell this[int x, int y]
{ {
get => _cells[x, y]; get => _cells[x, y];
set private set
{ {
_cells[x, y] = value; _cells[x, y] = value;
_observers.ForEach(observer => observer.OnNext(this)); _observers.ForEach(observer => observer.OnNext(this));
@ -43,7 +43,8 @@ namespace Life.Automaton
public void Transform(Rule transform) public void Transform(Rule transform)
{ {
_cells = transform(this); _cells = transform(this);
_observers.ForEach(observer => observer.OnNext(this));
Notify();
} }
public void Notify() public void Notify()
@ -51,19 +52,16 @@ namespace Life.Automaton
_observers.ForEach(observer => observer.OnNext(this)); _observers.ForEach(observer => observer.OnNext(this));
} }
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public IDisposable Subscribe(IObserver<IField> observer) public IDisposable Subscribe(IObserver<IField> observer)
{ {
_observers.Add(observer); _observers.Add(observer);
return new DelegateUnsubscriber(() => _observers.Remove(observer)); return new DelegateUnsubscriber(() => _observers.Remove(observer));
} }
public void OnDeserialization(object sender)
{
_observers = new List<IObserver<IField>>();
}
} }
} }

View File

@ -1,7 +1,9 @@
using Life.Misc; using System;
using Life.Misc;
namespace Life.Automaton namespace Life.Automaton
{ {
[Serializable]
public class Cell public class Cell
{ {
public bool IsAlive { get; set; } public bool IsAlive { get; set; }

View File

@ -1,12 +1,16 @@
using System.Linq; using System;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
namespace Life.Automaton namespace Life.Automaton
{ {
[Serializable]
public class GameOfLife : IAutomaton public class GameOfLife : IAutomaton
{ {
public GameOfLife(int width, int height) public GameOfLife(int width, int height)
{ {
Initialize(new MooreField(width, height)); Field = new MooreField(width, height);
} }
public static Rule MakeRule(string born, string survive) public static Rule MakeRule(string born, string survive)
@ -41,15 +45,15 @@ namespace Life.Automaton
public IField Field { get; private set; } public IField Field { get; private set; }
public void Initialize(IField field)
{
Field = field;
}
public void Advance() public void Advance()
{ {
Field.Transform(Rule); Field.Transform(Rule);
Iteration++; Iteration++;
} }
public void ReplaceField(IField field)
{
Field = field;
}
} }
} }

View File

@ -1,11 +1,14 @@
namespace Life.Automaton using System;
namespace Life.Automaton
{ {
public interface IAutomaton public interface IAutomaton
{ {
int Iteration { get; } int Iteration { get; }
IField Field { get; } IField Field { get; }
void Initialize(IField field);
void Advance(); void Advance();
void ReplaceField(IField field);
} }
} }

View File

@ -10,7 +10,7 @@ namespace Life.Automaton
{ {
Size Size { get; } Size Size { get; }
Cell this[int x, int y] { get; set; } Cell this[int x, int y] { get; }
IEnumerable<Cell> Cells { get; } IEnumerable<Cell> Cells { get; }

View File

@ -1,8 +1,10 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
namespace Life.Automaton namespace Life.Automaton
{ {
[Serializable]
public class MooreField : BasicField public class MooreField : BasicField
{ {
public MooreField(int width, int height) : base(width, height) public MooreField(int width, int height) : base(width, height)

View File

@ -7,33 +7,48 @@
xmlns:vm="clr-namespace:Life.ViewModel" xmlns:vm="clr-namespace:Life.ViewModel"
mc:Ignorable="d" mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800" d:DataContext="{d:DesignInstance vm:AutomatonViewModel}"> Title="MainWindow" Height="450" Width="800" d:DataContext="{d:DesignInstance vm:AutomatonViewModel}">
<Grid> <Window.InputBindings>
<Grid.ColumnDefinitions> <KeyBinding Key="O" Modifiers="Control" Command="{Binding LoadCommand}"/>
<ColumnDefinition Width="2*" MinWidth="400"/> <KeyBinding Key="S" Modifiers="Control" Command="{Binding SaveCommand}"/>
<ColumnDefinition Width="3"/> </Window.InputBindings>
<ColumnDefinition Width="1*" MinWidth="300" MaxWidth="400"/> <DockPanel>
</Grid.ColumnDefinitions> <Menu DockPanel.Dock="Top">
<MenuItem Command="{Binding LoadCommand}" Header="Load" />
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"> <MenuItem Command="{Binding SaveCommand}" Header="Save" />
<local:AutomatonField Field="{Binding Field}" Size="{Binding Size}" Separation="3" ClickCommand="{Binding CellClicked}"/> </Menu>
</ScrollViewer> <Grid>
<Grid.ColumnDefinitions>
<GridSplitter Grid.Column="1" Width="3" ResizeDirection="Columns" ResizeBehavior="PreviousAndNext"/> <ColumnDefinition Width="2*" MinWidth="400"/>
<Grid Margin="8" Grid.Column="2"> <ColumnDefinition Width="3"/>
<Grid.RowDefinitions> <ColumnDefinition Width="1*" MinWidth="300" MaxWidth="400"/>
<RowDefinition Height="3*"/> </Grid.ColumnDefinitions>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center"> <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<TextBlock Text="{Binding Field.Size.Width}"/> <local:AutomatonField Field="{Binding Field}" Size="{Binding Size}" Separation="3" ClickCommand="{Binding CellClicked}"/>
<TextBlock Text=" x "/> </ScrollViewer>
<TextBlock Text="{Binding Field.Size.Height}"/>
</StackPanel>
<StackPanel Orientation="Vertical" Grid.Row="1" VerticalAlignment="Bottom"> <GridSplitter Grid.Column="1" Width="3" ResizeDirection="Columns" ResizeBehavior="PreviousAndNext"/>
<Button VerticalAlignment="Stretch" Command="{Binding StepCommand}">Step</Button>
<StackPanel Orientation="Vertical" Margin="8" Grid.Column="2" HorizontalAlignment="Stretch">
<DockPanel HorizontalAlignment="Stretch">
<TextBlock Style="{StaticResource Header}" VerticalAlignment="Center">Iteracja</TextBlock>
<TextBlock Style="{StaticResource Value}" Text="{Binding Iteration}" VerticalAlignment="Stretch"/>
<Button VerticalAlignment="Center" Command="{Binding StepCommand}" HorizontalAlignment="Right">
<TextBlock Margin="4">krok</TextBlock>
</Button>
</DockPanel>
<DockPanel HorizontalAlignment="Stretch">
<TextBlock Style="{StaticResource Header}" VerticalAlignment="Center">Rozmiar</TextBlock>
<StackPanel Orientation="Horizontal" HorizontalAlignment="center" VerticalAlignment="Center">
<TextBox Text="{Binding Field.Size.Width, Mode=OneWay}"/>
<TextBlock Text=" x "/>
<TextBox Text="{Binding Field.Size.Height, Mode=OneWay}"/>
</StackPanel>
<Button VerticalAlignment="Center" Command="{Binding StepCommand}" HorizontalAlignment="Right">
<TextBlock Margin="4">Zapisz</TextBlock>
</Button>
</DockPanel>
</StackPanel> </StackPanel>
</Grid> </Grid>
</Grid> </DockPanel>
</Window> </Window>

View File

@ -1,4 +1,5 @@
using System.Windows; using System.Windows;
using System.Windows.Input;
using Life.Automaton; using Life.Automaton;
using Life.ViewModel; using Life.ViewModel;
@ -24,5 +25,9 @@ namespace Life
InitializeComponent(); InitializeComponent();
} }
private void CommandBinding_OnExecuted(object sender, ExecutedRoutedEventArgs e)
{
}
} }
} }

View File

@ -1,5 +1,8 @@
namespace Life.Misc using System;
namespace Life.Misc
{ {
[Serializable]
public struct Position public struct Position
{ {
public Position(int x, int y) public Position(int x, int y)

View File

@ -1,5 +1,8 @@
namespace Life.Misc using System;
namespace Life.Misc
{ {
[Serializable]
public struct Size public struct Size
{ {
public int Width { get; } public int Width { get; }

View File

@ -1,16 +1,20 @@
using System; using System;
using System.Diagnostics;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Windows.Input; using System.Windows.Input;
using Life.Automaton; using Life.Automaton;
using Life.Misc; using Life.Misc;
using Microsoft.Win32;
namespace Life.ViewModel namespace Life.ViewModel
{ {
public class AutomatonViewModel : BaseViewModel public class AutomatonViewModel : BaseViewModel
{ {
private int _size; private int _size;
private int _separation; private int _separation;
private IAutomaton _automaton; private IAutomaton _automaton;
private IFormatter _formatter = new BinaryFormatter();
public int Size public int Size
{ {
@ -31,7 +35,7 @@ namespace Life.ViewModel
OnPropertyChanged(nameof(Separation)); OnPropertyChanged(nameof(Separation));
} }
} }
public IAutomaton Automaton public IAutomaton Automaton
{ {
get => _automaton; get => _automaton;
@ -51,14 +55,26 @@ namespace Life.ViewModel
Action = HandleCellClick Action = HandleCellClick
}; };
public ICommand LoadCommand => new DelegateCommand<object>
{
Action = HandleLoadCommand
};
public ICommand SaveCommand => new DelegateCommand<object>
{
Action = HandleSaveCommand
};
public ICommand StepCommand => new DelegateCommand<object> public ICommand StepCommand => new DelegateCommand<object>
{ {
Action = Step Action = Step
}; };
private void Step(object param) private void Step(object param)
{ {
Automaton.Advance(); Automaton.Advance();
OnPropertyChanged(nameof(Iteration));
} }
private void HandleCellClick(Position position) private void HandleCellClick(Position position)
@ -66,5 +82,31 @@ namespace Life.ViewModel
Field[position.X, position.Y].IsAlive = !Field[position.X, position.Y].IsAlive; Field[position.X, position.Y].IsAlive = !Field[position.X, position.Y].IsAlive;
Field.Notify(); Field.Notify();
} }
private void HandleLoadCommand(object _)
{
OpenFileDialog dialog = new OpenFileDialog();
if (dialog.ShowDialog() == true)
{
using var file = dialog.OpenFile();
var field = _formatter.Deserialize(file) as IField;
Automaton.ReplaceField(field);
OnPropertyChanged(nameof(Field));
}
}
private void HandleSaveCommand(object _)
{
SaveFileDialog dialog = new SaveFileDialog();
if (dialog.ShowDialog() == true)
{
using var file = dialog.OpenFile();
_formatter.Serialize(file, Field);
}
}
} }
} }

View File

@ -1,6 +1,5 @@
using System.ComponentModel; using System.ComponentModel;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using Life.Annotations;
namespace Life.ViewModel namespace Life.ViewModel
{ {
@ -8,7 +7,6 @@ namespace Life.ViewModel
{ {
public event PropertyChangedEventHandler PropertyChanged; public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{ {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));