C# :: Aufgabe #47
2 Lösungen

Spiel: Schiffe versenken
Fortgeschrittener - C#
von david_k
- 06.01.2013 um 17:24 Uhr
Es soll ein Schiffe-Versenken Spiel (Konsole oder Gui) erstellt werden. Man solll gegen den Computer oder gegen einen Menschen spielen können.
Lösungen:
Schiffe versenken in der Konsole.
ACHTUNG! Spiel nur gegen CPU, nicht gegen Menschen, da die Spieler in der Konsole gegenseitig ihre Felder sehen können.
Erwähnenswertes:
- Eigene Spielfeldgröße von 5-5 bis 15-15
- Flottengröße und Maximale Schiffgröße abhängig von der Spielfeldgröße
- Schiffe können direkt nebeneinander stehen
- minimale KI: CPU schißt zufällig auf noch nicht beschossene Felder
C#-Code
ACHTUNG! Spiel nur gegen CPU, nicht gegen Menschen, da die Spieler in der Konsole gegenseitig ihre Felder sehen können.
Erwähnenswertes:
- Eigene Spielfeldgröße von 5-5 bis 15-15
- Flottengröße und Maximale Schiffgröße abhängig von der Spielfeldgröße
- Schiffe können direkt nebeneinander stehen
- minimale KI: CPU schißt zufällig auf noch nicht beschossene Felder

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace SchiffeVersenken_v2 { class Program { static Random rnd = new Random(); static char[] Alphabet = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O' }; static void Main(string[] args) { /* Schiff S * Wasser . * Treffer X * Danaben O */ int spielfeldBreite; int spielfeldHoehe; List<int> Flotte = new List<int>(); bool anDerReihe = true; //Spielfeldgröße ermitteln Console.Write("Bitte Spielfeldgröße(y,x) definieren mit jeweils min 5 und max 15: "); while (true) { String S = Console.ReadLine(); String[] S2 = S.Split(','); if (S2.Length < 2) continue; if (!Int32.TryParse(S2[0], out spielfeldBreite)) continue; if (!Int32.TryParse(S2[1], out spielfeldHoehe)) continue; if (spielfeldHoehe < 5 || spielfeldBreite < 5 || spielfeldHoehe > 15 || spielfeldBreite > 15) continue; break; } Console.WriteLine(); char[,] FeldSpieler = spielfeldGenerieren(spielfeldHoehe, spielfeldBreite); char[,] FeldCPU = spielfeldGenerieren(spielfeldHoehe, spielfeldBreite); Flotte = flotteZusammenstellen(spielfeldHoehe, spielfeldBreite); for (int i = 0; i < Flotte.Count; i++) { ausgabe(FeldSpieler, FeldCPU); schiffHinzufuegen(ref FeldSpieler, Flotte[i], true); schiffHinzufuegen(ref FeldCPU, Flotte[i], false); } //Spielen while (true) { ausgabe(FeldSpieler, FeldCPU); if (anDerReihe) { if (!schießen(ref FeldCPU, true)) { anDerReihe = !anDerReihe; } if (ueberpruefungSieg(FeldCPU)) { ausgabe(FeldSpieler, FeldCPU); Console.WriteLine("Sie haben Gewonnen, Gratulation!"); break; } } else { Console.ReadKey(); if (!schießen(ref FeldSpieler, false)) { anDerReihe = !anDerReihe; } if (ueberpruefungSieg(FeldSpieler)) { ausgabe(FeldSpieler, FeldCPU); Console.WriteLine("Sie haben Verloren; gegen zufälligen Beschuss! Du Pfeife ... tut mir leid, " +"ich meinte Sie Pfeife!"); break; } } } } static char[,] spielfeldGenerieren(int spielfeldHoehe, int spielfeldBreite) { char[,] Spielfeld = new char[spielfeldHoehe, spielfeldBreite]; for (int i1 = 0; i1 < spielfeldHoehe; i1++) { for (int i2 = 0; i2 < spielfeldBreite; i2++) { Spielfeld[i1, i2] = '.'; } } return Spielfeld; } static void ausgabe(char[,] FeldSpieler, char[,] FeldCPU) { //Kopfzeile Console.Write("Spieler"); for (int h1 = 0; h1 < (2 * FeldSpieler.GetLength(1) + 5); h1++) { Console.Write(" "); } Console.WriteLine("CPU"); Console.Write(" "); for (int h2 = 0; h2 < FeldSpieler.GetLength(1); h2++) { Console.Write(" {0}", Alphabet[h2]); } Console.Write(" "); for (int h3 = 0; h3 < FeldSpieler.GetLength(1); h3++) { Console.Write(" {0}", Alphabet[h3]); } Console.WriteLine(""); //Spielfelder for (int i1 = 0; i1 < FeldSpieler.GetLength(0); i1++) { Console.Write("{0:00}", i1 + 1); for (int i2 = 0; i2 < FeldSpieler.GetLength(1); i2++) { Console.Write(" {0}", FeldSpieler[i1, i2]); } Console.Write(" {0:00} || {0:00}", i1 + 1); for (int i2 = 0; i2 < FeldCPU.GetLength(1); i2++) { if (FeldCPU[i1, i2] == 'S') { Console.Write(" ."); } else { Console.Write(" {0}", FeldCPU[i1, i2]); } } Console.WriteLine(" {0:00}", i1 + 1); } //Schlusszeile Console.Write(" "); for (int h2 = 0; h2 < FeldSpieler.GetLength(1); h2++) { Console.Write(" {0}", Alphabet[h2]); } Console.Write(" "); for (int h3 = 0; h3 < FeldSpieler.GetLength(1); h3++) { Console.Write(" {0}", Alphabet[h3]); } Console.WriteLine("\n"); } static void schiffHinzufuegen(ref char[,] Spielfeld, int schiffslaenge, bool manuelleEingabe) { int[] BugKoordinate = new int[2]; int[] HeckKoordinate = new int[2]; int[] GesammtKoordinaten = new int[4]; int tempKoordinate; while (true) { bool kollision = false; if (manuelleEingabe) { Console.WriteLine("Ein Schiff der Länge {0} plazieren: \n", schiffslaenge); BugKoordinate = koordinateLesen(Spielfeld.GetLength(0), Spielfeld.GetLength(1)); if (schiffslaenge != 1) HeckKoordinate = koordinateLesen(Spielfeld.GetLength(0), Spielfeld.GetLength(1)); } else { GesammtKoordinaten = koordinatenZufall(Spielfeld, schiffslaenge); BugKoordinate[0] = GesammtKoordinaten[0]; BugKoordinate[1] = GesammtKoordinaten[1]; HeckKoordinate[0] = GesammtKoordinaten[2]; HeckKoordinate[1] = GesammtKoordinaten[3]; } //Überprüfung Koordinaten & Kollision if (schiffslaenge == 1) { if (Spielfeld[BugKoordinate[0], BugKoordinate[1]] != 'S') { Spielfeld[BugKoordinate[0], BugKoordinate[1]] = 'S'; break; } else continue; } if (BugKoordinate[0] == HeckKoordinate[0]) { if (BugKoordinate[1] - HeckKoordinate[1] == (schiffslaenge - 1) || BugKoordinate[1] - HeckKoordinate[1] == -(schiffslaenge - 1)) { if (BugKoordinate[1] < HeckKoordinate[1]) { tempKoordinate = BugKoordinate[1]; } else { tempKoordinate = HeckKoordinate[1]; } for (int i = tempKoordinate; i < (tempKoordinate + schiffslaenge); i++) { if (Spielfeld[BugKoordinate[0], i] != '.') { kollision = true; } } if (!kollision) { for (int i = tempKoordinate; i < (tempKoordinate + schiffslaenge); i++) { Spielfeld[BugKoordinate[0], i] = 'S'; } } else { if (manuelleEingabe) Console.WriteLine("Schiff kollidiert! Bitte neu setzten!\n"); continue; } break; } } else if (BugKoordinate[1] == HeckKoordinate[1]) { if (BugKoordinate[0] - HeckKoordinate[0] == (schiffslaenge - 1) || BugKoordinate[0] - HeckKoordinate[0] == -(schiffslaenge - 1)) { if (BugKoordinate[0] < HeckKoordinate[0]) { tempKoordinate = BugKoordinate[0]; } else { tempKoordinate = HeckKoordinate[0]; } for (int i = tempKoordinate; i < (tempKoordinate + schiffslaenge); i++) { if (Spielfeld[i, BugKoordinate[1]] != '.') { kollision = true; } } if (!kollision) { for (int i = tempKoordinate; i < (tempKoordinate + schiffslaenge); i++) { Spielfeld[i, BugKoordinate[1]] = 'S'; } } else { if (manuelleEingabe) Console.WriteLine("Schiff kollidiert! Bitte neu setzten!\n"); continue; } break; } } if (manuelleEingabe) Console.WriteLine("Koordianten scheinen nicht zueinender zu passen!\n"); } if (manuelleEingabe) Console.Write("Spieler: "); else Console.Write("CPU: "); Console.WriteLine("Schiff der Länge {0} hinzugefügt!\n", schiffslaenge); } static int[] koordinateLesen(int spielfeldHoehe, int spielfeldBreite) { int[] koordinate = new int[2]; bool buchstabeZuZahl = false; while (true) { String hoehe = ""; String breite = ""; Console.Write("Koordinate eingeben: "); String S = Console.ReadLine(); Console.WriteLine(); //Aufteilung des eingelesenen Strings in Buchstaben und Zahlen foreach (char c in S) { if (Char.IsNumber(c)) { //Ziffern aneinander reihen hoehe += c; } else { breite += c; } } if (hoehe.Length == 0) continue; // absicherung Crash; //Höhe-Koordiante if (Convert.ToInt32(hoehe) <= spielfeldHoehe) { koordinate[0] = Convert.ToInt32(hoehe) - 1; } else continue; //Breite-Koordinate if (breite.Length == 1) { for (int i = 0; i < spielfeldBreite; i++) { if (Alphabet[i] == Char.ToUpper(Convert.ToChar(breite))) { koordinate[1] = i; buchstabeZuZahl = true; break; } } if (!buchstabeZuZahl) { continue; } } else continue; break; } Console.WriteLine("Koordinate gültig!\n"); return koordinate; } static int[] koordinatenZufall(char[,] Spielfeld, int schiffslaenge) { //Zufälliges Koordinatenpaar in Abstand der Schiffslänge int[] BugKoordinate = new int[2]; int[] HeckKoordinate = new int[2]; BugKoordinate[0] = rnd.Next(0, Spielfeld.GetLength(0)); BugKoordinate[1] = rnd.Next(0, Spielfeld.GetLength(1)); int richtung = rnd.Next(4); switch (richtung) { case 0: //nord if (BugKoordinate[0] < schiffslaenge - 1) { goto case 1; } HeckKoordinate[0] = BugKoordinate[0] - (schiffslaenge - 1); HeckKoordinate[1] = BugKoordinate[1]; break; case 1: // west if (BugKoordinate[1] < schiffslaenge - 1) { goto case 2; } HeckKoordinate[0] = BugKoordinate[0]; HeckKoordinate[1] = BugKoordinate[1] - (schiffslaenge - 1); break; case 2: // süd if (BugKoordinate[0] + schiffslaenge > Spielfeld.GetLength(0)) { goto case 3; } HeckKoordinate[0] = BugKoordinate[0] + (schiffslaenge - 1); HeckKoordinate[1] = BugKoordinate[1]; break; case 3: // ost if (BugKoordinate[1] + schiffslaenge > Spielfeld.GetLength(1)) { goto case 0; } HeckKoordinate[0] = BugKoordinate[0]; HeckKoordinate[1] = BugKoordinate[1] + (schiffslaenge - 1); break; } int[] Koordinaten = { BugKoordinate[0], BugKoordinate[1], HeckKoordinate[0], HeckKoordinate[1] }; return Koordinaten; } static bool schießen(ref char[,] Spielfeld, bool manuell) { int[] ZielKoordinate = new int[2]; bool treffer = false; if (manuell) { Console.WriteLine("Bitte schießen!\n"); ZielKoordinate = koordinateLesen(Spielfeld.GetLength(0), Spielfeld.GetLength(1)); } else { while (true) //Minimal KI { ZielKoordinate[0] = rnd.Next(0, Spielfeld.GetLength(0)); ZielKoordinate[1] = rnd.Next(0, Spielfeld.GetLength(1)); if (Spielfeld[ZielKoordinate[0], ZielKoordinate[1]].Equals('X') || Spielfeld[ZielKoordinate[0], ZielKoordinate[1]].Equals('O')) continue; else { Console.Write("CPU schießt! "); break; } } } if (Spielfeld[ZielKoordinate[0], ZielKoordinate[1]].Equals('S')) { treffer = true; Spielfeld[ZielKoordinate[0], ZielKoordinate[1]] = 'X'; Console.WriteLine("Schuss auf {0}|{1}, Treffer!\n", Alphabet[ZielKoordinate[1]], ZielKoordinate[0] + 1); } else { Spielfeld[ZielKoordinate[0], ZielKoordinate[1]] = 'O'; Console.WriteLine("Schuss auf {0}|{1}, Daneben!\n", Alphabet[ZielKoordinate[1]], ZielKoordinate[0] + 1); } return treffer; } static bool ueberpruefungSieg(char[,] Spielfeld) { foreach (char c in Spielfeld) { if (c == 'S') return false; } return true; } static List<int> flotteZusammenstellen(int spielfeldHoehe, int spielfeldBreite) { //Ermittlung der größe der Flotte int schiffsTeile = (int)Math.Ceiling((double)((spielfeldBreite * spielfeldHoehe) / 8.0)); //Ermittlung der maximalen Schiffgröße int schiffMaximum; if (spielfeldBreite > spielfeldHoehe) schiffMaximum = spielfeldBreite/2; else schiffMaximum = spielfeldHoehe/2; Console.WriteLine("Bitte Flotte zusammenstellen! Auf diesem Spielfeld haben Sie dafür {0} Schiffsteile " + "für Schiffe mit der Größe 2-{1}\n", schiffsTeile, schiffMaximum); List<int> Flotte = new List<int>(); while (schiffsTeile > 1) { Console.Write("{0} Teile übrig: Schiff hinzufügen mit der Größe: ", schiffsTeile); int schiff = 0; if (!Int32.TryParse(Console.ReadLine(), out schiff)) continue; if (schiff > spielfeldBreite || schiff > spielfeldHoehe || schiff > schiffsTeile || schiff < 2 || schiff > schiffMaximum) continue; Flotte.Add(schiff); schiffsTeile -= schiff; Console.WriteLine(); } if (schiffsTeile == 1) { Flotte.Add(1); Console.WriteLine("Aus dem letzten Schiffteil wurde der Flotte noch ein Schlauchboot hinzugefüget.\n"); Console.ReadKey(); } return Flotte; } } }

using System; using System.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Media; namespace WpfSchiffeVersenken { /// <summary> /// Interaktionslogik für MainWindow.xaml /// </summary> public partial class MainWindow : Window { private static Random rnd = new Random(); List<Ship> allShips; List<Button> coordinates; int shots = 0; public MainWindow() { InitializeComponent(); } private void DrawField(int width, int height, double size) { coordinates = new List<Button>(); canvas.Children.Clear(); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { Button button = new Button() { Width = size, Height = size, Background = Brushes.DarkSeaGreen, Name = "btn_" + x.ToString() + "_" + y.ToString() }; button.Click += Button_Click; Canvas.SetLeft(button, x * size); Canvas.SetTop(button, y * size); canvas.Children.Add(button); coordinates.Add(button); } } } private void SetShips(int width, int height, int schlachtschiffe, int kreuzer, int zerstoerer, int uboote) { allShips = new List<Ship>(); int ships = schlachtschiffe + kreuzer + zerstoerer + uboote; for (int i = 0; i < ships; i++) { ShipPart startPart = new ShipPart(-1, -1); do { int startX = rnd.Next(0, width); int startY = rnd.Next(0, height); startPart = new ShipPart(startX, startY); } while (allShips.Any(a => a.Contains(startPart))); int size; List<int> movedDirections = new List<int>(); if (i < schlachtschiffe)//Schlachtschiff { size = 5; } else if (i < kreuzer + schlachtschiffe)//Kreuzer { size = 4; } else if (i < zerstoerer + schlachtschiffe + kreuzer)//Zerstörer { size = 3; } else//U-Boot { size = 2; } Ship ship = new Ship(); ship.Add(startPart); int dir; do { dir = rnd.Next(0, 4); } while (movedDirections.Contains(dir) && movedDirections.Count < 4); movedDirections.Add(dir); int x = 0; int y = 0; ShipPart part; for (int j = 1; j < size; j++) { switch (dir) { case 0://left part = new ShipPart(startPart.X - j, startPart.Y); break; case 1://right part = new ShipPart(startPart.X + j, startPart.Y); break; case 2://up part = new ShipPart(startPart.X, startPart.Y - j); break; case 3://down part = new ShipPart(startPart.X, startPart.Y + j); break; default: part = new ShipPart(-1, -1); break; } if (part.X < 0 || part.X > width - 1 || part.Y < 0 || part.Y > height - 1) { break; } if (!allShips.Any(a => a.Contains(part, ShipPartComparer.Comparer))) { ship.Add(part); } else { break; } } if (ship.Count != size) { i--; } else { allShips.Add(ship); } } } private void Init() { int width, height, size, schlacht, kreuz, zerstoer, uboot; if (int.TryParse(textBoxHeight.Text, out height) && int.TryParse(textBoxWidth.Text, out width) && int.TryParse(textBoxSize.Text, out size) && int.TryParse(textBoxSchlacht.Text, out schlacht) && int.TryParse(textBoxKreuzer.Text, out kreuz) && int.TryParse(textBoxZerstoerer.Text, out zerstoer) && int.TryParse(textBoxUboote.Text, out uboot)) { canvas.Children.Clear(); DrawField(width, height, size); SetShips(width, height, schlacht, kreuz, zerstoer, uboot); } } private void Button_Click(object sender, RoutedEventArgs e) { Button btnXY = ((Button)sender); string[] split = btnXY.Name.Split('_'); int x = Convert.ToInt32(split[1]); int y = Convert.ToInt32(split[2]); ShipPart part = new ShipPart(x, y); int indexShip = allShips.FindIndex(a => a.Contains(part, ShipPartComparer.Comparer)); shots++; if (indexShip > -1) { int indexPart = allShips[indexShip].IndexOf(part); if (!allShips[indexShip][indexPart].Destroyed) { btnXY.Background = Brushes.Red; allShips[indexShip][indexPart].Destroyed = true; if (allShips[indexShip].Destroyed) { MessageBox.Show("Schiff zerstört"); } } if (allShips.TrueForAll(a => a.Destroyed)) { MessageBox.Show("Alle Schiffe zerstört!\nBenötigte Züge: " + shots.ToString()); } } else { btnXY.Background = Brushes.Blue; } } private void button_Click_1(object sender, RoutedEventArgs e) { Init(); } } public class Ship : List<ShipPart> { public bool Destroyed { get { return this.TrueForAll(x => x.Destroyed); } } public bool Valid { get { return this.TrueForAll(x => x.X == this.FirstOrDefault().X) ^ this.TrueForAll(x => x.Y == this.FirstOrDefault().Y); } } } public class ShipPart { public int X { get; set; } public int Y { get; set; } public bool Destroyed { get; set; } public ShipPart(int x, int y) { X = x; Y = y; Destroyed = false; } public bool IsNeighbour(ShipPart part) { return (Math.Abs(this.X - part.X) == 1 && Math.Abs(this.Y - part.Y) == 0) || (Math.Abs(this.Y - part.Y) == 1 && Math.Abs(this.X - part.X) == 0); } public override bool Equals(object obj) { ShipPart part = (ShipPart)obj; return this.X == part.X && this.Y == part.Y; } public override int GetHashCode() { int hash = 13; hash = (hash * 7) + X.GetHashCode(); hash = (hash * 7) + Y.GetHashCode(); return hash; } } public class ShipPartComparer : IEqualityComparer<ShipPart> { public static readonly ShipPartComparer Comparer = new ShipPartComparer(); public bool Equals(ShipPart a, ShipPart b) { return a.Equals(b); } public int GetHashCode(ShipPart part) { return part.GetHashCode(); } } }
MainWindow.xaml

<Window x:Class="WpfSchiffeVersenken.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:WpfSchiffeVersenken" mc:Ignorable="d" Title="MainWindow" Height="500" Width="525"> <Grid> <Canvas x:Name="canvas"> <TextBlock x:Name="textBlock" Canvas.Left="10" TextWrapping="Wrap" Text="Höhe" Canvas.Top="10"/> <TextBox x:Name="textBoxHeight" Height="23" Canvas.Left="93" TextWrapping="Wrap" Text="10" Canvas.Top="7" Width="120" TextAlignment="Center"/> <TextBox x:Name="textBoxWidth" Height="23" Canvas.Left="93" TextWrapping="Wrap" Text="10" Canvas.Top="35" Width="120" TextAlignment="Center"/> <TextBlock x:Name="textBlock1" Canvas.Left="10" TextWrapping="Wrap" Text="Breite" Canvas.Top="38"/> <TextBox x:Name="textBoxSize" Height="23" Canvas.Left="93" TextWrapping="Wrap" Text="30" Canvas.Top="63" Width="120" TextAlignment="Center"/> <TextBlock x:Name="textBlock2" Canvas.Left="10" TextWrapping="Wrap" Text="Feldgröße" Canvas.Top="66"/> <TextBlock x:Name="textBlock3" Canvas.Left="10" TextWrapping="Wrap" Text="Schlachtschiffe" Canvas.Top="94"/> <TextBox x:Name="textBoxSchlacht" Height="23" Canvas.Left="93" TextWrapping="Wrap" Text="1" Canvas.Top="91" Width="120" TextAlignment="Center"/> <TextBox x:Name="textBoxKreuzer" Height="23" Canvas.Left="93" TextWrapping="Wrap" Text="2" Canvas.Top="119" Width="120" TextAlignment="Center"/> <TextBlock x:Name="textBlock3_Copy" Canvas.Left="10" TextWrapping="Wrap" Text="Kreuzer" Canvas.Top="122"/> <TextBox x:Name="textBoxZerstoerer" Height="23" Canvas.Left="93" TextWrapping="Wrap" Text="3" Canvas.Top="147" Width="120" TextAlignment="Center"/> <TextBlock x:Name="textBlock4" Canvas.Left="10" TextWrapping="Wrap" Text="Zerstörer" Canvas.Top="150"/> <TextBlock x:Name="textBlock5" Canvas.Left="10" TextWrapping="Wrap" Text="U-Boote" Canvas.Top="178"/> <TextBox x:Name="textBoxUboote" Height="23" Canvas.Left="93" TextWrapping="Wrap" Text="4" Canvas.Top="175" Width="120" TextAlignment="Center"/> <Button x:Name="button" Content="OK" Canvas.Left="10" Canvas.Top="203" Width="203" Click="button_Click_1"/> </Canvas> </Grid> </Window>