Igra u kojoj se nasumično uključuju i isključuju LED, a korisnik mora ponoviti redoslijed kojim su se uključivale. Redoslijed paljenja bira se preko potenciometra za označavanje željene LED i tipkala za potvrdu odabira. Povratne informacije o igri (poraz/nova razina/pobjeda) su napravljene uz pomoć prikladnih svjetlosnih i zvučnih efekata.

Dependencies:   mbed zvucniEfekti

https://os.mbed.com/media/uploads/nikola_cancer/igra_memory.png

main.cpp

Committer:
nikola_cancer
Date:
2021-12-01
Revision:
0:f1138da8bd35

File content as of revision 0:f1138da8bd35:

/* mbed Microcontroller Library
 * Copyright (c) 2019 ARM Limited
 * SPDX-License-Identifier: Apache-2.0
 */

#include "mbed.h"
#include "zvucniEfekti.h"

#define MAX_BROJ_SEKVENCE 10
#define SAMPLEFREQ 8000

InterruptIn tipkaloFlipLED(D12);
DigitalOut ledZaProvjeru(D6);

Ticker sampleRate;
AnalogOut zvucnik(PA_5);
AnalogIn potenciometar(A0);
DigitalIn tipkalo(D9);

int kontrolaZvuka; // globalna varijabla za odabir koji zvuk se pušta (u
                   // funkciji sviraj) na piezo

class Igra {
private:
  int brojLedica;
  DigitalOut *ledice;
  float vrijednostiZaPotenciometar[10];

public:
  Igra(DigitalOut *led, int brLED) {
    ledice = led;
    brojLedica = brLED;

    float korak = 1. / brojLedica;
    for (int i = 0; i < brojLedica + 1; i++) {
      if (i == 0) {
        vrijednostiZaPotenciometar[i] = 0;
      } else {
        vrijednostiZaPotenciometar[i] =
            vrijednostiZaPotenciometar[i - 1] + korak;
      }
    }

    tipkalo.mode(PullUp);

    srand(time(0));
  }

  /*
      globalna varijabla kontrolaZvuka:
      0 -> gameStart
      1 -> nextLevel
      2 -> finalLevel
      3 -> gameWon
      4 -> gameOver
  */
  void sviraj() {
    static int i = 0;

    switch (kontrolaZvuka) {
    case 0:
      zvucnik.write_u16(zvukGameStart[i] << 8);
      i++;
      if (i == brojSamplovaZvukGameStart) {
        i = 0;
        zvucnik.write_u16(0);
        sampleRate.detach();
      }
      break;

    case 1:
      zvucnik.write_u16(zvukNextLevel[i] << 8);
      i++;
      if (i == brojSamplovaZvukNextLevel) {
        i = 0;
        zvucnik.write_u16(0);
        sampleRate.detach();
      }
      break;

    case 2:
      zvucnik.write_u16(zvukFinalLevel[i] << 8);
      i++;
      if (i == brojSamplovaZvukFinalLevel) {
        i = 0;
        zvucnik.write_u16(0);
        sampleRate.detach();
      }
      break;

    case 3:
      zvucnik.write_u16(zvukGameWon[i] << 8);
      i++;
      if (i == brojSamplovaZvukGameWon) {
        i = 0;
        zvucnik.write_u16(0);
        sampleRate.detach();
      }
      break;

    case 4:
      zvucnik.write_u16(zvukGameOver[i] << 8);
      i++;
      if (i == brojSamplovaZvukGameOver) {
        i = 0;
        zvucnik.write_u16(0);
        sampleRate.detach();
      }
      break;
    }
  }

  void generirajRandomSekvencu(int brojUzoraka, int *sekvenca) {
    ugasiSveLED();
    for (int i = 0; i < brojUzoraka; i++) {
      int num = (rand() % brojLedica); // random broj između 0 i brLED
      sekvenca[i] = num; // spremi u sekvencu zbog kasnije usporedbe generiranog
      // i pogađanog

      // upali i ugasi random LED
      wait_ms(500);
      ledice[num] = 1;
      wait_ms(500);
      ledice[num] = 0;
      wait_ms(500);
    }
    wait(2);
  }

  void spremiUnosKorisnika(int brojUzoraka, int *sekvenca) {
    for (int k = 0; k < brojUzoraka; k++) {
      for (;;) {
        for (int i = 0; i < brojLedica; i++) {
          if (potenciometar >= vrijednostiZaPotenciometar[i] &&
              potenciometar < vrijednostiZaPotenciometar[i + 1]) {
            ledice[i] = 1;
          } else {
            ledice[i] = 0;
          }
        }

        if (tipkalo == 0) {
          wait_ms(50); // debounce
          if (tipkalo == 0) {
            for (int j = 0; j < brojLedica; j++) {
              if (ledice[j].read() == 1) {
                sekvenca[k] = j;

                // da korisnih ima feedback da je ucitan njegov odabir
                ledice[j] = 0;
                wait_ms(500);
                ledice[j] = 1;
              }
            }
            // cekaj dok tipkalo ne ode u jedan (radi ko rising edge)
            // da ove beskonacne petlje nema bi spremil 4x istu vrijednost u
            // array (jer radi brzo)
            do {
            } while (tipkalo.read() == 0);
            break;
          }
        }
      }
    }
  }
  /*
      funkcija vraca 0 za razlicite arraye, a 1 za iste
  */
  int provjeriSekvence(int *generiranaSekvenca, int *unesenaSekvenca,
                       int brojUzorakaSekvence) {
    int i = 0;
    for (i = 0; i < brojUzorakaSekvence; i++) {
      if (generiranaSekvenca[i] != unesenaSekvenca[i]) {
        return 0; // poraz
      }
    }
    return 1; // sljedeca razina/pobjeda
  }

  void ugasiSveLED() {
    for (int i = 0; i < brojLedica; i++) {
      ledice[i] = 0;
    }
  }

  void sljedecaRazina(int finalniLevel) {
    ugasiSveLED();
    if (finalniLevel != 0) {
      kontrolaZvuka = 2;
    } else {
      kontrolaZvuka = 1;
    }
    sampleRate.attach(this, &Igra::sviraj, 1.0 / SAMPLEFREQ);
    for (int i = 0; i < brojLedica; i++) {
      ledice[i] = 1;
      wait_us(100000);
      ledice[i] = 0;
    }
    wait_us(100000);
  }

  void novaIgra() {
    kontrolaZvuka = 0;
    sampleRate.attach(this, &Igra::sviraj, 1.0 / SAMPLEFREQ);
    wait(2);
  }

  void pobjeda() {
    ugasiSveLED();
    kontrolaZvuka = 3;
    sampleRate.attach(this, &Igra::sviraj, 1.0 / SAMPLEFREQ);

    // chaser effekt 5x sim tam
    int i = 0;
    do {

      for (int j = 0; j < brojLedica; j++) {
        ledice[j] = 1;
        wait_us(60000);
        ledice[j] = 0;
      }

      for (int j = brojLedica - 1; j >= 0;
           j--) // -1 jer sizeof(arr) za arr[20] npr daje 20 a zadnji element je
                // 19
      {
        ledice[j] = 1;
        wait_us(60000);
        ledice[j] = 0;
      }

      i++;
    } while (i < 10);
    wait(2);
  }

  void poraz() {
    ugasiSveLED();
    kontrolaZvuka = 4;
    sampleRate.attach(this, &Igra::sviraj, 1.0 / SAMPLEFREQ);
    int i = 0;
    do {

      for (int j = 0; j < brojLedica; j++) {
        ledice[j] = 1;
      }
      wait_us(500000);

      ugasiSveLED();
      wait_us(500000);

      i++;
    } while (i < 3);
    wait(2);
  }
};

void flipLED() { ledZaProvjeru = !ledZaProvjeru; }

int main() {
  wait(1);
  tipkaloFlipLED.mode(PullUp);
  tipkaloFlipLED.rise(&flipLED);
  // inicijalizacija pinova za igru
  DigitalOut led[] = {D2, D4, D7, D8, D10, D11};
  int brojLedica = sizeof(led) / sizeof(led[0]);

  // spremanje generiranih i unesenih vrijednosti
  int generiranaSekvenca[MAX_BROJ_SEKVENCE] = {0};
  int unosKorisnika[MAX_BROJ_SEKVENCE] = {0};

  // postavke i logika igre
  int brojUzorakaSekvence = 3; // kolko puta se LED pale/gase
  int pobjedaPorazZastavica;
  int trenutniLevel = 0;
  int finalniLevel = 2;

  Igra igra(led, brojLedica);

  while (true) {
    if (trenutniLevel == 0) {
      igra.novaIgra();
    }
    igra.generirajRandomSekvencu(brojUzorakaSekvence, generiranaSekvenca);
    igra.spremiUnosKorisnika(brojUzorakaSekvence, unosKorisnika);
    pobjedaPorazZastavica = igra.provjeriSekvence(
        generiranaSekvenca, unosKorisnika, brojUzorakaSekvence);

    switch (pobjedaPorazZastavica) {
    case 0:
      igra.poraz();
      brojUzorakaSekvence = 3;
      trenutniLevel = 0;
      break;
    case 1:
      if (trenutniLevel == finalniLevel - 1) {
        igra.sljedecaRazina(1); // 1 -> šalji zvuk finalLevel
        brojUzorakaSekvence++;
        trenutniLevel++;
      } else if (trenutniLevel == finalniLevel) {
        igra.pobjeda();
        brojUzorakaSekvence = 3;
        trenutniLevel = 0;
      } else {
        igra.sljedecaRazina(0); // 0 -> šalji zvuk nextLevel
        brojUzorakaSekvence++;
        trenutniLevel++;
      }
      break;
    }
  }
}