Damebrettspiel - Speicherzugriffsfehler



  • Huhu und zwar habe ich ein kleines Problem mit meinem Dameprogramm.
    Nach ca. 5 Zügen wird mir immer Speicherzugriffsfehler ausgegeben und nichts geht mehr woran liegt das ? 😕

    main.cpp:

    #include <iostream>
    #include "Dame.hpp"
    //#include <Dame.cpp>  nur für windows
    
    using namespace std;
    
    int main() {
      CheckersWithPlayers checkers;
      checkers.initBoard();
      CheckersWithPlayers Savefile;
      Savefile.initBoard();
      checkers.printBoard();
      while(true)
      {
        char zurueck;
        Savefile = checkers;
        checkers.setboardplayer1();
        checkers.tokencounter();
        checkers.printBoard();
        cout << "zuruecksetzen mit '-' Enter? Ansonsten druecken Sie 'n' und bestaetigen(Enter) um fortzufahren!" << endl;
        cin >> zurueck;
        if(zurueck == '-')
        {
          // zurücksetzen WHITE
          checkers = Savefile;
          checkers.printBoard();
          Savefile = checkers;
          checkers.setboardplayer1();
          checkers.tokencounter();
          checkers.printBoard();
        }
        Savefile = checkers;
        checkers.setboardplayer2();
        checkers.tokencounter();
        checkers.printBoard();
        cout << "zuruecksetzen mit '-' Enter? Ansonsten druecken Sie 'n' und bestaetigen(Enter) um fortzufahren!" << endl;
        cin >> zurueck;
        if(zurueck == '-')
        {
          // zurücksetzen BLACK
          checkers = Savefile;
          checkers.printBoard();
          Savefile = checkers;
          checkers.setboardplayer2();
          checkers.tokencounter();
          checkers.printBoard();
        }
    
      }
    }
    

    Dame.hpp

    #include <vector>
    #pragma once
    /*
    class CheckersWithPlayers
    
     ruft der Reihe nach alle Funktionen ab und beinhaltet die Vektoren des Brettes
    
       void initBoard
        setzt die Spielsteine
    
        Seite Spieler 1:
        setzt auf den oberen 3 Reihen [i-Zahlenseite] über die Länge der Buchstabenreihe [j-Buchstabenreihe]
        die B-Spielsteine immer mit einem Feld (waagerecht) Abstsand sowie in der 2ten Reihe[i] um 1 Feld versetzt
    
        Seite Spieler 2:
        setzt auf den unteren 3 Reihen [i-Zahlenseite] über die Länge der Buchstabenreihe [j-Buchstabenreihe]
        die W-Spielsteine immer mit einem Feld (waagerecht) Abstsand sowie in der 2ten Reihe[i] um 1 Feld versetzt
    
      void print Board
        erzeugt das Spielbrett
    
        erzeugt ein 10x10 Spielbrett und gibt die Seitenbeschriftung aus, die obere Zahlenreihe
        wird durch Buchstaben ersetzt und die linke Zahlenreihe wird invers ausgegeben
    
      void setboardplayer1
       Spielzüge Spieler 1 (WHITE)
    
        beinhaltet die Eingabe des Spielzuges sowie alle möglichen Spielzüge die getätigt werden können und deren Gültigkeit für Spieler 1
    
      void setboardplayer2
       Spielzüge Spieler 2 (BLACK)
    
        beinhaltet die Eingabe des Spielzuges sowie alle möglichen Spielzüge die getätigt werden können und deren Gültigkeit für Spieler 2
    
      void tokencounter
       aktueller Spielstand
    
        nimmt die Gesamtanzahl der aktuellen Spielsteine(WHITE & BLACK) und zieht bei "vernichten" eines  Spielsteines
        bei der "Farbe" einen ab
    
    main
    
     vereint das Programm mit allen Dateien und führt es der Reihe nach aus
    
      CheckersWithPlayers wird in checkers "gepackt" - die Spielsteine werden gesetzt in checkers -
      CheckersWithPlayers wird in Savefile "gepackt" - die Spielsteine werden gesetzt in Savefile -
      das Spielbrett wird erzeugt --> nun 2x der selbe Ablauf einmal Spieler1 und einmal Spieler2 -
      checkers wird in Savefile gespeichert - Spieler macht seinen Zug - Spielstand wird abgerufen-
      Brett wird erzeugt - falls 'n'+ (Enter): nächster Spieler - falls '-': Brett vor dem Zug wird geladen-
      Spieler kann erneut seinen Zug machen - Spielstand wird abgerufen - Brett wird erzeugt
     */
    class CheckersWithPlayers {
    public:
    
    void initBoard();
    void printBoard();
    void setboardplayer1();
    void setboardplayer2();
    void tokencounter();
    
    private:
         char Board [10][10] = {};
    };
    

    Dame.cpp

    #include <iostream>
    #include <vector>
    #include <iomanip>
    #include "Dame.hpp"
    
    using namespace std;
    
    void CheckersWithPlayers::initBoard()
    {
      // Seite Spieler 1 (WHITE)
      for(int i = 0; i < 3; i++) {
          for(int j = 0; j <10; j++) {
              if((j % 2) == 0) {
                  if((i % 2) == 0) {
                      Board[i][j] = 'W';
                  } else {
                      Board[i][(j + 1)] = 'W';
                    }
               }
           }
        }
      // Seite Spieler 2 (BLACK)
      for(int i = 0; i < 3; i++) {
          for(int j = 0; j < 10; j++) {
              if((j % 2) == 0) {
                  if((i % 2) != 0) {
                      Board[(i + 7)][j] = 'B';
                  } else {
                      Board[(i + 7)][(j + 1)] = 'B';
                    }
               }
           }
        }
    }
    
    void CheckersWithPlayers::printBoard()
    {
        // Buchstabe Position [j]
        cout << "  ";
        for(int k = 0; k <10; k++) {
            cout << "    " << static_cast<char> (k + 65);
        }
    
        cout << endl << endl;
    
        // Zahl Position [i]
        for(int i = 9; i >=0; i--) {
                cout <<setw(3)<< i+1 << "  ";
                for(int j = 0; j <10; j++) {
                    if(Board[i][j] != 0){
                        cout << "[ " << Board[i][j] << " ]";
                    } else {
                        cout << "[   ]";
                      }
                }
                cout << endl;
        }
    }
    
    void CheckersWithPlayers::setboardplayer1()
    {
      cout << endl;
      cout << "Spieler 1 (WHITE) ist an der Reihe !" << endl;
      cout << "Bitte geben Sie Start- und Zielposition Ihres Steines an (Bsp.: A3 B4):" << endl;
      int SN;  // Startnumber
      int EN;  // Endnumber
      char SC; // Startchar
      char EC; // Endchar
      cin >> SC >> SN >> EC >> EN;
    
      SN = SN-1;
      EN = EN-1;
      SC = SC-'A';
      EC = EC-'A';
    
     if(Board[EN][EC] == 0 && SN+1 == EN && (SC+1 == EC || EC+1 == SC)) {
       Board[EN][EC] = Board[SN][SC];
       Board[SN][SC] = 0;
       cout << "Ihr Zug ist gueltig !" << endl;
       cout << endl;
     }
     else if(SN+2 == EN && (SC+2 == EC || EC+2 == SC) && Board[SN+1][SC+(EC-SC)/2] == 'B') {
        Board[EN][EC] = Board[SN][SC];
        Board[SN][SC] = 0;
        Board[SN+1][SC+(EC-SC)/2] = 0;
        cout << "Ihr Zug ist gueltig !" << endl;
        cout << endl;
      }
      else
      {
        cout << "Ihr Zug ist ungueltig !" << endl;
        cout << "Bitte erneut eingeben !" << endl;
    
        setboardplayer1();
      }
    }
    
    void CheckersWithPlayers::setboardplayer2()
    {
      cout << endl;
      cout << "Spieler 2 (BLACK) ist an der Reihe !" << endl;
      cout << "Bitte geben Sie Start- und Zielposition Ihres Steines an (Bsp.: B8 C7):" << endl;
      int SN;
      int EN;
      char SC;
      char EC;
      cin >> SC >> SN >> EC >> EN;
    
      SN = SN-1;
      EN = EN-1;
      SC = SC-'A';
      EC = EC-'A';
    
     if(Board[EN][EC] == 0 && SN-1 == EN && (SC-1 == EC || EC-1 == SC)) {
       Board[EN][EC] = Board[SN][SC];
       Board[SN][SC] = 0;
       cout << "Ihr Zug ist gueltig !" << endl;
       cout << endl;
     }
     else if(SN-2 == EN && (SC-2 == EC || EC-2 == SC) && Board[SN-1][SC+(EC-SC)/2] == 'W') {
        Board[EN][EC] = Board[SN][SC];
        Board[SN][SC] = 0;
        Board[SN-1][SC+(EC-SC)/2] = 0;
        cout << "Ihr Zug ist gueltig !" << endl;
        cout << endl;
      }
      else
      {
        cout << "Ihr Zug ist ungueltig ! " << endl;
        cout << "Bitte erneut eingeben !" << endl;
    
        setboardplayer2();
      }
    }
    
    void CheckersWithPlayers::tokencounter()
    {
      int white = 0;
      int black = 0;
      for(int i = 0; i <= 9; i++)
      {
        for(int k = 0; k <= 9; k++)
        {
          if(Board[i][k] == 'W')
          {
            white++;
            black++;
          }
        }
      }
      cout << "Weiss: " << white << endl << "Schwarz: " << black << endl;
    }
    

    Danke 🙂



  • Was sagt denn der Debugger?



  • Was heißt ca?
    Wenn ich das grade richtig sehe überprüfst du nicht, ob deine Eingabe auf dem Spielfeld ist.



  • Du könntest auch mal überlegen, ob du wirklich 2x Code zum Einlesen eines Zuges und Prüfen der Gültigkeit brauchst. Das sollte doch für beide Farben praktisch identischer Code sein!



  • @Th69 Debugger spuckt mir nur die Warnung aus das [10][10] kein Char ist immer wenn es aufgerufen wird !
    @Schlangenmensch sry für die wahrscheinlich doofe Frage aber wie meinst du das? Bzw. setzt man das um ? 😕 ca. heißt das es auf meinem Rechner 16gb ram für 5 Züge reicht und auf einem anderen Rechner mit 4gb ram gingen gerade mal 3 Züge ich weiß allerdings nicht ob es was damit zu tuen hat.



  • felix92 schrieb:

    @Th69 Debugger spuckt mir nur die Warnung aus das [10][10] kein Char ist immer wenn es aufgerufen wird !

    ... und das zu Recht. Board geht von 0 bis 9 , Board[10][10] ist schon Speicher, der dir nicht gehört.

    felix92 schrieb:

    @Schlangenmensch sry für die wahrscheinlich doofe Frage aber wie meinst du das?

    Board[EN][EC] = Board[SN][SC];
       Board[SN][SC] = 0;
       cout << "Ihr Zug ist gueltig !" << endl;
    

    Du greifst hier lustig auf alle möglihen Speicherbereiche zu, nur weils der Benutzer eingibt. Prüfe zuerst, ob das Eingegebene überhaupt im Bereich von Brett liegt.



  • felix92 schrieb:

    @Th69 Debugger spuckt mir nur die Warnung aus das [10][10] kein Char ist immer wenn es aufgerufen wird

    Glaub ich, [10][10] gibt es auch nicht.



  • Also quasi [10][10] auf [0][9] ändern ? 😕 😕 aber dann gibt er mir doch ein falsches "Brett" aus 😕
    Sry aber verstehe das nicht so ganz ist der Speicher nicht frei für alle anstehenden Aufgaben ?



  • Irgendwo wirst du wohl über die Arraygrenzen [9][9] hinausgehen. Aber da hilft dir der Debugger weiter, Step für Step durchgehen.



  • Der gibt mir halt nur aus das [10][10] kein Char ist als Warnung funktionieren tut es ja für maximal 5 Züge 😞



  • Dein lieber Debugger sagt Dir doch sicher aus, wo Du auf Brett[10][10] zugreifst ...



  • felix92 schrieb:

    Der gibt mir halt nur aus das [10][10] kein Char ist als Warnung funktionieren tut es ja für maximal 5 Züge 😞

    Das ist der Compiler. Wenn du deinen Code im Debugger ausführst, sagt der dir, wo er raus fliegt.
    Da wir in einem C++ Forum sind, könntest du auch über die Verwendung von std::array nachdenken und mit at() zugreifen, das schmeißt eine Exception, wenn du außerhalb deiner Grenzen bist.

    Ich habe keine Lust, deine Logik nachzuvollziehen, aber, wenn du nur erlaubte Züge machst, würde ich mir mal die Randbedingungen anschauen. Vor allem, wenn du einen anderen Stein schlägst, da rechnest du einen Index hoch. Das sieht verdächtig aus.



  • Wichtig für dich vielleicht auch noch: wenn du einmal was falsches eingegeben hast, ist der ifstream "cin" im Failed-Status und nachfolgende Einleseoperationen finden dann nicht mehr statt.

    Schau dir vielleicht mal die Clear-Funktion an:
    http://en.cppreference.com/w/cpp/io/basic_ios/clear
    http://www.cplusplus.com/reference/ios/basic_ios/clear/



  • felix92 schrieb:

    Also quasi [10][10] auf [0][9] ändern ?

    Hä was? NEIN! Du verstehst es wirklich nicht oder? Du legst das Array Board mit 10 Zeilen und 10 Spalten an. Du willst aber später auf die 11. Zeile und die 11. Spalte zugreifen. Wie soll das gehen?! Es wird bei 0 angefangen zu zählen, das heißt dein maximaler Zugriffsbereich ist Board[9][9]...



  • Ich habe folgende Vermutung:
    die COMPILER-Warnmeldung zu dem Feld[10][10] wird hier als DEBUGGER-Fehlermeldung dargestellt. Daher vermutet hier jeder, dass es wirklich um einen Debugger ging, der tatsächlich gar nicht im Spiel war. Ich habs jetzt mal diverse Züge lang gespielt und wenn man keine Fehleingaben macht, kommt man schon weit - es ist bislang nicht abgestürzt. Daher denke ich, dass der Fehler von dem fehlenden Clear nach Fehleingaben und der darauf folgenden Endlosrekursion kommt.

    Mir ist noch was aufgefallen:
    a) Doppelsprünge sind nicht möglich, man kann also nicht 2 Figuren schlagen.
    b) Sprünge sind nicht pflicht. Ich kenne Dame so, dass man schlagen muss, wenn man kann.



  • Ja gut konntest du nicht wissen aber das ist gewollt so laut der Aufgabe 🙂 mein Problem liegt wirklich nur noch darin das der Speicherzugriffsfehler nicht mehr auftritt !? Um ehrlich zu sein verstehe ich auch garnicht warum das passiert bzw. wo der Fehler liegt 😕


Anmelden zum Antworten