C# :: Aufgabe #207 :: Lösung #1
3 Lösungen

#207
Minesweeper, der zündende Klassiker
Fortgeschrittener - C#
von Exception
- 16.05.2018 um 19:49 Uhr
Dieses Spielchen kennt sicher jeder...
...ein X * Y großes Spielfeld und die ein oder andere explosive Überraschung #boom ... :)
Ihr kennt Minesweeper nicht? Dann klickt hier!
Die Anforderungen:
1) Grafische Umsetzung
2) Das Spielfeld soll eine variable Größe haben (konfigurierbar vor dem Start)
3) Die einzelnen Minen sollen zufällig verteilt werden
4) Felder, die keine Mine enthalten zeigen nachdem sie angeklickt wurden die Anzahl der Minen, die sich im direkten Umkreis befinden.
5) Mit der rechten Maustaste kann der Spieler auf das Feld eine Fahne setzen, über dem er gerade mit dem Mauszeiger hovert und auf dem er eine Mine vermutet. Bei erneutem Rechtsklick wird die gesetzte Fahne wieder entfernt (Aufpassen dass nicht mehr Fahnen platziert werden können als es Minen gibt!)
Das Spiel endet...
... wenn ein Minenfeld angeklickt wurde / "explodiert" ist => Verloren
... oder bestenfalls, wenn alle Minen mit Fahnen markiert wurden => Sieg
Nice to have (optional):
- Ein Timer der anzeigt wie lange gebraucht wurde
- Bestenliste
- Anzahl der Minen kann eingestellt werden, sonst muss die Anzahl eben abhängig von der Feldgröße berechnet werden.
- Sound: Beim Feld anklicken, wenn Mine getroffen wurde, ...... #Kreativität
...ein X * Y großes Spielfeld und die ein oder andere explosive Überraschung #boom ... :)
Ihr kennt Minesweeper nicht? Dann klickt hier!
Die Anforderungen:
1) Grafische Umsetzung
2) Das Spielfeld soll eine variable Größe haben (konfigurierbar vor dem Start)
3) Die einzelnen Minen sollen zufällig verteilt werden
4) Felder, die keine Mine enthalten zeigen nachdem sie angeklickt wurden die Anzahl der Minen, die sich im direkten Umkreis befinden.
5) Mit der rechten Maustaste kann der Spieler auf das Feld eine Fahne setzen, über dem er gerade mit dem Mauszeiger hovert und auf dem er eine Mine vermutet. Bei erneutem Rechtsklick wird die gesetzte Fahne wieder entfernt (Aufpassen dass nicht mehr Fahnen platziert werden können als es Minen gibt!)
Das Spiel endet...
... wenn ein Minenfeld angeklickt wurde / "explodiert" ist => Verloren
... oder bestenfalls, wenn alle Minen mit Fahnen markiert wurden => Sieg
Nice to have (optional):
- Ein Timer der anzeigt wie lange gebraucht wurde
- Bestenliste
- Anzahl der Minen kann eingestellt werden, sonst muss die Anzahl eben abhängig von der Feldgröße berechnet werden.
- Sound: Beim Feld anklicken, wenn Mine getroffen wurde, ...... #Kreativität
#1

von daniel59 (4260 Punkte)
- 29.05.2018 um 14:58 Uhr
MainWindow.xaml.cs
C#-Code
MainWindow.xaml
XML-Code

using System; using System.Collections.Generic; using System.Linq; using System.Media; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media.Imaging; using System.Windows.Threading; namespace WpfMineSweeper { /// <summary> /// Interaktionslogik für MainWindow.xaml /// </summary> public partial class MainWindow : Window { const int size = 25; const string mine = "bombe.jpg"; const string flag = "flag.png"; static readonly Random rnd = new Random(); private List<Button> field; private List<Postion> positions; private DispatcherTimer timer; private int fieldWidth; private int fieldHeight; private int mines; public int LeftFlags => mines - positions.Count(a => a.HasFlag); private bool started = false; public MainWindow() { InitializeComponent(); } private void CreateField(int width, int height, int mines) { positions = new List<Postion>(); canvas.Children.Clear(); field = new List<Button>(); fieldWidth = width; fieldHeight = height; this.mines = mines; canvas.Width = size * width; canvas.Height = size * height; for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { Button but = new Button() { Content = "", Width = size, Height = size, Name = $"but_{x}_{y}", FontWeight = FontWeights.Bold }; positions.Add(new Postion() { X = x, Y = y }); but.PreviewMouseLeftButtonDown += But_PreviewMouseLeftButtonDown; but.PreviewMouseRightButtonDown += But_PreviewMouseRightButtonDown; Canvas.SetLeft(but, x * size); Canvas.SetTop(but, y * size); canvas.Children.Add(but); field.Add(but); } } while (positions.Count(a => a.IsMine) < mines) { var temp = positions.Where(a => !a.IsMine); temp.ElementAt(rnd.Next(0, temp.Count())).IsMine = true; } for (int i = 0; i < positions.Count; i++) { Postion cur = positions[i]; var temp = positions.Where(a => (Math.Abs(cur.X - a.X) == 1 && Math.Abs(cur.Y - a.Y) == 0) || (Math.Abs(cur.X - a.X) == 0 && Math.Abs(cur.Y - a.Y) == 1) || (Math.Abs(cur.X - a.X) == 1 && Math.Abs(cur.Y - a.Y) == 1)); positions[i].Mines = temp.Count(a => a.IsMine); } textBlockFlagsLeft.Text = $"Verbleibende Flaggen: {LeftFlags}"; } private void StartGame() { timer = new DispatcherTimer(); DateTime startTime = DateTime.Now; timer.Tick += delegate { textBlockTime.Text = (DateTime.Now - startTime).ToString("h'h 'm'm 's's'"); }; timer.Interval = new TimeSpan(0, 0, 1); int w, h, m; if (int.TryParse(textBoxWidth.Text, out w) && w > 0 && int.TryParse(textBoxHeight.Text, out h) && h > 0 && int.TryParse(textBoxMines.Text, out m) && m > 0 && m < w * h) { CreateField(w, h, m); } else { MessageBox.Show("Falsche Eingaben"); return; } started = true; buttonStartStop.Content = "Beenden"; textBlockTime.Text = (new TimeSpan()).ToString("h'h 'm'm 's's'"); timer.Start(); } private void EndGame() { timer.Stop(); started = false; buttonStartStop.Content = "Starten"; } private void ExplosionSound() { Task.Factory.StartNew(delegate { SoundPlayer player = new SoundPlayer(Properties.Resources.bombExplosion); player.Play(); }); } private void ShowMines() { foreach (Postion pos in positions) { Button button = field.Single(a => a.Name == $"but_{pos.X}_{pos.Y}"); if(pos.IsMine) { button.Content = GetImage(mine); } else { button.Content = pos.Mines.ToString(); } } } static Image GetImage(string file) { Image img = new Image(); BitmapImage source = new BitmapImage(); source.BeginInit(); source.UriSource = new Uri(file, UriKind.Relative); source.EndInit(); img.Source = source; return img; } private void buttonStartStop_Click(object sender, RoutedEventArgs e) { if (!started) { StartGame(); } else { EndGame(); } } private void But_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e) { if (started) { Button caller = (Button)sender; int x, y; var split = caller.Name.Split('_'); x = int.Parse(split[1]); y = int.Parse(split[2]); var pos = positions.SingleOrDefault(a => a.X == x && a.Y == y); if (pos.HasFlag) { pos.HasFlag = false; caller.Content = null; } else if (!pos.HasFlag && LeftFlags > 0) { pos.HasFlag = true; caller.Content = GetImage(flag); if (positions.Where(a => a.HasFlag && a.IsMine).Count() == mines) { EndGame(); MessageBox.Show("Du hast alle Minen gefunden. Das Spiel ist vorbei!"); } } textBlockFlagsLeft.Text = $"Verbleibende Flaggen: {LeftFlags}"; } } private void But_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { if (started) { Button caller = (Button)sender; int x, y; var split = caller.Name.Split('_'); x = int.Parse(split[1]); y = int.Parse(split[2]); var pos = positions.SingleOrDefault(a => a.X == x && a.Y == y); if (pos.HasFlag) { pos.HasFlag = false; textBlockFlagsLeft.Text = $"Verbleibende Flaggen: {LeftFlags}"; } if (pos.IsMine) { caller.Content = GetImage(mine); EndGame(); ExplosionSound(); ShowMines(); MessageBox.Show("Du bist leider auf eine Mine getreten. Das Spiel ist vorbei!"); } else { caller.Content = pos.Mines; } } } } class Postion { public int X { get; set; } public int Y { get; set; } public bool IsMine { get; set; } public int Mines { get; set; } public bool HasFlag { get; set; } public override bool Equals(object obj) { Postion p = (Postion)obj; return X == p.X && Y == p.Y; } public override int GetHashCode() { int hash = 13; hash = (hash * 7) + X.GetHashCode(); hash = (hash * 7) + Y.GetHashCode(); return base.GetHashCode(); } } }
MainWindow.xaml

<Window x:Class="WpfMineSweeper.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfMineSweeper" mc:Ignorable="d" Title="MainWindow" Height="550" Width="725" x:Name="main"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="1*"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Grid Margin="0,10,0,0"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="1*"/> </Grid.ColumnDefinitions> <Grid Grid.Column="0"> <TextBlock Text="Spielfeldbreite" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10,3,0,0"/> <TextBox x:Name="textBoxWidth" Width="50" Text="10" TextAlignment="Center" Margin="91,0,0,0"/> </Grid> <Grid Grid.Column="1"> <TextBlock Text="Spielfeldhöhe" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10,3,0,0"/> <TextBox x:Name="textBoxHeight" Width="50" Text="10" TextAlignment="Center" Margin="86,0,0,0"/> </Grid> <Grid Grid.Column="2"> <TextBlock Text="Minen" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10,3,0,0"/> <TextBox x:Name="textBoxMines" Width="50" Text="10" TextAlignment="Center" Margin="49,0,0,0"/> </Grid> <Button x:Name="buttonStartStop" Content="Start" Grid.Column="3" HorizontalAlignment="Left" Margin="10,2,0,0" VerticalAlignment="Top" Width="75" Click="buttonStartStop_Click"/> </Grid> <ScrollViewer Grid.Row="1" Margin="10" ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollBarVisibility="Auto"> <Canvas x:Name="canvas" Background="LightGray"/> </ScrollViewer> <StackPanel Grid.Row="2" Orientation="Horizontal" Margin="10,0,10,0" Background="LightGray"> <TextBlock x:Name="textBlockTime" Margin="10,10"/> <TextBlock x:Name="textBlockFlagsLeft" Margin="10,10"/> </StackPanel> </Grid> </Window>
Kommentare:
Für diese Lösung gibt es noch keinen Kommentar
Seite 1 von 0
1