Programarea unui joc Tic Tac Toe

Programarea jocurilor pe computer poate fi cea mai dificilă (și, eventual, cea mai plătită) slujbă pe care o poate avea un programator. Jocurile de nivel superior necesită cel mai bun atât din partea programatorilor, cât și a calculatoarelor.

Visual Basic 6 a fost acum ocolit complet ca o platformă pentru programarea jocurilor. (Niciodată nu a fost una. Chiar în zilele „bune”, programatorii de jocuri serioase nu ar folosi niciodată un limbaj la nivel înalt, precum VB 6, deoarece pur și simplu nu puteți obține performanțele de ultimă oră pe care le necesită majoritatea jocurilor.) Dar Jocul simplu "Tic Tac Toe" este o introducere excelentă în programare, care este ceva mai avansat decât "Hello World!"

Aceasta este o introducere excelentă în multe dintre conceptele fundamentale ale programării, deoarece combină tehnici, inclusiv:

  • Utilizarea tablelor. Marcajele X și O sunt păstrate în tablouri separate și întreaga matrice este trecută între funcții pentru a urmări progresul jocului..
  • Utilizarea graficelor la nivel VB 6: VB 6 nu oferă o capacitate grafică excelentă, dar jocul este o bună introducere în ceea ce este disponibil. O mare parte din restul acestei serii este o explorare a modului în care GDI +, următoarea generație de grafică Microsoft, înlocuiește graficele la nivel VB 6.
  • Utilizarea calculelor matematice pentru controlul programului: Programul folosește calcule inteligente modulo (Mod) și diviziune întreagă folosind tablourile de marcare cu două jocuri pentru a determina când a avut loc un „câștig” cu trei elemente.

Clasa de programare din acest articol este poate doar puțin trecută de nivelul de început, dar ar trebui să fie bună pentru programatorii „intermediari”. Dar haideți să începem la un nivel elementar pentru a ilustra unele dintre concepte și pentru a vă începe cu cariera de programare a jocurilor Visual Basic. Chiar și studenții mai avansați pot constata că este ușor dificil să obții obiectele sub formă corectă.

Cum se joacă Tic Tac Toe

Dacă nu ai jucat niciodată Tic Tac Toe, iată regulile. Doi jucători alternează la plasarea Xs și Os pe terenul de joc 3 x 3.

Înainte de începerea jocului, ambii jucători trebuie să fie de acord cu cine va merge mai întâi și cine va marca mișcările sale cu ce simbol. După prima mișcare, jucătorii își plasează alternativ semnele în orice celulă goală. Scopul jocului este de a fi primul jucător cu trei mărci pe o linie orizontală, diagonală sau verticală. Dacă nu există celule goale și niciun jucător nu are o combinație câștigătoare, jocul este o remiză.

Pornirea programului

Înainte de a începe orice codare reală, este întotdeauna o idee bună să schimbați numele componentelor pe care le utilizați. Odată ce începeți codarea, numele va fi folosit automat de Visual Basic, astfel încât să doriți să fie numele potrivit. Vom folosi numele formularului frmTicTacToe și, de asemenea, vom schimba subtitrarea la „Despre Tic Tac Toe”.

Cu forma stabilită, utilizați controlul cutiei de instrumente pentru a trasa o grilă de 3 x 3. Faceți clic pe instrumentul de linie, apoi desenați o linie unde doriți. Va trebui să creezi patru linii în acest fel și să ajustezi lungimea și poziția lor pentru a le face să pară corect. Visual Basic are, de asemenea, câteva instrumente convenabile în meniul Format care vă vor ajuta. Aceasta este o mare șansă de a exersa cu ei.

Pe lângă grila de redare, vom avea nevoie de câteva obiecte pentru simbolurile X și O care vor fi plasate pe grilă. Deoarece există nouă spații în grilă, vom crea un tablou de obiecte cu nouă spații, numite elemente în Visual Basic.

Există mai multe modalități de a face aproape orice în mediul de dezvoltare Visual Basic, iar crearea tablourilor de control nu face excepție. Probabil cel mai simplu este să creezi prima etichetă (faceți clic și desenați la fel ca instrumentul de linie), numiți-o, setați toate atributele (cum ar fi Font și ForeColor), apoi faceți copii ale acesteia. VB 6 vă va întreba dacă doriți să creați un tablou de control. Utilizați numele lblPlayGround pentru prima etichetă.

Pentru a crea celelalte opt elemente ale grilei, selectați primul obiect de etichetă, setați proprietatea Index la zero și apăsați CTRL + C (copiere). Acum puteți apăsa CTRL + V (lipire) pentru a crea un alt obiect de etichetă. Când copiați astfel de obiecte, fiecare copie va moșteni toate proprietățile, cu excepția Indexului de la prima. Indicele va crește cu unu pentru fiecare copie. Acesta este un tablou de control, deoarece toate au același nume, dar valori diferite ale indexului.

Dacă creați tabloul în acest fel, toate copiile vor fi stivuite una peste alta, în colțul din stânga sus al formularului. Trageți fiecare etichetă într-una dintre pozițiile grilei de redare. Asigurați-vă că valorile indexului sunt secvențiale în grilă. Logica programului depinde de acesta. Obiectul etichetei cu valoarea indexului 0 ar trebui să fie în colțul din stânga sus, iar eticheta din dreapta jos ar trebui să aibă index 8. Dacă etichetele acoperă grila de redare, selectați fiecare etichetă, faceți clic dreapta și selectați Trimite înapoi.

Deoarece există opt moduri posibile de a câștiga jocul, vom avea nevoie de opt linii diferite pentru a arăta câștigul pe grila de joc. Veți folosi aceeași tehnică pentru a crea un alt tablou de control. Mai întâi, desenați linia, denumiți-o linWin și setați proprietatea Index la zero. Apoi folosiți tehnica copy-paste pentru a produce încă șapte linii. Următoarea ilustrație arată cum să setați corect numerele de index.

Pe lângă obiectele de etichetă și linie, aveți nevoie de câteva butoane de comandă pentru a juca jocul și mai multe etichete pentru a păstra scorul. Pașii pentru crearea acestora nu sunt detaliate aici, dar acestea sunt obiectele de care aveți nevoie.

Două obiecte de buton:

  • cmdNewGame
  • cmdResetScore

Obiect cadru fraPlayFirst care conține două butoane de opțiune:

  • optXPlayer
  • optOPlayer

Obiect cadru fraScoreBoard care conține șase etichete. Numai lblXScore și lblOScore sunt modificate în codul programului.

  • lblX
  • lblXScore
  • lblO
  • lblOScore
  • lblMinus
  • lblColon

În sfârșit, aveți nevoie și de obiectul etichetă lblStartMsg pentru a „masca” butonul cmdNewGame atunci când nu ar trebui să fie dat clic. Acest lucru nu este vizibil în ilustrația de mai jos, deoarece ocupă același spațiu sub forma butonului de comandă. Este posibil să fie necesar să mutați temporar butonul de comandă pentru a desena această etichetă pe formular.

Până în prezent, nu a fost efectuată o codare VB, dar suntem în sfârșit gata să facem asta.

Inițializarea

Acum trebuie să începeți în sfârșit codificarea programului. Dacă nu ați făcut-o deja, poate doriți să descărcați codul sursă pe care să-l urmați pe parcursul explicării funcționării programului.

Una dintre primele decizii de proiectare care trebuie luate este modul de a urmări „starea” actuală a jocului. Cu alte cuvinte, care sunt actualele X și Os pe grila de joc și cine se mișcă în continuare. Conceptul de „stat” este esențial în multe programe și, în special, este important în programarea ASP și ASP.NET pentru web

Există mai multe moduri în care acest lucru ar putea fi realizat, deci este un pas critic în analiză. Dacă rezolvați singur această problemă, poate doriți să desenați o diagramă de flux și să încercați diferite opțiuni cu „hârtie zgârietură” înainte de a începe orice codare.

variabile

Soluția noastră folosește două "tablouri bidimensionale", deoarece aceasta ajută la urmărirea „stării” prin simpla schimbare a indexurilor de matrice în buclele de programe. Starea colțului din stânga sus va fi în elementul tabloului cu index (1, 1), colțul din dreapta sus va fi în (1, 3), în dreapta jos în (3,3), etc. . Cele două tablouri care fac acest lucru sunt:

iXPos (x, y)

și

iOPos (x, y)

Există o mulțime de moduri diferite de a face acest lucru, iar soluția VB.NET finală din această serie vă arată cum să o faceți doar cu un singur tablou unidimensional.

Programarea pentru a traduce aceste tablouri în decizii de câștig de jucător și afișajele vizibile în formular se află pe pagina următoare.

De asemenea, aveți nevoie de câteva variabile globale după cum urmează. Rețineți că acestea sunt incluse în codul general și declarații pentru formular. Acest lucru le face variabile „la nivel de modul” la care se poate face referire oriunde în cod pentru acest formular. Pentru mai multe detalii, verificați Înțelegerea domeniului de aplicare a variabilelor din Ajutor Visual Basic.

Există două domenii în care variabilele sunt inițializate în programul nostru. În primul rând, câteva variabile sunt inițializate în timp ce se încarcă formularul frmTicTacToe.

Sub Formular privat_Load ()

În al doilea rând, înainte de fiecare joc nou, toate variabilele care trebuie resetate la valorile de pornire sunt atribuite într-o subrutină de inițializare.

Sub InitPlayGround ()

Rețineți că inițializarea încărcării formularului apelează și la inițializarea locului de joacă.

Una dintre abilitățile critice ale unui programator este capacitatea de a utiliza facilitățile de depanare pentru a înțelege ce face codul. Puteți utiliza acest program pentru a încerca:

  • Pasul cu codul cu tasta F8
  • Setarea unui ceas pe variabile cheie, cum ar fi sPlaySign sau iMove
    Setarea unui punct de întrerupere și interogarea valorii variabilelor. De exemplu, în bucla interioară a inițializării:
lblPlayGround ((i - 1) * 3 + j - 1) .Caption = ""

Rețineți că acest program arată clar de ce este o practică bună de programare să păstrați datele în matrice ori de câte ori este posibil. Dacă nu aveți tablouri în acest program, ar trebui să scrieți coduri de genul:

Line0.Visible = False
Line1.Visible = False
Line2.Visible = False
Linia3.Vizibilă = Falsă
Line4.Visible = False
Linie5.Vizibil = False
Linia6.Vizibilă = Falsă
Line7.Visible = False

in loc de asta:

Pentru i = 0 până la 7
linWin (i) .Vizibil = False
Apoi eu

Efectuarea unei mișcări

Dacă orice parte a sistemului poate fi considerată „inima”, este subroutine lblPlayGround_Click. Această subrutină este numită de fiecare dată când un jucător face clic pe grila de redare. (Clicurile trebuie să se afle în unul dintre cele nouă elemente lblPlayGround.) Observați că această subrutină are un argument: (Index As Integer). Majoritatea celorlalte „subrutine eveniment”, cum ar fi cmdNewGame_Click () nu. Index indică pe ce obiect de etichetă a fost făcut clic. De exemplu, indexul ar conține valoarea zero pentru colțul din stânga sus al grilei și valoarea opt pentru colțul din dreapta jos.

După ce un jucător face clic pe un pătrat din grila de joc, butonul de comandă pentru a începe un alt joc, cmdNewGame, este "pornit", făcându-l vizibil. Starea acestui buton de comandă face dublă datorie, deoarece este folosită și ca variabilă de decizie booleană mai târziu. În program. Utilizarea unei valori de proprietate ca variabilă de decizie este de obicei descurajată, deoarece, dacă devine vreodată necesar să schimbați programul (să spunem, de exemplu, pentru a face butonul de comandă cmdNewGame vizibil tot timpul), atunci programul va eșua neașteptat deoarece s-ar putea să nu vă amintiți că este folosit și ca parte a logicii programului. Din acest motiv, este întotdeauna o idee bună să căutați prin codul programului și să verificați utilizarea oricărui lucru pe care îl schimbați atunci când efectuați întreținerea programului, chiar și valorile proprietății. regulați parțial să faceți acest punct și parțial pentru că acesta este o bucată de cod relativ simplă în care este mai ușor să vedeți ce se face și să evitați problemele ulterior.

O selecție de jucător a unui pătrat de joc este procesată apelând subrutinul GamePlay cu Index ca argument.

Procesarea mișcării

În primul rând, verificați dacă s-a dat clic pe un pătrat neocupat.

Dacă lblPlayGround (xo_Move) .Caption = "" Atunci

După ce suntem siguri că aceasta este o mutare legitimă, contorul de mișcare (iMove) este incrementat. Următoarele două linii sunt foarte interesante, deoarece traduc coordonatele din tabloul de componente unidimensionale If lblPlayGround în indexuri bidimensionale pe care le puteți folosi fie în iXPos, fie în iOPos. Diviziunea Mod și întreaga („reversarea”) sunt operații matematice pe care nu le utilizați în fiecare zi, dar iată un exemplu excelent care arată cum pot fi foarte utile.

 Dacă lblPlayGround (xo_Move) .Caption = "" Atunci
iMove = iMove + 1
x = Int (xo_Move / 3) + 1
y = (xo_Move Mod 3) + 1

Valoarea xo_Move 0 va fi tradusă în (1, 1), 1 la (1, 2) ... 3 la (2, 1) ... 8 până la (3, 3).

Valoarea din sPlaySign, o variabilă cu obiectivul modulului, urmărește ce jucător a făcut mișcarea. Odată ce tablourile de mutare sunt actualizate, componentele etichetelor din grila de redare pot fi actualizate cu semnul corespunzător.

Dacă sPlaySign = "O" Atunci
iOPos (x, y) = 1
iWin = CheckWin (iOPos ())
altfel
iXPos (x, y) = 1
iWin = CheckWin (iXPos ())
End If
lblPlayGround (xo_Move) .Caption = sPlaySign

De exemplu, când playerul X face clic pe colțul din stânga sus al grilei, variabilele vor avea următoarele valori:

Ecranul utilizatorului arată doar un X în caseta din stânga sus, în timp ce iXPos are un 1 în caseta din stânga sus și 0 în toate celelalte. IOPos are 0 în fiecare cutie.

Valorile se schimbă atunci când jucătorul O face clic pe pătratul central al grilei. Acum iOPos arată un 1 în caseta centrală, în timp ce ecranul utilizatorului arată un X în stânga sus și un O în caseta centrală. IXPos arată doar 1 în colțul din stânga sus, cu 0 în toate celelalte casete.

Acum că știți unde a făcut clic un jucător și ce jucător a făcut clicul (folosind valoarea din sPlaySign), tot ce trebuie să faceți este să aflați dacă cineva a câștigat un joc și să vă dați seama cum să arătați asta pe ecran.

Găsirea unui câștigător

După fiecare mișcare, funcția CheckWin verifică combinația câștigătoare. CheckWin funcționează adăugând în jos fiecare rând, pe fiecare coloană și prin fiecare diagonală. Urmărirea pașilor prin CheckWin folosind funcția Debug de Visual Basic poate fi foarte educativă. Găsirea unui câștig este mai întâi o problemă, verificând dacă s-au găsit trei 1 în fiecare dintre verificările individuale din variabila iScore, apoi se returnează o valoare "semnătură" unică în Checkwin care este utilizată ca indice de matrice pentru a modifica proprietatea vizibilă a un element din tabloul de componente linWin. Dacă nu există un câștigător, CheckWin va conține valoarea -1. Dacă există un câștigător, afișajul este actualizat, tabelul de schimb este schimbat, este afișat un mesaj de felicitare și jocul este reluat.

Haideți să parcurgem în detaliu una dintre verificări pentru a vedea cum funcționează. Celelalte sunt similare.

'Verificați rândurile pentru 3
Pentru i = 1 până la 3
iScore = 0
CheckWin = CheckWin + 1
Pentru j = 1 până la 3
iScore = iScore + iPos (i, j)
Următorul j
Dacă iScore = 3 Atunci
Funcție de ieșire
End If
Apoi eu

Primul lucru de remarcat este că primul contor de indexuri contează pe rânduri, în timp ce al doilea j contează peste coloane. Bucla exterioară, apoi trece pur și simplu de la un rând la altul. Bucla internă contează 1-urile din rândul curent. Dacă sunt trei, atunci ai un câștigător.

Rețineți că, de asemenea, țineți cont de numărul total de pătrate testate în variabila CheckWin, care este valoarea transmisă înapoi atunci când această funcție se încheie. Fiecare combinație câștigătoare va ajunge cu o valoare unică în CheckWin de la 0 la 7, care este utilizată pentru a selecta unul dintre elementele din tabloul de componente linWin (). Acest lucru face ca ordinea codului în funcția CheckWin să fie importantă și! Dacă ați mutat unul dintre blocurile de cod buclă (precum cel de mai sus), atunci când cineva câștigă, s-ar trasa linia greșită. Încercați și vedeți!

Detalii de finisare

Singurul cod care nu a fost încă discutat este subrutinul pentru un nou joc și subrutina care va reseta scorul. Restul logicii din sistem facilitează crearea acestora. Pentru a începe un joc nou, nu trebuie decât să apelați subprogramul InitPlayGround. Ca o comoditate pentru jucători, deoarece butonul poate fi făcut clic pe mijlocul unui joc, cereți confirmare înainte de a merge mai departe. De asemenea, solicitați confirmare înainte de a reporni tabloul de bord.