Programowanie gry w kółko i krzyżyk

Dzieci bawiące się w kółko i krzyżyk na placu zabaw

Filipe Pinto/Getty Images





Programowanie gry komputerowe może być najbardziej wymagającą technicznie (i prawdopodobnie najlepiej płatną) pracą, która: programista może mieć. Gry na najwyższym poziomie wymagają tego, co najlepsze zarówno od programistów, jak i komputerów.

Visual Basic 6 został całkowicie ominięty jako platforma do programowania gier. (Nigdy tak naprawdę nie było. Nawet w „starych dobrych czasach” poważni programiści nigdy nie używaliby języka wysokiego poziomu, takiego jak VB 6, ponieważ po prostu nie można było uzyskać najwyższej wydajności, której wymaga większość gier). prosta gra „Kółko i krzyżyk” to świetne wprowadzenie do programowania, które jest nieco bardziej zaawansowane niż 'Witaj świecie!'



To świetne wprowadzenie do wielu podstawowych pojęć programowania, ponieważ łączy w sobie techniki, w tym:

  • Sposób użycia tablice . Znaczniki X i O są przechowywane w oddzielnych tablicach, a całe tablice są przekazywane między funkcjami, aby śledzić postęp gry.
  • Korzystanie z grafiki poziomu VB 6: VB 6 nie oferuje wielkich możliwości graficznych, ale gra jest dobrym wprowadzeniem do tego, co jest dostępne. Znaczna część tej serii to eksploracja, w jaki sposób GDI+, następna generacja grafiki firmy Microsoft, zastępuje grafikę poziomu VB 6.
  • Korzystanie z obliczeń matematycznych do sterowania programem: program wykorzystuje sprytne obliczenia modulo (Mod) i dzielenia liczb całkowitych przy użyciu tablic znaczników dwóch gier, aby określić, kiedy nastąpiło trzyelementowe „wygrane”.

Klasa programowania w tym artykule jest może trochę poza poziomem początkującym, ale powinna być dobra dla 'średniozaawansowanych' programistów. Ale zacznijmy od poziomu podstawowego, aby zilustrować niektóre koncepcje i zacząć od Visual Basic kariera programowania gier. Nawet bardziej zaawansowani uczniowie mogą uznać, że uzyskanie odpowiedniej formy obiektów jest nieco trudne.



Jak grać w kółko i krzyżyk

Jeśli nigdy nie grałeś Kółko i krzyżyk , oto zasady. Dwóch graczy naprzemiennie umieszcza Xs i O na polu gry 3x3.

Przed rozpoczęciem gry obaj gracze muszą uzgodnić, kto pójdzie pierwszy i kto zaznaczy swoje ruchy jakim symbolem. Po pierwszym ruchu gracze naprzemiennie umieszczają swoje znaki w dowolnej pustej komórce. Celem gry jest bycie pierwszym graczem z trzema znakami w linii poziomej, ukośnej lub pionowej. Jeśli nie ma pustych komórek i żaden z graczy nie ma wygrywającej kombinacji, gra kończy się remisem.

Rozpoczęcie programu

Przed rozpoczęciem jakiegokolwiek kodowania zawsze dobrze jest zmienić nazwy wszystkich używanych komponentów. Kiedy zacznieszkodowanie, nazwa będzie używana automatycznie przez Visual Basic, więc chcesz, aby była to prawidłowa nazwa. Użyjemy nazwy formularza frmTicTactToe zmienimy też podpis na „O Kółku i krzyżyku”.

Po utworzeniu formularza użyj kontrolki przybornika linii, aby narysować siatkę 3 x 3. Kliknij narzędzie linii, a następnie narysuj linię w wybranym miejscu. Będziesz musiał stworzyć w ten sposób cztery linie i dostosować ich długość i położenie, aby wyglądały dobrze. Visual Basic ma również kilka wygodnych narzędzi w menu Format, które pomogą. To świetna okazja, aby z nimi poćwiczyć.



Oprócz siatki do gry, będziemy potrzebować kilku obiektów dla symboli X i O, które zostaną umieszczone na siatce. Ponieważ w siatce jest dziewięć spacji, utworzymy tablicę obiektów z dziewięcioma spacjami, zwanych elementami w Visual Basic.

Istnieje kilka sposobów na zrobienie prawie wszystkiego w środowisku programistycznym Visual Basic, a tworzenie tablic kontrolnych nie jest wyjątkiem. Prawdopodobnie najłatwiejszym sposobem jest utworzenie pierwszej etykiety (kliknij i narysuj tak jak narzędzie linii), nazwij ją, ustaw wszystkie atrybuty (takie jak Font i ForeColor), a następnie wykonaj jej kopie. VB 6 zapyta, czy chcesz utworzyć tablicę kontrolną. Jako pierwszej etykiety użyj nazwy lblPlayGround.



Aby utworzyć pozostałe osiem elementów siatki, wybierz pierwszy obiekt etykiety, ustaw właściwość Indeks na zero i naciśnij klawisze CTRL+C (kopiowanie). Teraz możesz nacisnąć CTRL+V (wklej), aby utworzyć kolejny obiekt etykiety. Kiedy kopiujesz obiekty w ten sposób, każda kopia odziedziczy wszystkie właściwości z wyjątkiem Index z pierwszej. Indeks zwiększy się o jeden dla każdej kopii. Jest to tablica kontrolna, ponieważ wszystkie mają tę samą nazwę, ale różne wartości indeksu.

Jeśli utworzysz tablicę w ten sposób, wszystkie kopie zostaną ułożone jedna na drugiej w lewym górnym rogu formularza. Przeciągnij każdą etykietę do jednej z pozycji siatki gry. Upewnij się, że wartości indeksu są sekwencyjne w siatce. Od tego zależy logika programu. Obiekt etykiety z indeksem o wartości 0 powinien znajdować się w lewym górnym rogu, a dolna prawa etykieta powinna mieć indeks 8. Jeśli etykiety pokrywają siatkę odtwarzania, zaznacz każdą etykietę, kliknij prawym przyciskiem myszy i wybierz opcję Przesuń na spód.



Ponieważ istnieje osiem możliwych sposobów na wygranie gry, będziemy potrzebować ośmiu różnych linii, aby pokazać wygraną na siatce gry. Użyjesz tej samej techniki, aby utworzyć kolejną tablicę kontrolną. Najpierw narysuj linię, nazwij ją linWin i ustaw właściwość Index na zero. Następnie użyj techniki kopiuj-wklej, aby utworzyć siedem kolejnych linii. Poniższa ilustracja pokazuje, jak poprawnie ustawić numery indeksu.

Oprócz obiektów etykiet i linii, potrzebujesz kilku przycisków poleceń, aby zagrać w grę i więcej etykiet, aby uzyskać wynik. Kroki prowadzące do ich utworzenia nie są tutaj szczegółowo opisane, ale są to obiekty, których potrzebujesz.



Dwa przyciski przedmioty :

  • cmdNowaGra
  • cmdResetScore

Obiekt ramki fraPlayFirst zawierający dwa przyciski opcji:

  • optXPlayer
  • optOPlayer

Obiekt ramki fraScoreBoard zawierający sześć etykiet. W kodzie programu zmieniane są tylko lblXScore i lblOScore.

  • lblX
  • lblXScore
  • lblO
  • IBLOScore
  • lblMinus
  • lblDwukropek

Na koniec potrzebujesz również obiektu etykiety lblStartMsg, aby „zamaskować” przycisk cmdNewGame, gdy nie powinien być klikany. Nie jest to widoczne na poniższej ilustracji, ponieważ zajmuje to samo miejsce w formularzu co przycisk polecenia. Może być konieczne tymczasowe przesunięcie przycisku polecenia, aby narysować tę etykietę na formularzu.

Jak dotąd nie wykonano żadnego kodowania VB, ale w końcu jesteśmy do tego gotowi.

Inicjalizacja

Teraz możesz wreszcie zacząć kodować program. Jeśli jeszcze tego nie zrobiłeś, możesz pobrać kod źródłowy, aby śledzić działanie programu.

Jedną z pierwszych decyzji projektowych, jakie należy podjąć, jest śledzenie aktualnego „stanu” gry. Innymi słowy, jakie są obecne X i O na siatce gry i kto się dalej porusza. Pojęcie „stanu” ma kluczowe znaczenie w wielu programach, a w szczególności jest ważne w programowaniu ASP i ASP.NET for the web

Można to zrobić na kilka sposobów, więc jest to krytyczny krok w analizie. Jeśli rozwiązywałeś ten problem samodzielnie, możesz chcieć narysować schemat blokowy i wypróbować różne opcje za pomocą „zdrapki”, zanim zaczniesz kodować.

Zmienne

Nasze rozwiązanie wykorzystuje dwie „tablice dwuwymiarowe”, ponieważ pomaga to śledzić „stan” po prostu zmieniając indeksy tablicy w pętlach programowych. Stan lewego górnego rogu będzie w elemencie tablicy z indeksem (1, 1), prawy górny róg będzie w (1, 3), prawy dolny w (3,3) i tak dalej . Dwie tablice, które to robią, to:

iXPos(x, y)

oraz

iOP(x, y)

Można to zrobić na wiele różnych sposobów, a ostateczne rozwiązanie VB.NET z tej serii pokazuje, jak to zrobić za pomocą pojedynczej tablicy jednowymiarowej.

Programy do tłumaczenia tych tablic na decyzje dotyczące wygranych graczy i widoczne wyświetlacze w formularzu znajdują się na następnej stronie.

Potrzebujesz również kilku zmiennych globalnych w następujący sposób. Zwróć uwagę, że znajdują się one w kodzie Ogólne i Deklaracje formularza. To sprawia, że „poziom modułu” zmienne, do których można się odwoływać w dowolnym miejscu w kodzie tego formularza. Aby uzyskać więcej informacji na ten temat, sprawdź Zrozumienie zakresu zmiennych w pomocy Visual Basic.

Istnieją dwa obszary, w których zmienne są inicjowane w naszym programie. Po pierwsze, kilka zmiennych jest inicjowanych podczas ładowania formularza frmTicTacToe.

Prywatny formularz podrzędny_Load()

Po drugie, przed każdą nową grą wszystkie zmienne, które muszą zostać zresetowane do wartości początkowych, są przypisywane w podprogramie inicjującym.

Sub InitPlayGround()

Należy zauważyć, że inicjowanie ładowania formularza wywołuje również inicjalizację placu zabaw.

Jedną z krytycznych umiejętności programisty jest umiejętność korzystania z funkcji debugowania w celu zrozumienia, co robi kod. Możesz użyć tego programu, aby wypróbować:

  • Przechodzenie przez kod klawiszem F8
  • Ustawianie zegarka na kluczowych zmiennych, takich jak sPlaySign lub iMove
    Ustawianie punktu przerwania i odpytywanie wartości zmiennych. Na przykład w wewnętrznej pętli inicjalizacji:
lblPlayGround((i - 1) * 3 + j - 1). Podpis = ''

Zauważ, że ten program wyraźnie pokazuje, dlaczego dobrą praktyką programistyczną jest przechowywanie danych w tablicach, kiedy tylko jest to możliwe. Gdybyś nie miał tablic w tym programie, musiałbyś napisać kod taki:

Linia0. Widoczny = Fałsz
Linia1.Widoczny = Fałsz
Linia2.Widoczny = Fałsz
Linia3.Widoczny = Fałsz
Linia4. Widoczny = Fałsz
Linia5. Widoczny = Fałsz
Linia6. Widoczny = Fałsz
Linia7.Widoczny = Fałsz

zamiast tego:

Dla i = 0 do 7
linWin(i).Visible = False
Dalej ja

Wykonywanie ruchu

Jeśli jakakolwiek część systemu może być uważana za „serce”, jest to podprogram lblPlayGround_Click. Ten podprogram jest wywoływany za każdym razem, gdy gracz kliknie siatkę gry. (Kliknięcia muszą znajdować się wewnątrz jednego z dziewięciu elementów lblPlayGround). Zauważ, że ten podprogram ma argument: (Index As Integer). Większość innych „podprogramów zdarzeń”, takich jak cmdNewGame_Click(), tego nie robi. Indeks wskazuje, który obiekt etykiety został kliknięty. Na przykład indeks zawierałby wartość zero dla lewego górnego rogu siatki i wartość osiem dla prawego dolnego rogu.

Gdy gracz kliknie kwadrat w siatce gry, przycisk polecenia uruchomienia innej gry, cmdNewGame, zostaje „włączony”, dzięki czemu jest widoczny. Stan tego przycisku polecenia pełni podwójną funkcję, ponieważ w dalszej części programu jest on również używany jako boolowska zmienna decyzyjna. Używanie wartości właściwości jako zmiennej decyzyjnej jest zwykle odradzane, ponieważ jeśli kiedykolwiek zajdzie potrzeba zmiany programu (na przykład, aby przycisk polecenia cmdNewGame był widoczny przez cały czas), program nieoczekiwanie zakończy się niepowodzeniem, ponieważ możesz nie pamiętać że jest również używany jako część logiki programu. Z tego powodu zawsze dobrze jest przeszukać kod programu i sprawdzić użycie wszystkiego, co zmienisz podczas konserwacji programu, nawet wartości właściwości. Ten program łamie tę zasadę częściowo, aby to podkreślić, a częściowo dlatego, że jest to stosunkowo prosty fragment kodu, w którym łatwiej jest zobaczyć, co jest robione i uniknąć później problemów.

Wybór gracza w polu gry jest przetwarzany przez wywołanie podprogramu GamePlay z argumentem Index.

Przetwarzanie ruchu

Najpierw sprawdzasz, czy kliknięto wolny kwadrat.

Jeśli lblPlayGround(xo_Move).Caption = '' Wtedy

Gdy jesteśmy pewni, że jest to prawidłowy ruch, licznik ruchów (iMove) jest zwiększany. Kolejne dwa wiersze są bardzo interesujące, ponieważ tłumaczą współrzędne z jednowymiarowej tablicy komponentów If lblPlayGround na dwuwymiarowe indeksy, których można używać w iXPos lub iOPos. Mod i dzielenie liczb całkowitych ('backslash') to operacje matematyczne, których nie używasz na co dzień, ale oto świetny przykład pokazujący, jak mogą być bardzo przydatne.

Jeśli lblPlayGround(xo_Move).Caption = '' Wtedy
iMove = iMove + 1
x = Int(xo_Przesuń / 3) + 1
y = (xo_Move Mod 3) + 1

Wartość xo_Move 0 zostanie przetłumaczona na (1, 1), 1 na (1, 2) ... 3 na (2, 1) ... 8 na (3, 3).

Wartość w sPlaySign, zmiennej o zakresie modułu, śledzi, który gracz wykonał ruch. Gdy tablice ruchu zostaną zaktualizowane, komponenty etykiet w siatce odtwarzania można zaktualizować za pomocą odpowiedniego znaku.

Jeśli sPlaySign = „O” Wtedy
iOPos(x, y) = 1
iWin = CheckWin(iOPos())
W przeciwnym razie
iXPos(x, y) = 1
Wygrana = Sprawdź Wygrana (iXPos())
Zakończ, jeśli
lblPlayGround(xo_Move).Caption = sPlaySign

Na przykład, gdy gracz X kliknie lewy górny róg siatki, zmienne będą miały następujące wartości:

Ekran użytkownika pokazuje tylko X w lewym górnym polu, podczas gdy iXPos ma 1 w lewym górnym polu i 0 we wszystkich pozostałych. iOPos ma 0 w każdym pudełku.

Wartości zmieniają się, gdy gracz O kliknie środkowy kwadrat siatki. Teraz iOPos pokazuje 1 w środkowym polu, podczas gdy ekran użytkownika pokazuje X w lewym górnym rogu i O w środkowym polu. iXPos pokazuje tylko 1 w lewym górnym rogu, z 0 we wszystkich innych polach.

Teraz, gdy wiesz, gdzie kliknął gracz i który z nich kliknął (używając wartości w sPlaySign), wszystko, co musisz zrobić, to dowiedzieć się, czy ktoś wygrał grę i dowiedzieć się, jak pokazać to na wyświetlaczu.

Znalezienie zwycięzcy

Po każdym ruchu funkcja CheckWin sprawdza zwycięską kombinację. CheckWin działa, dodając w dół każdy wiersz, w każdej kolumnie i na każdej przekątnej. Śledzenie kroków przez CheckWin przy użyciu funkcji debugowania języka Visual Basic może być bardzo pouczające. Znalezienie wygranej jest kwestią najpierw, sprawdzenie, czy trzy jedynki zostały znalezione w każdym z poszczególnych sprawdzeń w zmiennej iScore, a następnie zwrócenie unikalnej wartości „sygnatury” w Checkwin, która jest używana jako indeks tablicy do zmiany właściwości Visible jeden element w tablicy komponentów linWin. Jeśli nie ma zwycięzcy, CheckWin będzie zawierał wartość -1. Jeśli jest zwycięzca, wyświetlacz jest aktualizowany, tablica wyników jest zmieniana, wyświetlana jest wiadomość z gratulacjami i gra jest ponownie uruchamiana.

Przyjrzyjmy się szczegółowo jednej z kontroli, aby zobaczyć, jak to działa. Pozostałe są podobne.

„Sprawdź wiersze dla 3”
Dla i = 1 do 3
iScore = 0
CheckWin = CheckWin + 1
Dla j = 1 do 3
iScore = iScore + iPos(i, j)
Następny j
Jeśli iScore = 3 Wtedy
Wyjdź z funkcji
Zakończ, jeśli
Dalej ja

Pierwszą rzeczą, na którą należy zwrócić uwagę, jest to, że pierwszy licznik indeksu i odlicza wiersze, podczas gdy drugi licznik j liczy kolumny. Zewnętrzna pętla po prostu przechodzi z jednego rzędu do następnego. Wewnętrzna pętla zlicza jedynki w bieżącym rzędzie. Jeśli są trzy, masz zwycięzcę.

Zauważ, że śledzisz również całkowitą liczbę testowanych kwadratów w zmiennej CheckWin, która jest wartością przekazywaną z powrotem po zakończeniu tej funkcji. Każda zwycięska kombinacja będzie miała unikalną wartość w CheckWin od 0 do 7, która służy do wybrania jednego z elementów w tablicy komponentów linWin(). To sprawia, że ​​kolejność kodu w funkcji CheckWin jest również ważna! Jeśli przesunąłeś jeden z bloków kod pętli (jak ta powyżej), gdy ktoś wygra, na siatce gry zostanie narysowana niewłaściwa linia. Wypróbuj i przekonaj się!

Szczegóły wykończenia

Jedyny kod, który nie został jeszcze omówiony, to podprogram nowej gry i podprogram, który zresetuje wynik. Reszta logiki w systemie sprawia, że ​​tworzenie ich jest dość łatwe. Aby rozpocząć nową grę, wystarczy wywołać podprogram InitPlayGround. Jako udogodnienie dla graczy, ponieważ przycisk można kliknąć w środku gry, prosisz o potwierdzenie przed kontynuowaniem. Prosisz również o potwierdzenie przed ponownym uruchomieniem tablicy wyników.