Cum să faci un joc de X si 0

  

    Crezi că e greu să faci un joc de X și 0? După ce am făcut împreună jocul de labirint, cel mai probabil lucrurile deja nu ți se mai par de domeniul science-fiction. Totuși, poate că încă e prea devreme să îți iei singur zborul pe acest tărâm încă destul de încețoșat, așa că hai să dăm împreună ceață la o parte și să vedem cât de simplu e să programezi un joc de X și 0.
    Dacă ai citit articolul trecut, atunci știi că pentru a face un joc îți trebuiesc doar doi pași și trei mișcări. Ai văzut că abordarea asta funcționează foarte bine pentru jocul de labirint. Vei vedea în articolul acesta că ea funcționează la fel de bine și pentru X și 0.
    Bun, hai să ne apucăm de treabă!
 
Proiectarea jocului de X și 0
    Care e pasul 1? Proiectarea jocului. Adică acea parte în care practic realizezi jocul fără să ai nevoie de programare. Este pasul în care faci jocul pe hârtie.
    Și cum acesta este pasul esențial, l-am împărțit la rândul lui în 3 mișcări: (1) interfață, (2) variabilele și (3) schița.
  (1) Interfață jocului
    Asta e partea aceea foarte frumoasă în care te joci cu creionul pe hârtie și îți transformi gândurile în imagini. Având în vedere limitările destul de serioase ale ecranului de care dispunem (și anume doar 10×10 puncte ce pot avea doar 8 culori distincte, inclusiv alb), interfața proiectată de mine arăta ca cea din prima imagine din acest articol.
    Am ales că bordură pătratelor să fie desenată cu gri, X-ul cu albastru și 0-ul cu verde. Și ce-i cu punctul roșu? El indică poziția cursorului pe tablă.
    Cu ajutorul tastelor ADS, și W (stânga, dreapta, jos și sus) voi putea deplasa cursorul pe oricare din cele 9 poziții de pe tablă. Iar cu tasta P voi putea plasa o piesă (de culoarea jucătorului curent) pe tablă la poziția curentă a cursorului. (Bineînțeles, după ce voi verifică în prealabil că respectivă poziție de pe tablă să nu fie deja ocupată de o piesă.)
    După oricare plasare de piesă pe tablă voi verifică dacă respectivul jucător a făcut trei piese în linie (caz în care a câștigat jocul), sau dacă nu se mai poate face nicio mutare (caz în care jocul s-a încheiat cu remiză).
    În momentul încheierii jocului, cursorul nu va mai apărea pe ecran și programul va înceta să mai răspundă la apăsarea tastelor, iar liniile tablei se vor colora cu negru în cazul remizei, cu albastru în cazul victoriei lui X, sau cu verde în cazul victoriei lui 0.


  (2) Variabilele jocului
    Super. Am stabilit clar cum vreau să arate și ce vreau să facă jocul. Acum trebuie să văd ce obiecte și ce acțiuni pot identifica în descrierea jocului făcută până aici.
    Mai întâi obiectele. Dacă sparg jocul (având în minte interfața prezentată în secțiunea anterioară) în bucățele, atunci obțin următoarele obiecte:
        – tabla de joc (goală) <— liniile ce delimitează pătrățele de pe tablă.
        – piesele de pe tablă <— 3×3 piese, fiecare dintre ele putând avea una dintre valorile: gol, X, sau 0.
        – cursorul <— coordonatele lui pe ecran.
        – jucătorul curent <— X, sau 0.
        – starea jocului <— în desfășurare, terminat egalitate, terminat victorie X, sau terminat victorie 0.
    Iar ca acțiuni pe care jocul trebuie să le îndeplinească, ar fi următoarele:
        – pornește jocul <— la initializare.
        – mută cursoul <— cu tastele A, D, S, W.
        – pune piesa <— cu tasta P.
    Știind obiectele din joc, e ușor acuma să văd ce variabile mi-ar trebui pentru a putea obține un model abstract al jocului. Adică pentru a putea obține o memorare a elementelor esențiale ale jocului, fără a păstra toate detaliile legate de interfață.
    Îmi va trebui, deci, o variabilă piesă în care să memorez piesele de pe tablă. Și cum am 3×3 piese, cel mai indicat e să folosesc o matrice.
    Pentru a memora jucătorul care este la mutare îmi trebuie o variabilă juc_crt.
    Pentru a memora poziția curentă a cursorului pe tablă de joc pot folosi două variabile, cx și cy.
    Iar pentru a memora starea curentă a jocului pot folosi o altă variabilă, stare_joc.
    Acestea sunt, așadar, variabilele necesare pentru a memora întreagă stare a jocului la un moment dat. Pentru a putea face programul, însă, e posibil să mai am nevoie și de alte variabile în afară de acestea, dar asta voi vedea pe parcurs. În caz că va apărea necesitatea unei alte variabile, voi reveni și o voi adaugă aici.
    Acțiunile jocului, pe de altă parte, îmi vor fi necesare în secțiunea următoare.


  (3) Schița programului
    Ținând cont de cunoștințele de programare deprinse până aici, precum și de acțiunile jocului identificate în secțiunea anterioară, programul va avea următoarea structura:
        – definire variabile (globale)
        – definire funcții
        – programul propriu-zis.
    La partea de definire funcții aș pune în primul rând două funcții: una care să deseneze interfața grafică a jocului pe ecran (și pe care o pot denumi DeseneazaEcranJoc), și una în care să specific reacțiile jocului la apăsarea tastelor (și pe care o pot denumi FunctieTaste).
    Iar în partea de program propriu-zis va trebui să am o parte de initializare a variabilelor (în care să le dau acestora valori adecvate pornirii jocului), urmată de apelul DeseneazaEcranJoc(), și apoi de apelul AscultaTaste(FunctieTaste).
    Mai rămâne acuma să detaliez (tot la nivelul de schița, bineînțeles) cele două funcții de care am pomenit.
    Funcția DeseneazaEcranJoc. Aici voi avea grijă să desenez întreagă interfață a jocului, țînând cont de starea curentă a jocului, așa cum e ea memorată în variabilele piesă, juc_crt, cx, cy și stare_joc. Funcția asta va cuprinde:
        – desenarea liniilor tablei.
        – desenarea pieselor pe tablă.
        – desenarea cursorului.
    Și funcția FunctieTaste. Ea va trebui să cuprindă următoarele:
        – deplasarea cursorului la apăsarea tastelor A, D, S, W.
        – plasarea unei piese pe tablă la apăsarea tastei P.
        – redesenarea interfeței jocului.
        – încetarea ascultării tastelor în cazul încheierii jocului (prin remiză sau victorie X sau victorie 0).
 
    Programarea jocului de X și 0
    Deja ajuns în acest punct am un plan suficient de bun încât să pot trece fără teamă la pasul al doilea, și anume programarea propriu-zisă. Bineînțeles că fiecare dintre punctele menționate mai pot fi detaliate. (Ba chiar este indicat s-o faci, la început. Nu are sens să te arunci direct în scrierea de cod sursă, căci nu acolo vei găsi programarea adevărată. Programarea adevărată nu se produce sub degetele tale atunci când scrii cod sursă de programe, ci se produce în creierul tău, atunci când proiectezi și rulezi în minte secvențe de programe.)
    Eu nu voi detalia aici pașii menționați, ci te voi lasă să descoperi singur ce soluții am ales pentru implementarea lor.
    O singură remarcă mai fac: Vei observa, desigur, că pe lângă variabilele menționate de mine am folosit în program și variabilă nr_mutare. Nu era absolut necesară (căci numărul mutării curente îl puteam obține parcurgând matricea piesă și numărând câte elemente egale cu valorile asociate pentru X sau pentru 0 găsesc acolo). Însă prin folosirea ei am simplificat mult verificarea situației în care jocul se încheie prin remiză (așa cum vei putea vedea spre finalul funcției FunctieTaste). În mod similar, vei observa că pentru a simplifica funcțiile DeseneazaEcranJoc și FunctieTaste am mai definit alte funcții. Cu ajutorul acestor noi funcții definite am crescut mult claritatea celor două funcții mari din program. (Îți reamintesc faptul că o funcție trebuie definită mai înainte de locul din program în care o apelezi (pentru prima oară), la fel cum o variabilă trebuie declarată mai înainte de locul din program în care o folosești pentru prima oară.) Vei putea remarcă, de asemenea, că în cazul unora dintre funcții am avut nevoie temporar de niște variabile pe care le-am definit acolo, că variabile locale acelor funcții.
 
Ia uite si codul sursa complet al programului:
// Joc de X si 0 (Tic Tac Toe Game)
// —> Definesc variabilele jocului:
var piesa; // {0: gol, 1: X, 2: 0}
var juc_crt; // {1: X, 2: 0}
var cx; // {1, 2, 3, …, 10}
var cy; // {1, 2, 3, …, 10}
var stare_joc; // {1: in desfasurare, 2: terminat egal, 3: terminat victorie X, 4: terminat victorie 0}
var nr_mutare; // {1, 2, 3, …, 10}
// —> Definesc functiile necesare:
function AprindeNrCul(x, y, nc)
{
  if (nc == 0)
    Aprinde(x, y, ALB);
  else if (nc == 1)
    Aprinde(x, y, NEGRU);
  else if (nc == 2)
    Aprinde(x, y, ROSU);
  else if (nc == 3)
    Aprinde(x, y, VERDE);
  else if (nc == 4)
    Aprinde(x, y, ALBASTRU);
  else if (nc == 5)
    Aprinde(x, y, GRI);
  else if (nc == 6)
    Aprinde(x, y, GALBEN);
  else if (nc == 7)
    Aprinde(x, y, TURCOAZ);
}
function DeseneazaEcranJoc()
{
  // Deseneaza tabla
  var nr_culoare = 0;
  if (stare_joc == 1)
    nr_culoare = 5;
  else if (stare_joc == 2)
    nr_culoare = 1;
  else if (stare_joc == 3)
    nr_culoare = 4;
  else if (stare_joc == 4)
    nr_culoare = 3;
  var i;
  i = 1;
  while (i<=10)
  {
    // liniile orizontale
    AprindeNrCul(i, 1, nr_culoare);
    AprindeNrCul(i, 4, nr_culoare);
    AprindeNrCul(i, 7, nr_culoare);
    AprindeNrCul(i, 10, nr_culoare);
    // liniile verticale
    AprindeNrCul(1, i, nr_culoare);
    AprindeNrCul(4, i, nr_culoare);
    AprindeNrCul(7, i, nr_culoare);
    AprindeNrCul(10, i, nr_culoare);
    i = i+1;
  }
  // Deseneaza piesele
  var l;
  var c;
  l = 0;
  while (l < 3)
  {
    c = 0;
    while (c < 3)
    {
      nr_culoare = 0;
      if (piesa[l][c] == 0)
        nr_culoare = 0;
      else if (piesa[l][c] == 1)
        nr_culoare = 4;
      else if (piesa[l][c] == 2)
        nr_culoare = 3;
      AprindeNrCul(2+c*3, 9-l*3, nr_culoare);
      AprindeNrCul(2+c*3+1, 9-l*3, nr_culoare);
      AprindeNrCul(2+c*3, 9-l*3-1, nr_culoare);
      AprindeNrCul(2+c*3+1, 9-l*3-1, nr_culoare);
      c = c+1;
    }
    l = l+1;
  }
  // Deseneaza cursorul
  if (stare_joc == 1)
  {
    Aprinde(cx, cy, ROSU);
  }
}
function CalcDiv(A, B)
{
  var rest = A % B;
  var cat = (A-rest)/B;
  return cat;
}
function PunePiesa()
{
  var c = CalcDiv(cx-2, 3);
  var l = CalcDiv(9-cy, 3);
  if (piesa[l][c] == 0)
  {
    piesa[l][c] = juc_crt;
    return 1;
  }
  else
  {
    return 0;
  }
}
function VerificaVictorie()
{
  if ( ( (piesa[0][0]==1)&&(piesa[0][1]==1)&&(piesa[0][2]==1) ) ||
        ( (piesa[1][0]==1)&&(piesa[1][1]==1)&&(piesa[1][2]==1) ) ||
        ( (piesa[2][0]==1)&&(piesa[2][1]==1)&&(piesa[2][2]==1) ) ||
        ( (piesa[0][0]==1)&&(piesa[1][0]==1)&&(piesa[2][0]==1) ) ||
        ( (piesa[0][1]==1)&&(piesa[1][1]==1)&&(piesa[2][1]==1) ) ||
        ( (piesa[0][2]==1)&&(piesa[1][2]==1)&&(piesa[2][2]==1) ) ||
        ( (piesa[0][0]==1)&&(piesa[1][1]==1)&&(piesa[2][2]==1) ) ||
        ( (piesa[2][0]==1)&&(piesa[1][1]==1)&&(piesa[0][2]==1) ) )
  {
    stare_joc = 3;
  }
  if ( ( (piesa[0][0]==2)&&(piesa[0][1]==2)&&(piesa[0][2]==2) ) ||
        ( (piesa[1][0]==2)&&(piesa[1][1]==2)&&(piesa[1][2]==2) ) ||
        ( (piesa[2][0]==2)&&(piesa[2][1]==2)&&(piesa[2][2]==2) ) ||
        ( (piesa[0][0]==2)&&(piesa[1][0]==2)&&(piesa[2][0]==2) ) ||
        ( (piesa[0][1]==2)&&(piesa[1][1]==2)&&(piesa[2][1]==2) ) ||
        ( (piesa[0][2]==2)&&(piesa[1][2]==2)&&(piesa[2][2]==2) ) ||
        ( (piesa[0][0]==2)&&(piesa[1][1]==2)&&(piesa[2][2]==2) ) ||
        ( (piesa[2][0]==2)&&(piesa[1][1]==2)&&(piesa[0][2]==2) ) )
  {
    stare_joc = 4;
  }
}
function FunctieTaste(ev)
{
  var tasta = TastaApasata(ev);
  // mutare cursor
  if ( (tasta == 'a') && (cx >= 5) )
    cx = cx-3;
  if ( (tasta == 'd') && (cx <= 5) )
    cx = cx+3;
  if ( (tasta == 's') && (cy >= 6) )
    cy = cy-3;
  if ( (tasta == 'w') && (cy <= 6) )
    cy = cy+3;
  // plasare piesa
  if (tasta == 'p')
  {
    var rez = PunePiesa();
    // efectueaza mutare
    if (rez == 1)
    {
      juc_crt = 3-juc_crt;
      nr_mutare = nr_mutare+1;
      VerificaVictorie();
      // daca n-a fost victorie, verifica remiza
      if ( (stare_joc < 3) && (nr_mutare == 10) )
      {
        stare_joc = 2;
      }
    }
  }
  // reimprospatare ecran
  DeseneazaEcranJoc();
  if (stare_joc != 1)
  {
    AscultaTaste();
  }
}
// —> Programul propriu-zis:
// Initializez variabilele
piesa = Matrice(3, 3);
piesa[0][0] = 0; piesa[0][1] = 0; piesa[0][2] = 0;
piesa[1][0] = 0; piesa[1][1] = 0; piesa[1][2] = 0;
piesa[2][0] = 0; piesa[2][1] = 0; piesa[2][2] = 0;
juc_crt = 1;
cx = 2; cy = 9;
stare_joc = 1;
nr_mutare = 1;
// Desenez ecranul initial
DeseneazaEcranJoc();
// Asculta apasarea tastelor
AscultaTaste(FunctieTaste);// Joc de X si 0 (Tic Tac Toe Game)
// —> Definesc variabilele jocului:
var piesa; // {0: gol, 1: X, 2: 0}
var juc_crt; // {1: X, 2: 0}
var cx; // {1, 2, 3, …, 10}
var cy; // {1, 2, 3, …, 10}
var stare_joc; // {1: in desfasurare, 2: terminat egal, 3: terminat victorie X, 4: terminat victorie 0}
var nr_mutare; // {1, 2, 3, …, 10}
// —> Definesc functiile necesare:
function AprindeNrCul(x, y, nc)
{
  if (nc == 0)
    Aprinde(x, y, ALB);
  else if (nc == 1)
    Aprinde(x, y, NEGRU);
  else if (nc == 2)
    Aprinde(x, y, ROSU);
  else if (nc == 3)
    Aprinde(x, y, VERDE);
  else if (nc == 4)
    Aprinde(x, y, ALBASTRU);
  else if (nc == 5)
    Aprinde(x, y, GRI);
  else if (nc == 6)
    Aprinde(x, y, GALBEN);
  else if (nc == 7)
    Aprinde(x, y, TURCOAZ);
}
function DeseneazaEcranJoc()
{
  // Deseneaza tabla
  var nr_culoare = 0;
  if (stare_joc == 1)
    nr_culoare = 5;
  else if (stare_joc == 2)
    nr_culoare = 1;
  else if (stare_joc == 3)
    nr_culoare = 4;
  else if (stare_joc == 4)
    nr_culoare = 3;
  var i;
  i = 1;
  while (i<=10)
  {
    // liniile orizontale
    AprindeNrCul(i, 1, nr_culoare);
    AprindeNrCul(i, 4, nr_culoare);
    AprindeNrCul(i, 7, nr_culoare);
    AprindeNrCul(i, 10, nr_culoare);
    // liniile verticale
    AprindeNrCul(1, i, nr_culoare);
    AprindeNrCul(4, i, nr_culoare);
    AprindeNrCul(7, i, nr_culoare);
    AprindeNrCul(10, i, nr_culoare);
    i = i+1;
  }
  // Deseneaza piesele
  var l;
  var c;
  l = 0;
  while (l < 3)
  {
    c = 0;
    while (c < 3)
    {
      nr_culoare = 0;
      if (piesa[l][c] == 0)
        nr_culoare = 0;
      else if (piesa[l][c] == 1)
        nr_culoare = 4;
      else if (piesa[l][c] == 2)
        nr_culoare = 3;
      AprindeNrCul(2+c*3, 9-l*3, nr_culoare);
      AprindeNrCul(2+c*3+1, 9-l*3, nr_culoare);
      AprindeNrCul(2+c*3, 9-l*3-1, nr_culoare);
      AprindeNrCul(2+c*3+1, 9-l*3-1, nr_culoare);
      c = c+1;
    }
    l = l+1;
  }
  // Deseneaza cursorul
  if (stare_joc == 1)
  {
    Aprinde(cx, cy, ROSU);
  }
}
function CalcDiv(A, B)
{
  var rest = A % B;
  var cat = (A-rest)/B;
  return cat;
}
function PunePiesa()
{
  var c = CalcDiv(cx-2, 3);
  var l = CalcDiv(9-cy, 3);
  if (piesa[l][c] == 0)
  {
    piesa[l][c] = juc_crt;
    return 1;
  }
  else
  {
    return 0;
  }
}
function VerificaVictorie()
{
  if ( ( (piesa[0][0]==1)&&(piesa[0][1]==1)&&(piesa[0][2]==1) ) ||
        ( (piesa[1][0]==1)&&(piesa[1][1]==1)&&(piesa[1][2]==1) ) ||
        ( (piesa[2][0]==1)&&(piesa[2][1]==1)&&(piesa[2][2]==1) ) ||
        ( (piesa[0][0]==1)&&(piesa[1][0]==1)&&(piesa[2][0]==1) ) ||
        ( (piesa[0][1]==1)&&(piesa[1][1]==1)&&(piesa[2][1]==1) ) ||
        ( (piesa[0][2]==1)&&(piesa[1][2]==1)&&(piesa[2][2]==1) ) ||
        ( (piesa[0][0]==1)&&(piesa[1][1]==1)&&(piesa[2][2]==1) ) ||
        ( (piesa[2][0]==1)&&(piesa[1][1]==1)&&(piesa[0][2]==1) ) )
  {
    stare_joc = 3;
  }
  if ( ( (piesa[0][0]==2)&&(piesa[0][1]==2)&&(piesa[0][2]==2) ) ||
        ( (piesa[1][0]==2)&&(piesa[1][1]==2)&&(piesa[1][2]==2) ) ||
        ( (piesa[2][0]==2)&&(piesa[2][1]==2)&&(piesa[2][2]==2) ) ||
        ( (piesa[0][0]==2)&&(piesa[1][0]==2)&&(piesa[2][0]==2) ) ||
        ( (piesa[0][1]==2)&&(piesa[1][1]==2)&&(piesa[2][1]==2) ) ||
        ( (piesa[0][2]==2)&&(piesa[1][2]==2)&&(piesa[2][2]==2) ) ||
        ( (piesa[0][0]==2)&&(piesa[1][1]==2)&&(piesa[2][2]==2) ) ||
        ( (piesa[2][0]==2)&&(piesa[1][1]==2)&&(piesa[0][2]==2) ) )
  {
    stare_joc = 4;
  }
}
function FunctieTaste(ev)
{
  var tasta = TastaApasata(ev);
  // mutare cursor
  if ( (tasta == 'a') && (cx >= 5) )
    cx = cx-3;
  if ( (tasta == 'd') && (cx <= 5) )
    cx = cx+3;
  if ( (tasta == 's') && (cy >= 6) )
    cy = cy-3;
  if ( (tasta == 'w') && (cy <= 6) )
    cy = cy+3;
  // plasare piesa
  if (tasta == 'p')
  {
    var rez = PunePiesa();
    // efectueaza mutare
    if (rez == 1)
    {
      juc_crt = 3-juc_crt;
      nr_mutare = nr_mutare+1;
      VerificaVictorie();
      // daca n-a fost victorie, verifica remiza
      if ( (stare_joc < 3) && (nr_mutare == 10) )
      {
        stare_joc = 2;
      }
    }
  }
  // reimprospatare ecran
  DeseneazaEcranJoc();
  if (stare_joc != 1)
  {
    AscultaTaste();
  }
}
// —> Programul propriu-zis:
// Initializez variabilele
piesa = Matrice(3, 3);
piesa[0][0] = 0; piesa[0][1] = 0; piesa[0][2] = 0;
piesa[1][0] = 0; piesa[1][1] = 0; piesa[1][2] = 0;
piesa[2][0] = 0; piesa[2][1] = 0; piesa[2][2] = 0;
juc_crt = 1;
cx = 2; cy = 9;
stare_joc = 1;
nr_mutare = 1;
// Desenez ecranul initial
DeseneazaEcranJoc();
// Asculta apasarea tastelor
AscultaTaste(FunctieTaste);
Link articol: https://igotopia.ro/cum-sa-programezi-cu-vectori-si-matrici-fara-sa-fii-as-la-matematica/
Mulțumim, Florin Bîrleanu




x
Acest website utilizează cookie-uri pentru a creea o experiență cât mai plăcută. Învață mai multe Acceptă