Entwickler-Ecke
WinForms - Tic-Tac-Toe
erlo68 - Fr 20.09.13 22:22
Titel: Tic-Tac-Toe
Moin erstmal...
bin was C# angeht noch recht Grün hinter den Ohren aber ich habe mir vorgenommen ein Tic-Tac-Toe Spiel zu programmieren, und bin dabei auf einige Hürden gestoßen die ich selbst nicht gelöst bekomme.
Es hat noch viele fehlende stellen wie den Bot oder die Gewinn-Abfragen aber man soll nachher entweder zu PvP oder PvE spielen können. Dafür Benutze ich PictureBoxen und überprüfe über ein 2-Dimensionales-Array die Gewinn-Abfragen.
Mein Hauptproblem liegt darin das ich das Hauptfenster quasi auf Eis legen will, solange ein anderes Fenster aktiv ist, da ich vor dem Start via 2 anderer Fenster die Namen der Spieler einlese. Ich wollte das so machen da ich das so schöner finde. nun möchte ich den Namen "Player1" im Form1 in den im Form2 eingegebenen Namen umwandeln aber statt dessen verschwindet sogar das "Player1" im Form1.
Ich habe ihn zwar Standardmäßig als "" deklariert aber diesen hab ich durch die Eingabe in Form2 überschrieben (meiner Meinung nach).
Zum Zweiten brauch ich eine Idee wie ich es hin bekomme, dass das Programm wartet bis ich ein Feld angeklickt habe und erst dann die Abfrage ob jemand gewonnen hat starte, noch nicht fertig aber der Testfall hat nicht gegriffen, da ich kein Plan davon habe in welcher Reihenfolge das Programm arbeitet. Währe schön wenn ich das irgendwie vorgeben könnte.
Hier meine Forms:
PS: Kann auf Wunsch auch das gesamte Projekt per PN schicken zur besseren Übersicht. Und schon mal Danke im Voraus :D
Form1:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101:
| namespace WindowsFormsApplication1 { public partial class Form1 : Form { public static int count = 0; public static bool player1 = false; public static string name1 = ""; public static string name2 = ""; public static bool player2 = false; public static bool wins = false; public static int[,] grid = { { 0, 0, 0 }, { 0, 0, 0 },{0, 0, 0} }; public Form1() { InitializeComponent(); }
private void button1_Click(object sender, EventArgs e) { button1.Enabled = false; button2.Enabled = true; button3.Enabled = true; pictureBox1.Enabled = true; pictureBox2.Enabled = true; pictureBox3.Enabled = true; pictureBox4.Enabled = true; pictureBox5.Enabled = true; pictureBox6.Enabled = true; pictureBox7.Enabled = true; pictureBox8.Enabled = true; pictureBox9.Enabled = true; if (player1 == true && player2 == true) { Form2 Player1 = new Form2(); Player1.Show(); label1.Text = name1; label2.Text = name2; } }
private void button2_Click(object sender, EventArgs e) { for (int i = 0; i < 3; i ++) { for (int j = 0; j < 3; j++) { grid[i, j] = 0; } } pictureBox1.Image = WindowsFormsApplication1.Properties.Resources.clear; pictureBox2.Image = WindowsFormsApplication1.Properties.Resources.clear; pictureBox3.Image = WindowsFormsApplication1.Properties.Resources.clear; pictureBox4.Image = WindowsFormsApplication1.Properties.Resources.clear; pictureBox5.Image = WindowsFormsApplication1.Properties.Resources.clear; pictureBox6.Image = WindowsFormsApplication1.Properties.Resources.clear; pictureBox7.Image = WindowsFormsApplication1.Properties.Resources.clear; pictureBox8.Image = WindowsFormsApplication1.Properties.Resources.clear; pictureBox9.Image = WindowsFormsApplication1.Properties.Resources.clear; pictureBox1.Enabled = true; pictureBox2.Enabled = true; pictureBox3.Enabled = true; pictureBox4.Enabled = true; pictureBox5.Enabled = true; pictureBox6.Enabled = true; pictureBox7.Enabled = true; pictureBox8.Enabled = true; pictureBox9.Enabled = true; count = 0; do { wins = win(grid); } while (wins == false); MessageBox.Show(name1 + " hat gewonnen!"); }
private static bool win(int[,] grid) { bool yes = false; if (grid[0, 0] == 1 && grid[1, 0] == 1 && grid[2, 0] == 1) { yes = true; } return yes; } private void button3_Click(object sender, EventArgs e) /Dient zum zurücksetzen der gesamten Form1 { while (Controls.Count > 0) { Controls[0].Dispose(); } count = 0; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { grid[i, j] = 0; } } InitializeComponent(); } |
Form2:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| namespace WindowsFormsApplication1 { public partial class Form2 : Form { public Form2() { InitializeComponent(); }
private void button1_Click(object sender, EventArgs e) { Form1.name1 = textBox1.Text; Form3 Player2 = new Form3(); Player2.Show(); this.Close(); } } } |
Form3:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
| namespace WindowsFormsApplication1 { public partial class Form3 : Form { public Form3() { InitializeComponent(); }
private void button1_Click(object sender, EventArgs e) { Form1.name2 = textBox1.Text; this.Close(); }
private void Form3_Load(object sender, EventArgs e) {
} } } |
Th69 - Sa 21.09.13 09:04
Hallo und :welcome:
daß die Namen nicht übernommen werden liegt daran, daß du die 2. Form zwar aufrufst, aber der Programmablauf danach sofort fortgesetzt wird (und dann sind die beiden Namensvariablen ja noch nicht gefüllt).
Verwende anstatt
Show() die Methode
ShowDialog() - diese wartet solange, bis das Fenster wieder geschlossen wird (dies ist dann ein sogenannter "modaler Dialog").
Einige Tipps kann ich dir auch noch geben (damit dein Programm besser wartbar bleibt):
- Packe (wie das interne
grid) die PictureBoxen in ein Array:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| private PictureBox[] pictureBoxes;
public Form1() { InitializeComponent();
pictureBoxes = new PictureBox[] { pictureBox1, pictureBox2, pictureBox9 }; } |
Nun kannst du elegant mithilfe einer Schleife die einzelnen PictureBoxen ansprechen, z.B.
C#-Quelltext
1: 2: 3: 4:
| foreach (PictureBox pb in pictureBoxes) { pb.Enabled = true; } |
- verwende möglichst keine öffentlichen (
public) Felder, sondern nimm dafür Eigenschaften
- und
static sollten deine meisten Variablen auch nicht sein
- nur eine Kleinigkeit:
den Namensbereich
WindowsFormsApplication1 brauchst du nicht zu schreiben, da die Klasse sich ja im selben Namensbereich befindet.
- die
do..while-Schleife bei der Gewinnabfrage blockiert deine GUI (sofern die Bedingung nciht erfüllt ist). In WinForms mußt du ereignisorientiert programmieren!
-
InitializeComponent() sollte nur innerhalb des Konstruktors aufgerufen werden (d.h. entferne diesen Aufruf sowie die
Controls-Schleife). Schreibe besser eine Methode, welche explizit wieder einzelne Controls initialisiert.
- die beiden Forms (für die Spielereingabe) sollten beide von der Hauptform aus aufgerufen werden (und dann reicht es auch, wenn du nur genau eine Spieler-Form erstellst und diese dann aber für jeden Spieler einmal aufrufst - anstatt 2 (fast) identische Form-Klassen zu erstellen). Wenn du für den Namen dann eine Eigenschaft verwendest, so benötigst du dann auch nicht mehr die
public static Namensvariablen in
Form1).
Wenn du mal etwas Zeit (und Muße) hast, kannst du dir mal meinen Artikel
Kommunikation von 2 Forms [
http://www.bitel.net/dghm1164/programming/Kommunikation_von_2_Forms.html] durchlesen (dieser geht auf einige der oben beschriebenen Tipps ein - besonders Eigenschaften und Ereignisse - und am Ende befindet sich auch ein Beispielprojekt).
P.S: Ich hoffe, ich habe dich jetzt nicht mit der Menge an Informationen abgeschreckt!?
erlo68 - Sa 21.09.13 21:40
Danke erstmal für die schnelle Antwort.
Ich habe einige deiner Vorschläge befolgt und das meiste funktioniert nun.
Zudem da ich noch Anfänger bin weiß ich nicht wie ich die Controls einzeln initialisieren soll, da mir die jetzige Methode nicht mehr komplett weiterhilft wie ich feststellen musste.
Nur weiß ich nicht was du mit "Eigenschaften" meintest, aber nun habe ich das Problem das ich den Computer Gegner nicht implementiert bekomme.
Am liebsten würde ich ihn durch 2-3 eigene Methoden erstelle wozu ich aber eine Möglichkeit bräuchte die meinem Programm sagt das ich und der Bot abwechselnd spielen, der bot soll also warten bis ich meinen Zug gemacht habe. Im Moment versuche ich ihn durch eine Komplette Erweiterung der meisten meiner Methoden welsche die PictureBoxen betrifft einzufügen, insofern das er immer dann an der Reihe ist sobald der "Enabled"-Status geändert wurde welches eintrifft sobald ein Feld angeklickt und somit nicht mehr anklickbar sein soll. Dies führte aber zu weiteren Fehlern die mich zwingen würden meine ganze Struktur auf den Bot auszulegen worauf ich aber nicht hinaus möchte.
Irgendwelche Ideen oder Anregungen? :?!?:
Th69 - Mo 23.09.13 16:55
Hallo,
bei Eigenschaften meine ich selbige der Programmiersprache C#:
Eigenschaften [
http://msdn.microsoft.com/de-de/library/x9fsa0sw%28v=vs.90%29.aspx].
Und mit deinem "Bot" (andere sagen auch "KI" dazu) bist du schon auf dem richtigen Weg. Immer wenn der Spieler einen Zug ausgeführt hat, läßt du den "Bot" einen Zug berechnen und durchführen. Wenn du diese Funktionalität in eine Methode packst, so reduziert sich dadurch der Code.
Ich lese aus deiner Beschreibung, daß du für jede einzelne PictureBox eine eigene Ereignismethode hinterlegt hast. Dies ist aber nicht erforderlich - besser ist es, nur eine Ereignismethode für alle PictureBox-Click zu verwenden und dann anhand des übergebenen Objekts
sender die PcitrueBox zu ermitteln:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| void PictureBox_Click(object sender, EventArgs e) { PictureBox pb = sender as PictureBox; if (pb != null) { pb.Enabled = false; CalculateBot(); } } |
erlo68 - Mo 23.09.13 18:35
Mit dem Wort KI halte mich da etwas zurück da dieser ja nur vorbestimmte Abfragen abgeht ^^
Aber jetzt fällt es mir wie Schuppen von den Augen! O-O
Ich bin natürlich so schlau un benutze die Enabled.Changed-Events anstatt der Click-Events *facepalm* das würde einiges vereinfachen. Nungut erstmal danke für den Rat und ich meld mich dann wieder obs geklappt hat.
EDIT: Naja kurz nach der "Erleuchtung" ist mir eingefallen,da ich auch Bot gegen Bot spielen lassen will, da komm ich mit Click-Events nicht weit :/
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!