diff --git a/Morris/ConsoleInteraction.cs b/Morris/ConsoleInteraction.cs index 208945c..2c0c570 100644 --- a/Morris/ConsoleInteraction.cs +++ b/Morris/ConsoleInteraction.cs @@ -26,6 +26,8 @@ namespace Morris public void Notify(IReadOnlyGameState state) { + Console.Clear(); + // Ein mit Leerzeichen initialisiertes 13*13 Jagged Array char[][] field = Enumerable.Repeat(0, 13).Select(_ => Enumerable.Repeat(' ', 13).ToArray()).ToArray(); diff --git a/Morris/GameWindow.xaml b/Morris/GameWindow.xaml new file mode 100644 index 0000000..05b6182 --- /dev/null +++ b/Morris/GameWindow.xaml @@ -0,0 +1,12 @@ + + + + + diff --git a/Morris/GameWindow.xaml.cs b/Morris/GameWindow.xaml.cs new file mode 100644 index 0000000..15d9133 --- /dev/null +++ b/Morris/GameWindow.xaml.cs @@ -0,0 +1,187 @@ +/* + * GameWindow.xaml.cs + * Copyright (c) 2016 Markus Himmel + * This file is distributed under the terms of the MIT license + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; + +namespace Morris +{ + + /// + /// Eine WPF-gestütze Mühle-GUI + /// + public partial class GameWindow : Window, IGameStateObserver + { + + private const int BLOCK_SIZE = 100; // Sollte durch 2 teilbar sein + private const int OFFSET_LEFT = 50; + private const int OFFSET_TOP = 70; + private const int OFFSET_BOTTOM = 90; + private const int OFFSET_RIGHT = 10; + private const int LINE_THICKNESS = 6; // Sollte durch 2 teilbar sein + private const int PIECE_RADIUS = 30; + private const int LEGEND_OFFSET = 30; + private const int LABEL_BUFFER_SIZE = 40; + + private Ellipse[] pieces; + + private SolidColorBrush primaryColor = new SolidColorBrush(Color.FromRgb(0, 0, 0)); + + private Label status; + + public GameWindow() + { + InitializeComponent(); + + // Spielfield zeichnen + for (int i = 0; i < GameState.FIELD_SIZE; i++) + { + var pointI = CoordinateTranslator.CoordinatesFromID(i); + foreach (int j in GameState.GetConnected(i).Where(j => j < i)) + { + var pointJ = CoordinateTranslator.CoordinatesFromID(j); + + // "Fire and Forget": Sobald wir die Objekte zum Grid hinzugefügt haben, + // brauchen wir keine Referenzen mehr zu speichern. + var h = new Rectangle(); + h.Fill = primaryColor; + h.Width = BLOCK_SIZE * Math.Abs(pointI[1] - pointJ[1]) + LINE_THICKNESS; + h.Height = BLOCK_SIZE * Math.Abs(pointI[0] - pointJ[0]) + LINE_THICKNESS; + h.HorizontalAlignment = HorizontalAlignment.Left; + h.VerticalAlignment = VerticalAlignment.Top; + + h.Margin = new Thickness( + BLOCK_SIZE * Math.Min(pointI[1], pointJ[1]) + BLOCK_SIZE / 2 - LINE_THICKNESS / 2 + OFFSET_LEFT, + BLOCK_SIZE * Math.Min(pointI[0], pointJ[0]) + BLOCK_SIZE / 2 - LINE_THICKNESS / 2 + OFFSET_TOP, + 0, 0); + + grid.Children.Add(h); + } + } + + // Beschriftung links + for (int i = 0; i < 7; i++) + { + Label l = new Label(); + l.VerticalContentAlignment = VerticalAlignment.Center; + l.HorizontalAlignment = HorizontalAlignment.Left; + l.VerticalAlignment = VerticalAlignment.Top; + l.Content = (7 - i).ToString(); + l.Height = LABEL_BUFFER_SIZE; + + l.Margin = new Thickness(OFFSET_LEFT - LEGEND_OFFSET, OFFSET_TOP + i * BLOCK_SIZE + BLOCK_SIZE / 2 - LABEL_BUFFER_SIZE / 2, 0, 0); + l.FontSize = 20; + l.Foreground = primaryColor; + grid.Children.Add(l); + } + + // Beschriftung unten + for (int i = 0; i < 7; i++) + { + Label l = new Label(); + l.HorizontalContentAlignment = HorizontalAlignment.Center; + l.HorizontalAlignment = HorizontalAlignment.Left; + l.VerticalAlignment = VerticalAlignment.Top; + l.Content = (char)('a' + i); + l.Width = LABEL_BUFFER_SIZE; + l.Margin = new Thickness(OFFSET_LEFT + i * BLOCK_SIZE + BLOCK_SIZE / 2 - LABEL_BUFFER_SIZE / 2, OFFSET_TOP + 7 * BLOCK_SIZE, 0, 0); + l.FontSize = 20; + l.Foreground = primaryColor; + grid.Children.Add(l); + } + + // Fenstergröße + Height = OFFSET_TOP + 7 * BLOCK_SIZE + OFFSET_BOTTOM; + Width = OFFSET_LEFT + 7 * BLOCK_SIZE + OFFSET_RIGHT; + + + + // Es gibt nicht für jeden tatsächlichen Spielstein eine Ellipse, die sich bewegt. Stattdessen gibt es eine + // Ellipse auf jedem der 24 Spielfeldpunkte, die je nach Belegung Schwarz, weiß oder transparent ist + pieces = new Ellipse[GameState.FIELD_SIZE]; + for (int i = 0; i < GameState.FIELD_SIZE; i++) + { + var point = CoordinateTranslator.CoordinatesFromID(i); + var e = new Ellipse(); + e.Fill = null; + e.Width = e.Height = 2 * PIECE_RADIUS; + e.HorizontalAlignment = HorizontalAlignment.Left; + e.VerticalAlignment = VerticalAlignment.Top; + + e.Margin = new Thickness( + OFFSET_LEFT + BLOCK_SIZE * point[1] + BLOCK_SIZE / 2 - PIECE_RADIUS, + OFFSET_TOP + BLOCK_SIZE * point[0] + BLOCK_SIZE / 2 - PIECE_RADIUS, + 0, 0); + + grid.Children.Add(e); + + pieces[i] = e; + } + + // Statusanzeige + status = new Label(); + status.HorizontalContentAlignment = HorizontalAlignment.Center; + status.HorizontalAlignment = HorizontalAlignment.Left; + status.VerticalAlignment = VerticalAlignment.Top; + status.Width = 7 * BLOCK_SIZE + LINE_THICKNESS; + status.Margin = new Thickness(OFFSET_LEFT, 10, 0, 0); + status.FontSize = 40; + grid.Children.Add(status); + } + + public void Notify(IReadOnlyGameState state) + { + Dispatcher.Invoke(() => + { + // Ellipsen einfärben + for (int i = 0; i < GameState.FIELD_SIZE; i++) + { + switch (state.Board[i]) + { + case Occupation.Free: + pieces[i].Fill = null; + break; + + case Occupation.Black: + pieces[i].Fill = new SolidColorBrush(Colors.Black); + break; + + case Occupation.White: + pieces[i].Fill = new SolidColorBrush(Colors.White); + break; + } + } + + // Statusanzeige, falls das Spiel vorbei ist + switch (state.Result) + { + case GameResult.BlackVictory: + status.Content = "Schwarz hat gewonnen"; + break; + + case GameResult.WhiteVictory: + status.Content = "Weiß hat gewonnen"; + break; + + case GameResult.Draw: + status.Content = "Unentschieden"; + break; + } + }); + } + } +} diff --git a/Morris/Morris.csproj b/Morris/Morris.csproj index dfac97d..e915032 100644 --- a/Morris/Morris.csproj +++ b/Morris/Morris.csproj @@ -2,6 +2,7 @@ + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} Debug AnyCPU {E3CCB2E8-5840-4442-8A66-177F5DF4C4F5} @@ -33,14 +34,18 @@ 4 + + + + @@ -49,6 +54,9 @@ + + GameWindow.xaml + @@ -65,6 +73,12 @@ + + + Designer + MSBuild:Compile + +