Programming_Memory_Game_Problem



  • Hello,
    I am learning C++ with QT and have a problem for a task which requests to add an Button named
    "Schummeln" that opens for a certain time the not opened pictures. After then the pictures should close again.

    I tried to programm it to this task but there are some pictures. Can somebody help me to open the not opened pictures in a right way and close then again. I tried also to upload the project as zip but I coudnt do it (not enough privileges)

    Thank you in advance,

    //Part_1 - Programmcode ("memoryspiel.cpp")
    
    //die Header-Datei der eigenen Klasse
    #include "memoryspiel.h"
    #include "memorykarte.h"
    #include <QHeaderView>
    #include <QMessageBox>
    #include <algorithm>
    #include <ctime>
    
    //für die Grafiken
    QString bildNamen[] = {
        ":/bilder/apfel.bmp", ":/bilder/birne.bmp", ":/bilder/blume.bmp", ":/bilder/blume2.bmp",
        ":/bilder/ente.bmp", ":/bilder/fisch.bmp", ":/bilder/fuchs.bmp", ":/bilder/igel.bmp",
        ":/bilder/kaenguruh.bmp", ":/bilder/katze.bmp", ":/bilder/kuh.bmp", ":/bilder/maus1.bmp",
        ":/bilder/maus2.bmp", ":/bilder/maus3.bmp", ":/bilder/melone.bmp", ":/bilder/pilz.bmp",
        ":/bilder/ronny.bmp", ":/bilder/schmetterling.bmp", ":/bilder/sonne.bmp",
        ":/bilder/wolke.bmp", ":/bilder/maus4.bmp"
    };
    
    
    //der Konstruktor
    memoryspiel::memoryspiel()
    {
        //die Größe setzen
        resize(394, 550);
        //und den Titel
        setWindowTitle("Memoryspiel");
    
        //den Timer erstellen
        timerUmdrehen = new QTimer();
        //er soll nur einmal ausgeführt werden
        timerUmdrehen->setSingleShot(true);
    
        //die Attribute initialisieren
        //es ist keine Karte umgedreht
        umgedrehteKarten = 0;
        //der Spieler 0 - der Mensch - fängt an
        spieler = 0;
        //es hat noch keiner Punkte
        menschPunkte = 0;
        computerPunkte = 0;
        //die Spielstärke setzen
        spielstaerke = 10;
    
        //gemerkteKarten wird mit -1 initialisiert
        for (int aussen = 0; aussen < 2; aussen++)
            for (int innen = 0; innen < 21; innen++)
                gemerkteKarten[aussen][innen] = -1;
    
        //eine neue Tabelle mit sieben Zeilen und sechs Spalten erzeugen
        spielfeld = new QTableWidget(7, 6, this);
    
        //die Spalten- und Zeilenköpfe ausblenden
        spielfeld->horizontalHeader()->hide();
        spielfeld->verticalHeader()->hide();
    
        //das Gitternetz ausblenden
        spielfeld->setShowGrid(false);
    
        //die Auswahl deaktivieren
        spielfeld->setSelectionMode(QTableWidget::NoSelection);
    
        //die Höhe und Breite der Zellen setzen
        for (int zeile = 0; zeile < 7; zeile++)
            spielfeld->setRowHeight(zeile, 64);
        for (int spalte = 0; spalte < 6; spalte++)
            spielfeld->setColumnWidth(spalte, 64);
    
        //die Größe anpassen
        spielfeld->resize(394, 458);
    
        //die Labels erzeugen und positionieren
        labelTextMensch = new QLabel(this);
        labelTextMensch->setText("Mensch");
        labelTextMensch->setGeometry(10, 460, 50, 25);
        labelMensch = new QLabel(this);
        labelMensch->setText("0");
        labelMensch->setGeometry(100, 460, 50, 25);
        labelTextComputer = new QLabel(this);
        labelTextComputer->setText("Computer");
        labelTextComputer->setGeometry(10, 480, 50, 25);
        labelComputer = new QLabel(this);
        labelComputer->setText("0");
        labelComputer->setGeometry(100, 480, 50, 25);
    
        //den Label für den aktuellen Spieler
        labelTextaktuellerSpieler = new QLabel(this);
        labelTextaktuellerSpieler->setText("Aktueller Spieler");
        labelTextaktuellerSpieler->setGeometry(10, 500, 150, 25);
        labelaktuellerSpieler = new QLabel(this);
        labelaktuellerSpieler->setText("Mensch");
        labelaktuellerSpieler->setGeometry(100, 500, 50, 25);
    
        //den PushButton für das "Schummeln" erstellen
        ButtonSchummeln = new QPushButton(this);
        ButtonSchummeln->setText("Schummeln");
        ButtonSchummeln->setGeometry(250, 460, 100, 25);
    
        //den PushButton für das "Abbrechen" erstellen
        ButtonAbbrechen = new QPushButton(this);
        ButtonAbbrechen->setText("Abbrechen");
        ButtonAbbrechen->setGeometry(250, 500, 100, 25);
    
        //die Karten erstellen
        int bildZaehler = 0;
        for (int schleife = 0; schleife < 42; schleife++)
        {
            karten[schleife] = new memorykarte(bildNamen[bildZaehler], bildZaehler);
            if ((schleife + 1) % 2 == 0)
                bildZaehler++;
        }
    
        //die Karten durcheinander werfen
        srand(time(NULL));
        //die Karten durcheinander werfen
        srand(time(NULL));
        std::random_shuffle(karten, karten + 42);
    
        //die Größe der Icons einstellen
        spielfeld->setIconSize(QSize(64,64));
        //die Karten in die Tabelle stellen
        for (int zeile = 0; zeile < 7; zeile++)
            for (int spalte = 0; spalte < 6; spalte++)
            {
                spielfeld->setItem(zeile, spalte, karten[(spalte * 7) + zeile]);
                //die Position setzen
                karten[(spalte * 7) + zeile]->setBildPos((spalte * 7) + zeile);
            }
    
        //das Anklicken einer Zelle mit dem Slot mausKlickSlot verbinden
        QObject::connect(spielfeld,SIGNAL(cellClicked(int, int)), this, SLOT(mausKlickSlot(int, int)));
        //den Timer mit dem Slot verbinden
        QObject::connect(timerUmdrehen,SIGNAL(timeout()), this, SLOT(timerSlot()));
    
        //das Anklicken des Schummeln Buttons
        QObject::connect(ButtonSchummeln, SIGNAL(clicked()), this, SLOT(ButtonfuerSchummeln()));
    
        //das Anklicken des Abbrechen Buttons
        QObject::connect(ButtonAbbrechen, SIGNAL(clicked()), this, SLOT(close()));
    }
    
    //die Methode dreht eine Karte um
    void memoryspiel::karteOeffnen(memorykarte *karte)
    {
        //zum Zwischenspeichern der Nummer und der Position
        int kartenID, kartenPos;
        //die Karten zwischenspeichern
        paar[umgedrehteKarten] = karte;
        //die Nummer und die Position beschaffen
        kartenID = karte->getBildID();
        kartenPos = karte->getBildPos();
        //die Karten in das Gedächtnis eintragen
        //aber nur dann, wenn es noch keinen Eintrag an der entsprechenden Stelle gibt
        if ((gemerkteKarten[0][kartenID] == -1))
            gemerkteKarten[0][kartenID] = kartenPos;
        else
            //wenn es schon einen Eintrag gibt und der nicht mit der aktuellen Position
            //übereinstimmt, haben wir die zweite Karte gefunden
            //Sie wird in die zweite Dimension eingetragen
            if ((gemerkteKarten[0][kartenID] != kartenPos))
                gemerkteKarten[1][kartenID] = kartenPos;
        //umgedrehte Karten erhöhen
        umgedrehteKarten++;
    
        //sind zwei Karten umgedreht worden?
        //dann prüfen wir, ob es ein Paar ist
        if (umgedrehteKarten == 2)
        {
            paarPruefen(kartenID);
    
            //die Karten wieder umdrehen
            timerUmdrehen->start(2000);
        }
        //haben wir zusammen 21 Paare?
        //dann ist das Spiel vorbei
        if (menschPunkte + computerPunkte == 21)
        {
            //den Timer anhalten
            timerUmdrehen->stop();
    
            if (menschPunkte > computerPunkte)
                  QMessageBox::information(this, "Danke", "Der Mensch hat gewonnen");
    
            else
                 {
                 QMessageBox::information(this, "Danke", "Der Computer hat gewonnen");
                 }
            QMessageBox::information(this, "Spielende", "Das Spiel ist zu Ende");
    
            this->close();
        }
    }
    
    //die Methode prüft, ob ein Paar gefunden wurde
    void memoryspiel::paarPruefen(int kartenID)
    {
        if (paar[0]->getBildID() == paar[1]->getBildID())
        {
            //die Punkte setzen
            paarGefunden();
            //die Karten aus dem Gedächtnis löschen
            gemerkteKarten[0][kartenID] = -2;
            gemerkteKarten[1][kartenID] = -2;
        }
    }
    
    //die Methode setzt die Punkte, wenn ein Paar gefunden wurde
    void memoryspiel::paarGefunden()
    {
        //spielt gerade der Mensch?
        if (spieler == 0)
        {
    
            menschPunkte++;
            labelMensch->setNum(menschPunkte);
    
        }
        else
        {
            computerPunkte++;
            labelComputer->setNum(computerPunkte);
    
        }
    }
    
    //die Methode dreht die Karten wieder um bzw. nimmt sie aus dem Spiel
    void memoryspiel::kartenSchliessen()
    {
        bool raus = false;
        //ist es ein Paar?
        if (paar[0]->getBildID() == paar[1]->getBildID())
        {
            //dann nehmen wir die Karten aus dem Spiel
            paar[0]->rausnehmen();
            paar[1]->rausnehmen();
            //raus wird auf true gesetzt
            raus = true;
        }
        else
        {
            //sonst drehen wir die Karten nur wieder um
            paar[0]->umdrehen();
            paar[1]->umdrehen();
        }
        //es ist keine Karte mehr geöffnet
        umgedrehteKarten = 0;
        //hat der Spieler kein Paar gefunden
        if (raus == false)
            //dann wird der Spieler gewechselt
            spielerWechseln();
        else
            //hat der Computer eine Paar gefunden?
            //dann ist er noch einmal an der Reihe
            if (spieler == 1)
                computerZug();
    }
    
    //die Methode wechselt den Spieler
    void memoryspiel::spielerWechseln()
    {
        //wenn der Mensch an der Reihe war, kommt jetzt der Computer
        if (spieler == 0)
        {
            labelaktuellerSpieler->setText("Computer");
            spieler = 1;
            computerZug();
        }
        else
        {
            labelaktuellerSpieler->setText("Mensch");
            spieler = 0;
        }
    }
    
    //die Methode für den Computerzug
    void memoryspiel::computerZug()
    {
        int kartenZaehler = 0;
        int zufall = 0;
        bool treffer = false;
    
        //zur Steuerung der Spielstärke
        if ((rand() % spielstaerke) == 7)
        {
            //erst einmal nach einem Paar suchen
            //dazu durchsuchen wir das Feld gemerkteKarten,
            //bis wir in den beiden Dimensionen einen Wert
            //für eine Karte finden
            while ((kartenZaehler < 21) && (treffer == false))
            {
                //gibt es in beiden Dimensionen einen Wert größer oder gleich 0?
                if ((gemerkteKarten[0][kartenZaehler] >= 0) && (gemerkteKarten[1][kartenZaehler] >= 0))
                {
                    //dann haben wir ein Paar
                    treffer = true;
                    //die erste Karte umdrehen
                    karten[gemerkteKarten[0][kartenZaehler]]->umdrehen();
                    karteOeffnen(karten[gemerkteKarten[0][kartenZaehler]]);
                    //und die zweite auch
                    karten[gemerkteKarten[1][kartenZaehler]]->umdrehen();
                    karteOeffnen(karten[gemerkteKarten[1][kartenZaehler]]);
                }
                kartenZaehler++;
            }
        }
        //wenn wir kein Paar gefunden haben, drehen wir zufällig zwei Karten um
        if (treffer == false)
        {
            //so lange eine Zufallszahl suchen, bis eine Karte
            //gefunden wird, die noch im Spiel ist
            do {
                zufall = rand() % 42;
            } while (karten[zufall]->getNochImSpiel() == false);
            //die erste Karte umdrehen
            karten[zufall]->umdrehen();
            karteOeffnen(karten[zufall]);
            //für die zweite Karte müssen wir außerdem prüfen,
            //ob sie nicht gerade angezeigt wird
            do {
                zufall = rand() % 42;
            } while ((karten[zufall]->getNochImSpiel() == false) || (karten[zufall]->getUmgedreht() == true));
            //und die zweite Karte umdrehen
            karten[zufall]->umdrehen();
            karteOeffnen(karten[zufall]);
        }
    }
    
    //der Slot für das Anklicken einer Zelle
    void memoryspiel::mausKlickSlot(int x, int y)
    {
        //darf der Mensch ziehen?
        if (zugErlaubt() == true)
        {
            //ist die Karte nicht schon umgedreht und ist sie noch im Spiel?
            if ((karten[(y * 7) + x]->getUmgedreht() == false) && (karten[(y * 7) + x]->getNochImSpiel() == true))
            {
                //dann umdrehen
                karten[(y * 7) + x]->umdrehen();
                karteOeffnen(karten[(y * 7) + x]);
            }
         }
    }
    
    //der Slot für den Timer
    void memoryspiel::timerSlot()
    {
        //die Karten wieder umdrehen
        kartenSchliessen();
    }
    
    //die Methode prüft, ob Züge des Menschen erlaubt sind
    //die Rückgabe ist false, wenn gerade der Computer zieht oder wenn schon zwei Karten umgedreht sind
    //sonst ist die Rückgabe true
    bool memoryspiel::zugErlaubt()
    {
        bool erlaubt = true;
        //zieht der Computer?
        if (spieler == 1)
            erlaubt = false;
        //sind schon zwei Karten umgedreht?
        if (umgedrehteKarten == 2)
            erlaubt = false;
        return erlaubt;
    }
    
    void memoryspiel::ButtonfuerSchummeln()
    {
    
         int i=0;
         int j=0;
         int x; int y;
         spieler = 1;
    
        //wenn wir kein Paar gefunden haben, drehen wir Karten um
        if ((karten[i]->getNochImSpiel() == true) && (karten[i]->getUmgedreht() == false))
        {
    
            for(i=0 ;i < 42; i++)
            {
             karten[i]->umdrehen();
             karteOeffnen(karten[i]);
            }
    
    
           QMessageBox::information(this, "Karten", "Geöffnet");
           timerUmdrehen->start(2000);
    
           for (int j=0;j <42; j++)
           {
               karten[j]->restumdrehen();
           }
    
           //timerUmdrehen->stop();
    
           QMessageBox::information(this, "Karten", "Geschlossen");
           //timerSlot();
           //this->close();
        }
    
    
    
        }
    
    
    
    
    
    
    void memoryspiel::ButtonfuerAbbrechen()
    {
    
    }
    
    
    
    
    
    
    

  • Qt Champions 2016

    @cprogcoder said in Programming_Memory_Game_Problem:

    Hi
    I assume that all code that turns the cards works.
    So i think its the delay before hiding them again that is the issue ?

    So maybe you can use qtimer single slot with a lamda

    so in ButtonfuerSchummeln()
    just after 
     QMessageBox::information(this, "Karten", "Geöffnet");
     QTimer::singleShot(5000, [=] {
            for (int j=0;j <42; j++)
            {
                karten[j]->restumdrehen();
            }
    
        });
    

    That will all loop all cards and call restumdrehen() after 5 secs.

    If that is not what you need help with, please state more clearly
    which part of the code that is not working as you want to.


  • Moderators

    Hallo! As my guess is that you're doing this for learning and fun, I assume you want a clean / good solution. First advice is to separate game logic and GUI code.



  • @mrjj 0_1507150674955_Clipboard01.jpg

    Hello,

    thank you at first for your support. The not working part is that :

    • if I push the "ButtonSchummeln" not all cards in the game (first all cards are opening and then two brown cards are directly change ==> there is actually a failure ). ?

    • after opening all cards it doesnt close again => I included the timer but it doesnt reacted to the timer. I had some failures and changed it as ```
      //QTimer::singleShot(5000, this ,SLOT ({
      for (int j=0;j <42; j++)
      {
      karten[j]->restumdrehen();
      }

           }));
      
    - the cards should close after 
    
    Can I  upload the zip file ? How do we get the right to upload  ?
    Then I think it would be better to understand the open points.
    
    Thank you in advance

  • Qt Champions 2016

    @cprogcoder
    It wont let you upload zip files here, not even for mods :)
    Use something like
    https://wetransfer.com/ Awful. sorry
    https://expirebox.com/

    The german variable names is a challenge for me but hopefully others can help.



  • @mrjj
    I dont have E-Mail of your account ?. Should I send the zip file with https://wetransfer.com ?

    Thanks in advance,



  • @cprogcoder hi,
    you try to automate the showImage functionality with function that are clearly meant to be used by an user input e.g. mouseclick.

    My guess is, that somewhere along the line some thing is not set, or that the paar marker ist falsely set.

    Here's my suggestion, it will also clean up your code a good amount.

    You already have your own class memorykarte in that class add a simple Slot for example reset, that resets itself to the initialisation.

    and connect your timeout signal to that reset slot:

    for (int schleife = 0; schleife < 42; schleife++)
        {
            karten[schleife] = new memorykarte(bildNamen[bildZaehler], bildZaehler);
            QObject::connect(timerUmdrehen,&QTimer::timeout, karten[schleife], &memorykarte::reset);
            if ((schleife + 1) % 2 == 0)
                bildZaehler++;
        }
    

  • Qt Champions 2016

    Hi
    sorry https://wetransfer.com was bad example of online file share site.
    Forget them. they uses email so not useful here.

    you can use https://expirebox.com/
    and paste the Download-Link link of the file here

    But it seems @J-Hilk already found some issues that might help you along.



  • @mrjj
    Hello,

    the download link is as follows :
    https://expirebox.com/download/aaa6e79ddf8b023f57dcb6e03e66fcc0.html

    Thank you in advance,



  • @J.Hilk
    Hello J.Hilk,

    I tried the code but there was a failure like "no matching..."
    I included also the "memoryspiel" code as file into the following link, could you analyze it ?

    https://expirebox.com/download/96f66c50ec28af600c5af38c209dd779.html

    Thank you in advance,



  • @cprogcoder well, the link only contains the mainwindow cpp. Did you create a matching slot in memorykarte to connect to?


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.