C# - Conways Spiel des Lebens

    • C#

    Es gibt 4 Antworten in diesem Thema. Der letzte Beitrag () ist von VaporiZed.

      C# - Conways Spiel des Lebens

      Beschreibung:
      Diese Konsolenanwendung ist eine codierte Darstellung des Conways Spiel des Lebens, nachzulesen auf Wikipedia.

      Verwendete Programmiersprache(n) und IDE(s):
      Visual Studio 2017 Community, C#

      Systemveränderungen:
      Es wird gefordert, ein Spielfeld in Form einer Textdatei auf dem Desktop anzulegen.

      Download(s):
      Projektordner - Dekomprimiert ca. 3,5 MB
      Beispiel Spielfeld, muss sich auf Desktop befinden

      Lizenz/Weitergabe:
      Open Source, der sich im Anhang befindende Code dient als Vorlage und wurde komplett Kommentiert. Mir hat es sehr dabei geholfen, C# ein wenig besser zu lernen. Der Code stammt allein von mir, in rücksicht auf die Regeln des Wikipedia Beitrags. Für Verbesserungvorschläge bin ich sehr offen, da ich dieses Programm auch nur entwickelt habe, um mich ein bisschen mehr in C# einzufinden.

      Grundlegendes zum Code:
      Das Spiel besteht aus Zellen. Eine Leere Zelle (" ") ist eine "Tote Zelle", eine mit einem Rautezeichen gefüllte Zelle ("#") ist eine "Lebendige Zelle". Je nach dem wie viele "Nachbarn" eine Zelle hat stirbt sie, bleibt am Leben oder wird geboren, je nach Status der Zelle. Gearbeitet wird größtenteils mit einer 2-Dimensionalen String-Liste die als Spielfeld dient. Es werden Zeilenweise alle Zeichen der Textdatei in diese Liste hinzugefügt. Die Liste wird nach der überprüfung der Regeln verändert, da das sonst die Ergebnisse verfälschen würde.

      Hier der Code in Textform zum drüber schaun:
      Spoiler anzeigen

      C#-Quellcode

      1. using System;
      2. using System.Collections.Generic;
      3. using System.Linq;
      4. using System.Text;
      5. using System.Threading.Tasks;
      6. namespace gameOfLife {
      7. class Program {
      8. static List<List<string>> hashRows = new List<List<string>>(); // 2-Dimensionale String-Liste die das Spielfeld darstellt (das Spielfeld kann beliebig groß sein)
      9. static List<string> changePoints = new List<string>(); // Liste in der zu verändernde Punkte eingetragen werden
      10. static string fillData = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\Spielfeld.txt"; // Pfad zur Spielfeld-Datei auf dem Desktop
      11. static void Main(string[] args) {
      12. if(System.IO.File.Exists(fillData)) {
      13. bool goOn = true;
      14. int generation = 1;
      15. fillList();
      16. doListOutput(hashRows, generation);
      17. while(goOn) {
      18. generation += 1;
      19. checkGeneration();
      20. changeGeneration();
      21. doListOutput(hashRows, generation);
      22. if(!Console.ReadKey().Key.Equals(ConsoleKey.Enter)) { goOn = false; }
      23. }
      24. } else {
      25. System.IO.File.Create(fillData);
      26. Console.WriteLine("Auf Ihrem Desktop wurde eine Text-Datei mit dem Namen 'Spielfeld.txt' erstellt. Sie können Ihre eigene Anfangs-Generation bestimmen, dabei steht ein Leerzeichen " +
      27. "für ein nicht existierendes- und ein Rautezeichen ('#') für ein lebendiges Lebewesen. Es empfiehlt sich ein 40x20 Spielfeld anzulegen aus Leerzeichen und Rautezeichen. " +
      28. "Die Regeln sind dabei nachzulesen auf: https://de.wikipedia.org/wiki/Conways_Spiel_des_Lebens");
      29. Console.ReadKey();
      30. }
      31. }
      32. /// <summary>
      33. /// Füllt die Variable hashRows mit den Eingaben aus der Textdatei Zeilenweise. Jede Zeile wird dabei eine neue Leere String-Liste die mit dem Text der Zeile gefüllt wird. Jedes Zeichen ist
      34. /// ein einzelnes Item.
      35. /// </summary>
      36. /// <see cref="hashRows"/>
      37. /// <see cref="fillData"/>
      38. static void fillList() {
      39. int lineCount = 0;
      40. foreach(var line in System.IO.File.ReadLines(fillData)) { // Es wird jede Zeile des Spielfeldes durch Iteriert.
      41. List<string> emptyFillList = new List<string>(); // Zwischenvariable
      42. hashRows.Add(emptyFillList); // Leere String-Liste wird hinzugefügt.
      43. foreach(char element in line) { hashRows[lineCount].Add(element.ToString()); } // Das zuvor Leer hinzugefügte Item wird mit Zeichen der Zeile gefüllt.
      44. lineCount += 1;
      45. }
      46. }
      47. /// <summary>
      48. /// Diese Funktion überprüft das Spielfeld nach den Regeln. Hierbei ist es wichtig, dass man das Spielfeld erst NACH dem Überprüfen verändern darf, da das sonst das ergebnis verfälschen würde.
      49. /// </summary>
      50. static void checkGeneration() {
      51. for(int lstIndx = 0; lstIndx < hashRows.Count; lstIndx++) { // es wird jede Zeile des Spielfelds durch Iteriert
      52. for(int i = 0; i < hashRows[lstIndx].Count; i++) { // es werden alle Items (Zeichen der Zeile) der oben bestimmten Zeile durch Iteriert
      53. List<string> arround = new List<string> { // in dieser Liste werden im Folgenden alle umliegenden Items des Items hashRows[lstIndx][i] hinzugefügt, um die Regeln zu überprüfen
      54. hashRows[calcIndex(hashRows.Count, lstIndx - 1)][calcIndex(hashRows[calcIndex(hashRows.Count, lstIndx - 1)].Count, i - 1)], // oben links
      55. hashRows[calcIndex(hashRows.Count, lstIndx - 1)][i], // oben mitte
      56. hashRows[calcIndex(hashRows.Count, lstIndx - 1)][calcIndex(hashRows[calcIndex(hashRows.Count, lstIndx - 1)].Count, i + 1)], // oben rechts
      57. hashRows[lstIndx][calcIndex(hashRows[lstIndx].Count, i - 1)], // links
      58. hashRows[lstIndx][calcIndex(hashRows[lstIndx].Count, i + 1)],// rechts
      59. hashRows[calcIndex(hashRows.Count, lstIndx + 1)][calcIndex(hashRows[calcIndex(hashRows.Count, lstIndx + 1)].Count, i - 1)], // unten links
      60. hashRows[calcIndex(hashRows.Count, lstIndx + 1)][i], // unten mitte
      61. hashRows[calcIndex(hashRows.Count, lstIndx + 1)][calcIndex(hashRows[calcIndex(hashRows.Count, lstIndx + 1)].Count, i + 1)] // unten rechts
      62. };
      63. int surrounding = countElementsWith("#", arround);
      64. string cellType = hashRows[lstIndx][i];
      65. if (cellType == "#") { if (surrounding < 2 || surrounding > 3) { addAsChange(lstIndx, i, " "); } } else { if (surrounding == 3) { addAsChange(lstIndx, i, "#"); } } // Die Regeln
      66. // hierbei durch einfaches Zählen der lebenden Zellen ('#') überprüft, alle zu ändernden Zellen werden in addAsChange zur Liste changePoints mit allen Argumenten hinzugefügt.
      67. }
      68. }
      69. }
      70. /// <summary>
      71. /// Hier werden zur Liste changePoints die Punkte in einem Element gespeichert, die zu verändern sind. Sie werden so als String hinzugefügt, dass man sie später nur mit einem ',' splitten
      72. /// muss.
      73. /// </summary>
      74. /// <param name="pointY">Y-Punkt des zu Verändernden Elements</param>
      75. /// <param name="pointX">x-Punkt des zu Verändernden Elements</param>
      76. /// <param name="cellType">Typ in den es geändert werden soll</param>
      77. /// <see cref="changePoints"/>
      78. static void addAsChange(int pointY, int pointX, string cellType) {
      79. changePoints.Add(pointY.ToString() + "," + pointX.ToString() + "," + cellType);
      80. }
      81. /// <summary>
      82. /// Hier wird die Generation mit den zuvor gespeicherten Punkten verändert. Dabei wird so vorgegangen:
      83. /// [0] = Y-Punkt
      84. /// [1] = X-Punkt
      85. /// [2] = Zellen Typ
      86. /// </summary>
      87. static void changeGeneration() {
      88. foreach (string elements in changePoints) {
      89. string[] vs = elements.Split(',');
      90. hashRows[Int16.Parse(vs[0])][Int16.Parse(vs[1])] = vs[2];
      91. }
      92. }
      93. /// <summary>
      94. /// Im folgenden wird mit den angegebenen Werten ein Index berechnet bzw. überprüft. Dabei muss man immer im Kopf behalten, dass das Spielfeld Torus-förmig ist. Heißt: wenn der zu suchende
      95. /// Index über das Spielfeld hinaus geht, ist er 0. Wenn er kleiner ist als das Spielfeld, ist er das letzte Item der Liste, also der maximal mögliche Wert.
      96. /// Sollte er aber Legitim mitten auf dem Spielfeld liegen, so wird er nicht verändert und nur zurück gegeben.
      97. /// </summary>
      98. /// <param name="maxVal">Größt möglicher Wert, letztes Item einer Liste</param>
      99. /// <param name="checkVal">Zu überprüfender Index</param>
      100. /// <returns>Legitimen Punkt auf dem Spielfeld.</returns>
      101. static int calcIndex(int maxVal, int checkVal) {
      102. if (checkVal >= maxVal) { checkVal = 0; } else if (checkVal < 0) { checkVal = maxVal - 1; }
      103. return checkVal;
      104. }
      105. /// <summary>
      106. /// Zählt wie viele Elemente einer Liste angegebenen Parameter enthalten.
      107. /// </summary>
      108. /// <param name="searchParam">Zu suchender Parameter</param>
      109. /// <param name="vs">Liste in der gesucht werden soll</param>
      110. /// <returns>Anzahl der Elemente, die angegebenen Parameter gleichen.</returns>
      111. static int countElementsWith(string searchParam, List<string> vs) {
      112. int i = 0;
      113. foreach(string element in vs) {
      114. if(element.Equals(searchParam)) { i++; }
      115. }
      116. return i;
      117. }
      118. /// <summary>
      119. /// Gibt die angegebene 2-Dimensionale String-Liste (das Spielfeld) aus.
      120. /// </summary>
      121. /// <param name="list">Auszugebene Liste</param>
      122. /// <param name="gen">Generation in der man sich befindet</param>
      123. static void doListOutput(List<List<string>> list, int gen) {
      124. Console.WriteLine( gen.ToString() + ". Generation:" + Environment.NewLine);
      125. foreach(List<string> listItm in list) {
      126. for(int i = 0; i < listItm.Count; i++) {
      127. Console.Write(listItm[i]);
      128. }
      129. Console.WriteLine();
      130. }
      131. Console.WriteLine();
      132. }
      133. }
      134. }




      In den Sourcecode-Austausch verschoben, da keine Binaries zum Download vorhanden sind.
      -Artentus
      Projekte

      Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Quellcoder02“ ()

      @Quellcoder02 Ohne Kommentar:
      Spielfeld.txt
      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      Programmierfragen über PN / Konversation werden ignoriert!
      @RodFromGermany komisch, bei mir funktioniert alles ohne Probleme. Befindet sich bei dir die Spielfeld.txt Datei auf dem Desktop auch unter dem Namen Spielfeld.txt? Oder kannst du mir zirka sagen wo bei dir der Fehler kommt?
      Projekte
      @Quellcoder02 unter VS13 und VS10 dasselbe:

      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      Programmierfragen über PN / Konversation werden ignoriert!
      Keine Probleme bei mir. VS17CE (15.6.3), daher Fehlertracking schwierig
      Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

      Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.