Programmieren eines Tic Tac Toe-Spiels

Das Programmieren von Computerspielen kann die technisch anspruchsvollste (und möglicherweise die bestbezahlte) Aufgabe sein, die ein Programmierer haben kann. Top-Level-Spiele erfordern sowohl von Programmierern als auch von Computern das Beste.

Visual Basic 6 wurde nun als Plattform für die Spielprogrammierung vollständig umgangen. (Es war nie wirklich eine. Selbst in den "guten alten Tagen" würden ernsthafte Spielprogrammierer niemals eine Hochsprache wie VB 6 verwenden, weil Sie einfach nicht die Spitzenleistung erzielen konnten, die die meisten Spiele benötigen.) Aber die einfaches "Tic Tac Toe" -Spiel ist eine großartige Einführung in die Programmierung, die etwas fortgeschrittener ist als "Hello World!"

Dies ist eine großartige Einführung in viele der grundlegenden Konzepte der Programmierung, da sie Techniken kombiniert, darunter:

  • Die Verwendung von Arrays. Die X- und O-Marker werden in separaten Arrays gespeichert und die gesamten Arrays werden zwischen Funktionen ausgetauscht, um den Fortschritt des Spiels zu verfolgen.
  • Verwenden von VB 6-Grafiken: VB 6 bietet keine großartigen Grafikfunktionen, aber das Spiel ist eine gute Einführung in die verfügbaren Funktionen. Ein Großteil des Restes dieser Serie befasst sich mit der Frage, wie GDI +, die nächste Generation von Microsoft-Grafiken, die VB 6-Grafik ersetzt.
  • Verwenden von mathematischen Berechnungen zur Programmsteuerung: Das Programm verwendet clevere Modulo- (Mod) und Ganzzahl-Divisionsberechnungen unter Verwendung der Zwei-Spiel-Marker-Arrays, um zu bestimmen, wann ein "Gewinn" aus drei Elementen aufgetreten ist.

Die Programmierklasse in diesem Artikel ist vielleicht noch nicht ganz so weit fortgeschritten, sollte aber für "fortgeschrittene" Programmierer geeignet sein. Beginnen wir jedoch auf einer elementaren Ebene, um einige der Konzepte zu veranschaulichen und Ihnen den Einstieg in Ihre Karriere als Visual Basic-Programmierer zu erleichtern. Sogar für fortgeschrittene Schüler ist es möglicherweise eine leichte Herausforderung, die Objekte in die richtige Form zu bringen.

Wie man Tic Tac Toe spielt

Wenn Sie noch nie Tic Tac Toe gespielt haben, finden Sie hier die Regeln. Zwei Spieler wechseln sich beim Platzieren von Xs und Os auf 3 x 3 Spielfeldern ab.

Bevor das Spiel beginnt, müssen sich beide Spieler darauf einigen, wer zuerst geht und wer seine Züge mit welchem ​​Symbol markiert. Nach dem ersten Zug setzen die Spieler abwechselnd ihre Marken in eine leere Zelle. Das Ziel des Spiels ist es, der erste Spieler mit drei Markierungen in einer horizontalen, diagonalen oder vertikalen Linie zu sein. Wenn keine leeren Zellen vorhanden sind und keiner der Spieler eine Gewinnkombination hat, ist das Spiel unentschieden.

Programm starten

Bevor Sie mit der eigentlichen Codierung beginnen, sollten Sie immer die Namen der von Ihnen verwendeten Komponenten ändern. Sobald Sie mit dem Codieren beginnen, wird der Name automatisch von Visual Basic verwendet, sodass Sie möchten, dass er der richtige Name ist. Wir werden den Formularnamen verwenden frmTicTacToe und wir werden auch die Beschriftung in "Über Tic Tac Toe" ändern.

Verwenden Sie bei eingerichtetem Formular das Linien-Toolbox-Steuerelement, um ein 3 x 3-Raster zu zeichnen. Klicken Sie auf das Linienwerkzeug und zeichnen Sie eine Linie an der gewünschten Stelle. Sie müssen auf diese Weise vier Linien erstellen und ihre Länge und Position anpassen, damit sie richtig aussehen. Visual Basic verfügt auch über einige praktische Tools im Menü Format, die hilfreich sind. Dies ist eine großartige Gelegenheit, mit ihnen zu üben.

Zusätzlich zum Spielfeld benötigen wir einige Objekte für die X- und O-Symbole, die auf dem Feld platziert werden. Da das Raster neun Leerzeichen enthält, erstellen wir ein Objektarray mit neun Leerzeichen, die in Visual Basic als Elemente bezeichnet werden.

In der Visual Basic-Entwicklungsumgebung gibt es mehrere Möglichkeiten, fast alles zu tun, und das Erstellen von Steuerfeldern ist keine Ausnahme. Am einfachsten ist es wahrscheinlich, das erste Etikett zu erstellen (klicken und zeichnen wie beim Linienwerkzeug), es zu benennen, alle Attribute (wie z. B. Schriftart und ForeColor) festzulegen und dann Kopien davon zu erstellen. VB 6 fragt, ob Sie ein Control Array erstellen möchten. Verwenden Sie den Namen lblPlayGround für das erste Etikett.

Um die anderen acht Elemente des Rasters zu erstellen, wählen Sie das erste Beschriftungsobjekt aus, setzen Sie die Index-Eigenschaft auf Null und drücken Sie STRG + C (Kopieren). Jetzt können Sie STRG + V (Einfügen) drücken, um ein weiteres Beschriftungsobjekt zu erstellen. Wenn Sie Objekte wie dieses kopieren, übernimmt jede Kopie alle Eigenschaften mit Ausnahme von Index von der ersten. Der Index erhöht sich für jedes Exemplar um eins. Dies ist ein Steuerfeld, da alle denselben Namen, aber unterschiedliche Indexwerte haben.

Wenn Sie das Array auf diese Weise erstellen, werden alle Kopien in der oberen linken Ecke des Formulars übereinander gestapelt. Ziehen Sie jedes Etikett an eine der Positionen des Wiedergaberasters. Stellen Sie sicher, dass die Indexwerte im Raster fortlaufend sind. Die Logik des Programms hängt davon ab. Das Beschriftungsobjekt mit dem Indexwert 0 sollte sich in der oberen linken Ecke befinden, und die untere rechte Beschriftung sollte den Index 8 aufweisen. Wenn die Beschriftungen das Wiedergaberaster abdecken, wählen Sie die einzelnen Beschriftungen aus, klicken Sie mit der rechten Maustaste, und wählen Sie die Option "An den Hintergrund senden".

Da es acht Möglichkeiten gibt, das Spiel zu gewinnen, benötigen wir acht verschiedene Linien, um den Gewinn auf dem Spielfeld anzuzeigen. Sie verwenden dieselbe Technik, um ein anderes Steuerfeld zu erstellen. Zeichnen Sie zuerst die Linie, nennen Sie sie linWin und setzen Sie die Index-Eigenschaft auf Null. Verwenden Sie dann die Copy-Paste-Technik, um weitere sieben Zeilen zu erstellen. Die folgende Abbildung zeigt, wie die Indexnummern richtig eingestellt werden.

Zusätzlich zu den Beschriftungs- und Linienobjekten benötigen Sie einige Befehlsschaltflächen, um das Spiel zu spielen, und weitere Beschriftungen, um die Punktzahl zu halten. Die Schritte zum Erstellen dieser werden hier nicht detailliert beschrieben, aber dies sind die Objekte, die Sie benötigen.

Zwei Schaltflächenobjekte:

  • cmdNewGame
  • cmdResetScore

Das Frame-Objekt fraPlayFirst enthält zwei Optionsfelder:

  • optXPlayer
  • optOPlayer

Rahmenobjekt fraScoreBoard mit sechs Beschriftungen. Im Programmcode werden nur lblXScore und lblOScore geändert.

  • lblX
  • lblXScore
  • IblO
  • lblOScore
  • lblMinus
  • lblColon

Schließlich benötigen Sie auch das Beschriftungsobjekt lblStartMsg, um die Schaltfläche cmdNewGame zu maskieren, wenn nicht darauf geklickt werden soll. Dies ist in der folgenden Abbildung nicht sichtbar, da es denselben Platz im Formular einnimmt wie die Befehlsschaltfläche. Möglicherweise müssen Sie die Befehlsschaltfläche vorübergehend verschieben, um diese Beschriftung auf dem Formular zu zeichnen.

Bisher wurde noch keine VB-Codierung durchgeführt, aber wir sind endlich dazu bereit.

Initialisierung

Jetzt können Sie endlich mit dem Codieren des Programms beginnen. Wenn Sie dies noch nicht getan haben, möchten Sie möglicherweise den Quellcode herunterladen, um die Funktionsweise des Programms zu erläutern.

Eine der ersten Designentscheidungen, die getroffen werden müssen, besteht darin, den aktuellen "Status" des Spiels zu verfolgen. Mit anderen Worten, was sind die aktuellen Xs und Os auf dem Spielfeld und wer bewegt sich als nächstes? Das Konzept des Status ist bei vielen Programmiervorgängen von entscheidender Bedeutung, insbesondere bei der Programmierung von ASP und ASP.NET für das Web

Es gibt verschiedene Möglichkeiten, dies zu tun. Dies ist also ein kritischer Schritt in der Analyse. Wenn Sie dieses Problem alleine gelöst haben, möchten Sie möglicherweise ein Flussdiagramm zeichnen und verschiedene Optionen mit "Rubbelpapier" ausprobieren, bevor Sie mit dem Codieren beginnen.

Variablen

Unsere Lösung verwendet zwei "zweidimensionale Arrays", da dies dazu beiträgt, den Status zu verfolgen, indem einfach die Array-Indizes in Programmschleifen geändert werden. Der Status der oberen linken Ecke befindet sich im Array-Element mit dem Index (1, 1), die obere rechte Ecke befindet sich in (1, 3), die untere rechte Ecke in (3,3) usw. . Die beiden Arrays, die dies tun, sind:

iXPos (x, y)

und

iOPos (x, y)

Es gibt viele verschiedene Möglichkeiten, dies zu tun, und die endgültige VB.NET-Lösung in dieser Reihe zeigt Ihnen, wie Sie dies mit nur einem eindimensionalen Array tun können.

Die Programmierung, um diese Arrays in Spielergewinnentscheidungen und sichtbare Anzeigen im Formular zu übersetzen, befindet sich auf der nächsten Seite.

Sie benötigen auch einige globale Variablen wie folgt. Beachten Sie, dass sich diese im Code "Allgemein" und "Erklärungen" für das Formular befinden. Dies macht sie zu Variablen auf "Modulebene", auf die für dieses Formular an beliebiger Stelle im Code verwiesen werden kann. Weitere Informationen hierzu finden Sie in der Visual Basic-Hilfe unter Grundlegendes zum Variablenbereich.

Es gibt zwei Bereiche, in denen Variablen in unserem Programm initialisiert werden. Zunächst werden einige Variablen initialisiert, während das Formular frmTicTacToe geladen wird.

Private Sub Form_Load ()

Zweitens werden vor jedem neuen Spiel alle Variablen, die auf Startwerte zurückgesetzt werden müssen, in einem Initialisierungsunterprogramm zugewiesen.

Sub InitPlayGround ()

Beachten Sie, dass die Formularladeinitialisierung auch die Spielplatzinitialisierung aufruft.

Eine der entscheidenden Fähigkeiten eines Programmierers ist die Fähigkeit, mithilfe der Debugging-Funktionen zu verstehen, was der Code tut. Mit diesem Programm können Sie Folgendes versuchen:

  • Den Code mit der Taste F8 durchgehen
  • Festlegen einer Überwachung für Schlüsselvariablen wie sPlaySign oder iMove
    Einen Haltepunkt setzen und den Wert von Variablen abfragen. Zum Beispiel in der inneren Schleife der Initialisierung:
lblPlayGround ((i - 1) * 3 + j - 1) .Caption = ""

Beachten Sie, dass dieses Programm deutlich macht, warum es eine gute Programmierpraxis ist, Daten nach Möglichkeit in Arrays zu speichern. Wenn Sie keine Arrays in diesem Programm hätten, müssten Sie Code in etwa so schreiben:

Line0.Visible = False
Line1.Visible = False
Line2.Visible = False
Line3.Visible = False
Line4.Visible = False
Line5.Visible = False
Line6.Visible = False
Line7.Visible = False

an Stelle von:

Für i = 0 bis 7
linWin (i) .Visible = False
Weiter i

Einen Zug machen

Wenn ein Teil des Systems als "das Herz" betrachtet werden kann, ist es die Subroutine lblPlayGround_Click. Diese Unterroutine wird jedes Mal aufgerufen, wenn ein Spieler auf das Spielfeld klickt. (Klicks müssen sich in einem der neun lblPlayGround-Elemente befinden.) Beachten Sie, dass diese Unterroutine ein Argument hat: (Index As Integer). Die meisten anderen 'Event-Subroutinen' wie cmdNewGame_Click () tun dies nicht. Der Index gibt an, auf welches Beschriftungsobjekt geklickt wurde. Beispielsweise würde der Index den Wert Null für die linke obere Ecke des Rasters und den Wert Acht für die rechte untere Ecke enthalten.

Nachdem ein Spieler auf ein Quadrat im Spielfeld geklickt hat, wird die Befehlsschaltfläche zum Starten eines anderen Spiels, cmdNewGame, "eingeschaltet", indem sie sichtbar gemacht wird. Der Status dieser Befehlsschaltfläche hat doppelte Funktion, da sie später auch als boolesche Entscheidungsvariable verwendet wird In der Regel wird davon abgeraten, einen Eigenschaftswert als Entscheidungsvariable zu verwenden, da das Programm unerwartet fehlschlagen wird, wenn es jemals erforderlich wird, das Programm zu ändern (z. B. um die Befehlsschaltfläche cmdNewGame ständig sichtbar zu machen) Sie erinnern sich vielleicht nicht, dass es auch als Teil der Programmlogik verwendet wird. Aus diesem Grund ist es immer eine gute Idee, den Programmcode zu durchsuchen und die Verwendung von Änderungen zu überprüfen, die Sie bei der Programmwartung vornehmen, auch von Eigenschaftswerten Teilweise, um dies zu verdeutlichen, und teilweise, weil dies ein relativ einfacher Teil des Codes ist, in dem es einfacher ist, zu sehen, was gerade getan wird, und Probleme zu einem späteren Zeitpunkt zu vermeiden.

Eine Spielerauswahl eines Spielfelds wird verarbeitet, indem die GamePlay-Subroutine mit Index als Argument aufgerufen wird.

Bearbeitung des Umzugs

Zuerst prüfen Sie, ob ein nicht belegtes Quadrat angeklickt wurde.

If lblPlayGround (xo_Move) .Caption = "" Dann

Sobald wir sicher sind, dass dies ein legitimer Zug ist, wird der Bewegungszähler (iMove) inkrementiert. Die nächsten beiden Zeilen sind sehr interessant, da sie die Koordinaten aus dem eindimensionalen If lblPlayGround-Komponentenarray in zweidimensionale Indizes übersetzen, die Sie entweder in iXPos oder iOPos verwenden können. Mod und Integer Division (der 'Backslash') sind mathematische Operationen, die Sie nicht jeden Tag benutzen, aber hier ist ein großartiges Beispiel, wie sie sehr nützlich sein können.

 If lblPlayGround (xo_Move) .Caption = "" Dann
iMove = iMove + 1
x = Int (xo_Move / 3) + 1
y = (xo_Move Mod 3) + 1

Der xo_Move-Wert 0 wird in (1, 1), 1 bis (1, 2)… 3 bis (2, 1)… 8 bis (3, 3) übersetzt..

Der Wert in sPlaySign, einer Variablen mit Modulbereich, protokolliert, welcher Spieler den Zug ausgeführt hat. Sobald die Verschiebearrays aktualisiert wurden, können die Beschriftungskomponenten im Wiedergaberaster mit dem entsprechenden Zeichen aktualisiert werden.

Wenn sPlaySign = "O", dann
iOPos (x, y) = 1
iWin = CheckWin (iOPos ())
Sonst
iXPos (x, y) = 1
iWin = CheckWin (iXPos ())
End If
lblPlayGround (xo_Move) .Caption = sPlaySign

Wenn der X-Player beispielsweise auf die linke obere Ecke des Rasters klickt, haben die Variablen die folgenden Werte:

Der Benutzerbildschirm zeigt nur ein X in der oberen linken Box an, während der iXPos in der oberen linken Box eine 1 und in allen anderen eine 0 hat. Das iOPos hat 0 in jeder Box.

Die Werte ändern sich, wenn der O-Spieler auf das mittlere Quadrat des Gitters klickt. Jetzt zeigt das iOPos eine 1 in der mittleren Box, während der Benutzerbildschirm oben links ein X und in der mittleren Box ein O anzeigt. Das iXPos zeigt nur die 1 in der oberen linken Ecke und die 0 in allen anderen Feldern.

Nachdem Sie nun wissen, wo ein Spieler geklickt hat und welcher Spieler geklickt hat (unter Verwendung des Werts in sPlaySign), müssen Sie nur noch herausfinden, ob jemand ein Spiel gewonnen hat, und herausfinden, wie dies im Display angezeigt werden kann.

Einen Gewinner finden

Nach jedem Zug sucht die CheckWin-Funktion nach der Gewinnkombination. CheckWin fügt jede Zeile, jede Spalte und jede Diagonale hinzu. Das Verfolgen der Schritte durch CheckWin mithilfe der Debug-Funktion von Visual Basic kann sehr lehrreich sein. Um einen Gewinn zu finden, müssen Sie zunächst prüfen, ob in jeder der einzelnen Prüfungen in der Variablen iScore drei Einsen gefunden wurden, und anschließend einen eindeutigen "Signatur" -Wert in Checkwin zurückgeben, der als Array-Index zum Ändern der Visible-Eigenschaft von verwendet wird ein Element im linWin-Komponentenarray. Wenn es keinen Gewinner gibt, enthält CheckWin den Wert -1. Wenn es einen Gewinner gibt, wird die Anzeige aktualisiert, die Anzeigetafel geändert, eine Glückwunschmeldung angezeigt und das Spiel neu gestartet.

Lassen Sie uns einen der Checks im Detail durchgehen, um zu sehen, wie es funktioniert. Die anderen sind ähnlich.

'Überprüfen Sie die Zeilen für 3
Für i = 1 bis 3
iScore = 0
CheckWin = CheckWin + 1
Für j = 1 bis 3
iScore = iScore + iPos (i, j)
Weiter j
Wenn iScore = 3, dann
Funktion beenden
End If
Weiter i

Das erste, was zu bemerken ist, ist, dass der erste Indexzähler i die Zeilen herunterzählt, während das zweite j über die Spalten hinweg zählt. Die äußere Schleife bewegt sich dann einfach von einer Reihe zur nächsten. Die innere Schleife zählt die Einsen in der aktuellen Zeile. Wenn es drei gibt, haben Sie einen Gewinner.

Beachten Sie, dass Sie auch die Gesamtzahl der in der Variablen CheckWin getesteten Quadrate verfolgen. Dies ist der Wert, der beim Beenden dieser Funktion zurückgegeben wird. Jede Gewinnkombination erhält in CheckWin einen eindeutigen Wert von 0 bis 7, mit dem eines der Elemente im linWin () -Komponentenarray ausgewählt wird. Daher ist auch die Reihenfolge des Codes in der Funktion CheckWin wichtig! Wenn Sie einen der Loop-Code-Blöcke (wie oben) verschoben haben, wird beim Gewinn eines Spielers die falsche Linie auf dem Spielfeld angezeigt. Probieren Sie es aus und sehen Sie!

Abschlussdetails

Der einzige Code, der noch nicht besprochen wurde, ist das Unterprogramm für ein neues Spiel und das Unterprogramm, das die Punktzahl zurücksetzt. Der Rest der Logik im System macht das Erstellen dieser ganz einfach. Um ein neues Spiel zu starten, müssen Sie nur die Unterroutine InitPlayGround aufrufen. Da die Schaltfläche während eines Spiels angeklickt werden kann, bitten Sie die Spieler um Bestätigung, bevor Sie fortfahren. Sie bitten auch um Bestätigung, bevor Sie die Anzeigetafel neu starten.