M9 | L10 – Joc de memorie II

Astăzi vom afla despre:

  • Placile intoarse pe fata

Aplicațiile pe care le vom folosi sunt:

Khan Academy

PROIECTE:

Joc de memorie

Exemplu: https://www.khanacademy.org/computer-programming/joc-memorie-02/5361280322846720

Placile intoarse pe fata

Acum, că avem o grilă de plăci cu fața în jos, să abordăm o problemă mai dificilă: atribuirea fiecăreia dintre ele a unei imagini, astfel încât să existe 2 din fiecare imagine în matrice, distribuite aleatoriu în întreaga. Probabil că există multe modalități prin care am putea realiza acest lucru, dar iată ce aș sugera:

  1. Creăm o serie de imagini posibile, folosind funcția getImage pentru a le alege din biblioteca noastră.
  2. Vom avea nevoie doar de 10 imagini pentru fețele celor 20 de dale ale noastre, așa că vom crea o nouă matrice care conține 2 copii a 10 imagini selectate aleatoriu din prima matrice.
  3. Amestecăm matricea de imagini selectată, astfel încât perechile de imagini să nu mai fie una lângă alta într-o matrice.
  4. În bucla imbricată în care creăm dale, vom atribui o imagine din acea matrice fiecărei dale.

Este posibil ca acești pași să nu aibă încă sens – să le facem fiecare și să vedem cum arată.

Pasul 1: Creăm o serie de imagini posibile, folosind funcția getImage pentru a le alege din biblioteca noastră:

var faces = [

    getImage(„avatars/leafers-seed”),

    getImage(„avatars/leafers-seedling”),

    getImage(„avatars/leafers-sapling”),

    getImage(„avatars/leafers-tree”),

    getImage(„avatars/leafers-ultimate”),

    getImage(„avatars/marcimus”),

    getImage(„avatars/mr-pants”),

    getImage(„avatars/mr-pink”),

    getImage(„avatars/old-spice-man”),

    getImage(„avatars/robot_female_1”),

    getImage(„avatars/piceratops-tree”),

    getImage(„avatars/orange-juice-squid”)

];

Am ales o grămadă de avatare, dar ai putea să le schimbi pentru a alege indiferent de imaginile tale preferate. Important este să ne asigurăm că această matrice conține cel puțin 10 imagini, astfel încât să nu rămânem fără imagini pentru cele 20 de dale. Cu toate acestea, putem adăuga mai mult de 10 imagini, pentru a oferi jocului nostru mai multă varietate de fiecare dată când este jucat, pentru că vom restrânge lista în pasul următor.

Pasul 2: Vom avea nevoie doar de 10 imagini pentru fețele celor 20 de plăci, așa că vom crea o nouă matrice care conține 2 copii a 10 imagini selectate aleatoriu din prima matrice.

Pentru a face acest lucru, creăm o buclă for care se repetă de 10 ori. În fiecare iterație, alegem în mod aleatoriu un index din tabloul de fețe, îl împingem de două ori pe tabloul selectat și apoi folosim metoda de îmbinare pentru a-l elimina din tabloul de fețe, astfel încât să nu-l selectăm de două ori. Ultimul pas este foarte important!

var selected = [];

for (var i = 0; i < 10; i++) {

    // Randomly pick one from the array of faces

    var randomInd = floor(random(faces.length));

    var face = faces[randomInd];

    // Push 2 copies onto array

    selected.push(face);

    selected.push(face);

    // Remove from faces array so we don’t re-pick

    faces.splice(randomInd, 1);

}

Pasul 3: Amestecăm matricea de imagini selectată, astfel încât perechile de imagini să nu mai fie una lângă alta într-o matrice.

Probabil că ați amestecat un pachet de cărți în viața dvs., dar ați amestecat vreodată o matrice în JavaScript? Cea mai populară tehnică de amestecare în orice limbaj de programare se numește Fisher-Yates Shuffle și asta vom folosi aici.

Fisher-Yates Shuffle începe prin selectarea mai întâi a unui element aleatoriu oriunde în matrice și schimbarea acestuia cu ultimul element din matrice. În pasul următor, selectează un element aleatoriu de oriunde din matrice în afară de ultimul element și îl schimbă cu al doilea până la ultimul element. Continuă până când a schimbat fiecare element.

Pentru a implementa acest lucru în JavaScript, să facem o funcție shuffleArray care preia o matrice și amestecă elementele sale, schimbând matricea originală:

var shuffleArray = function(array) {

    var counter = array.length;

    // While there are elements in the array

    while (counter > 0) {

        // Pick a random index

        var ind = Math.floor(Math.random() * counter);

        // Decrease counter by 1

        counter–;

        // And swap the last element with it

        var temp = array[counter];

        array[counter] = array[ind];

        array[ind] = temp;

    }

};

Dacă algoritmul nu are încă sens, după ce ați parcurs vizualizarea și ați citit codul, ați putea să-l încercați cu un pachet de cărți real din lumea reală sau să urmăriți cum o face Adam Khoury în videoclipul său de pe YouTube.

După definirea acelei funcții, trebuie să o numim efectiv:

shuffleArray(selected);

Și acum avem o serie de 10 perechi de imagini, amestecate la întâmplare!

Pasul 4: În bucla imbricată în care creăm dale, vom atribui o imagine din acea matrice fiecărei dale.

Avem 20 de imagini în matricea selectată și repetăm de 20 de ori pentru a crea noi dale în locații din grilă. Pentru a selecta o imagine aleatorie pentru fiecare țiglă, putem apela metoda pop din matrice. Această metodă elimină ultimul element din matrice și îl returnează și este cel mai simplu mod de a ne asigura că atribuim toate imaginile, dar nu le atribuim dublu.

for (var i = 0; i < NUM_COLS; i++) {

  for (var j = 0; j < NUM_ROWS; j++) {

    var tileX = i * 54 + 5;

    var tileY = j * 54 + 40;

    var tileFace = selected.pop();

    var tile = new Tile(tileX, tileY, tileFace);

    tiles.push(tile);

  }

}

Observați cum codul respectiv trece tileFace ca al treilea parametru către Tileconstructor? Constructorul nostru inițial avea doar 2 parametri, x și y, dar acum îl modificăm astfel încât să ne putem aminti și imaginea fiecărei fețe de dale, plus dacă este cu fața în sus:

var Tile = function(x, y, face) {

    this.x = x;

    this.y = y;

    this.size = 70;

    this.face = face;

    this.isFaceUp = false;

};

Deci, acum avem teoretic imagini atribuite fiecărei țigle, dar nu le afișăm încă! Să modificăm metoda Tile.draw astfel încât să poată desena plăci cu fața în sus:

Tile.prototype.draw = function() {

    fill(214, 247, 202);

    strokeWeight(2);

    rect(this.x, this.y, this.size, this.size, 10);

    if (this.isFaceUp) {

        image(this.face, this.x, this.y,

              this.size, this.size);

    } else {

        image(getImage(„avatars/leaf-green”),

              this.x, this.y, this.size, this.size);

    }

};

În cele din urmă, pentru a testa totul funcționează, putem schimba bucla noastră pentru a seta proprietatea isFaceUp a fiecărei plăci la adevărată înainte de a o desena:

for (var i = 0; i < tiles.length; i++) {

  tiles[i].isFaceUp = true;

  tiles[i].draw();

}