Vergleich von zwei lokalen Variablen



  • Hallo Leute,

    ich bin gerade dabei das Spiel "Schere Stein Papier" zu programmieren, stoße aber auf folgendes Problem: Beim Versuch zwei lokale Variablen(jeweils in einer funktion) zu vergleichen(Computers Zug, users zug) scheitere ich, da nicht genügend kenntnisse über funktionen.

    Code-Abschnitte:

    void kiopponent()
    {
    
    	srand(time(0));
    	int ki_decision = 1+(rand()%3);				// 1 = Schere, 2 = Stein, 3 = Papier
    	cout << ki_decision;
    	if(ki_decision == 1)
    		cout << " - Gegner: Schere\n";
    
    int users_decision()
    {
    	cout << "Gib eine Option an(Schere, Stein, Papier): \n";
    	string h_decision;
    	cin >> h_decision;
    	int users_number;
    
    	if(h_decision == "Schere" || "schere")
    	{
    		cout << "Du: Schere   \n";
    		users_number = 1; // Ist nicht unbedingt notwendig, aber was soll's  :)
    

    Vielen Dank für jegliche Hilfe 🙂
    Edit: Das Problem könnte man einfach umgehen, wenn man aus diesen zwei funktionen eine macht, will aber wissen wie man das so löst.

    mfg,


  • Mod

    Die Frage sollte nicht lauten, wie du zwei lokale Variablen vergleichst (das geht nicht). Sie sollte lauten, wie du die Ergebnisse der beiden Funktionen vergleichst. Die Antwort ist, indem du Rückgabewerte benutzt. Wenn du noch nicht weißt, was das ist, wird das sehr bald drankommen.

    Deine Funktionen sind nicht gut gemacht. Eine Funktion sollte genau eine Aufgabe haben. Dein Problem ist teilweise darauf zurück zu führen. Deine Funktionen machen derzeit alles ein bisschen: Eingabe, Ausgabe, Spiellogik, Initialisierung des globalen Zufallsgenerators rand (Das gehört einmal an den Anfang des Programms!), und so weiter.



  • Vielen Dank für deinen Beitrag. Das Funktionen diesen Zweck haben wusste ich nicht, ich weiß aber was Rückgabewerte sind :).
    Ich komme später wieder wenn ich Fragen habe, danke!!!

    mfg,


  • Mod

    Derfragensteller2014nicht schrieb:

    Das Funktionen diesen Zweck haben wusste ich nicht,

    Das ist nicht direkt Zweck oder Pflicht für Funktionen. Es ist aber bewährte Designpraxis und du solltest dich da dran halten. Es erleichtert später vieles, wenn man keine Monsterfunktionen schreibt.



  • Somit sind Funktionen Mittel zur Abstraktion?
    Ich merke gerade das ich gewaltige Wissenslücken bei Funktionen habe, das Kapitel Funktionen sollte ich mich mir mal besser anschauen.
    Wie vergleicht man denn Rückgabewerte?


  • Mod

    Derfragensteller2014nicht schrieb:

    Somit sind Funktionen Mittel zur Abstraktion?

    Ja!

    Wie vergleicht man denn Rückgabewerte?

    Wie vergleichst du andere Werte?



  • SeppJ schrieb:

    Die Frage sollte nicht lauten, wie du zwei lokale Variablen vergleichst (das geht nicht).

    😕


  • Mod

    hustbaer schrieb:

    SeppJ schrieb:

    Die Frage sollte nicht lauten, wie du zwei lokale Variablen vergleichst (das geht nicht).

    😕

    Er meint von außerhalb. Man muss schon mitdenken.



  • SeppJ schrieb:

    Derfragensteller2014nicht schrieb:

    Somit sind Funktionen Mittel zur Abstraktion?

    Ja!

    Wie vergleicht man denn Rückgabewerte?

    Wie vergleichst du andere Werte?

    Mit der if-Anweisung
    Hmm, eben hat es nicht funktioniert. Jetzt komischerweise schon.



  • Ich möchte dich noch auf etwas im Code aufmerksam machen:

    if(h_decision == "Schere" || "schere")
    

    Diese Bedingung ist immer Wahr. Als erstes wird überprüft, ob h_decision den Wert "Schere" hat. Danach wird überprüft, ob "schere" true ist. Da Zeichenkettenliterale in C++ char-Arrays sind und diese zu const char* zerfallen können, prüfst du, ob die Adresse, an der "schere" liegt nicht null ist. Und das ist immer wahr. Du hast also die Wahrheitswerte (egal || true) und wenn ein Teil des Oders wahr ist, ist das ganze Oder wahr.

    Was du sicher wolltest:

    if(h_decision == "Schere" || h_decision == "schere")
    

    Was besser ist:

    std::transform(h_decision.begin(), h_decision.end(), h_decision.begin(), [](char c){return std::tolower(c);});
    if(h_decision == "schere")
    

    Damit bekommst du auch so Fälle wie "ScHeRe" richtig abgefragt.



  • patrick246 schrieb:

    std::transform(h_decision.begin(), h_decision.end(), h_decision.begin(), [](char c){return std::tolower(c);});
    if(h_decision == "schere")
    

    Wieso Lambda?


  • Mod

    Ich hatte zu viel Zeit. Ich habe mich auch absichtlich zurück gehalten und nur ganz niedrige Sprachmittel benutzt. Es ist ganz schön schwierig, so auf ganz niedrigem Abstraktionsniveau, ohne Klassen, STL, Templates & Co. halbwegs sauber zu programmieren 🙂 . So wirklich zufrieden bin ich dann auch nicht. Wenn man häufiger so programmiert, kann man das sicher auch besser:

    #include <iostream>
    #include <string>
    #include <cstdlib>
    #include <ctime>
    
    using namespace std;
    
    enum Gesture
    {
      Rock, Paper, Scissors, Lizard, Spock
    };
    
    const char* gesture_to_string(Gesture gesture)
    {
      if (gesture == Rock) return "Stein";
      if (gesture == Paper) return "Papier";
      if (gesture == Scissors) return "Schere";
      if (gesture == Lizard) return "Echse";
      if (gesture == Spock) return "Spock";
      return "Fehler: Ungültige Geste";
    }
    
    void output_choice(const string &player_name, Gesture choice)
    {
      cout << "Spieler \"" << player_name << "\" hat \"" << gesture_to_string(choice) << "\" gewählt.\n";
    }
    
    Gesture interactive_choice(const string &player_name)
    {
      cout << player_name << " was ist deine Wahl?\n"
        "(1) Stein\n(2) Papier\n(3) Schere\n(4) Echse\n(5) Spock\n\n";
      int choice;
      do 
        {
          cin >> choice;
          if (!cin || choice < 1 || choice > 5)
            {
              cout << "Bitte nur Zahlen zwischen 1 und 5!\n";
              if (!cin)
                {
                  cin.clear();
                  cin.ignore(1);
                  choice = 0;
                }
            }
        }
      while (choice < 1 || choice > 5);
      return static_cast<Gesture>(choice - 1);
    }
    
    Gesture non_interactive_choice()
    {
      return static_cast<Gesture>(rand() % 5);
    }
    
    void print_result(Gesture gesture1, Gesture gesture2)
    {
      const char* const result_string_matrix[5][5] = {
        {   
          /* Rock, Rock */      "Unentschieden.",
          /* Rock, Paper */     "Papier bedeckt Stein.",
          /* Rock, Scissors */  "Stein schleift Schere.",
          /* Rock, Lizard */    "Stein zerquetscht Echse.",
          /* Rock, Spock */     "Spock verdampft Stein."
        },
        {
          /* Paper, Rock */      "Papier bedeckt Stein.",
          /* Paper, Paper */     "Unentschieden.",
          /* Paper, Scissors */  "Schere schneidet Papier.",
          /* Paper, Lizard */    "Echse frisst Papier.",
          /* Paper, Spock */     "Papier widerlegt Spock."
        },
        {
          /* Scissors, Rock */      "Stein schleift Schere.",
          /* Scissors, Paper */     "Schere schneidet Papier.",
          /* Scissors, Scissors */  "Unentschieden.",
          /* Scissors, Lizard */    "Schere köpft Echse.",
          /* Scissors, Spock */     "Spock zertrümmert Schere."
        },
        {
          /* Lizard, Rock */      "Stein zerquetscht Echse.",
          /* Lizard, Paper */     "Echse frisst Papier.",
          /* Lizard, Scissors */  "Schere köpft Echse.",
          /* Lizard, Lizard */    "Unentschieden.",
          /* Lizard, Spock */     "Echse vergiftet Spock."
        },
        {
          /* Spock, Rock */      "Spock verdampft Stein.",
          /* Spock, Paper */     "Papier widerlegt Spock.",
          /* Spock, Scissors */  "Spock zertrümmert Schere.",
          /* Spock, Lizard */    "Echse vergiftet Spock.",
          /* Spock, Spock */     "Unentschieden."
        }};
    
      cout << result_string_matrix[gesture1][gesture2] << '\n';
    }
    
    int get_winner(Gesture gesture1, Gesture gesture2)
    {
      const int winner_matrix[5][5] = {
        {0, 2, 1, 1, 2},
        {1, 0, 2, 2, 1},
        {2, 1, 0, 1, 2},
        {2, 1, 2, 0, 1},
        {1, 2, 1, 2, 0}
      };
      return winner_matrix[gesture1][gesture2];
    }
    
    void print_winner(int winner, const string& player1, const string& player2)
    {
      if (winner == 0) { cout << "Kein Spieler gewinnt.\n\n"; };
      if (winner == 1) { cout << '"' << player1 << "\" gewinnt.\n\n"; };
      if (winner == 2) { cout << '"' << player2 << "\" gewinnt.\n\n"; };
    }
    
    void one_player_game(const std::string &player1)
    {
      const string player2 = "KI";
      Gesture gesture1 = interactive_choice(player1);
      Gesture gesture2 = non_interactive_choice();
      output_choice(player1, gesture1);
      output_choice(player2, gesture2);
      print_result(gesture1, gesture2);
      print_winner(get_winner(gesture1, gesture2), player1, player2);
    }
    
    int main()
    {
      srand(time(0));
      std::string name;
      cout << "Name? ";
      getline(cin, name);
      cout << '\n';
    
      char another_game;
      do
        {
          one_player_game(name);
          cout << "Noch ein Spiel? J/j für Ja, alles andere für Nein. ";
        }
      while ((cin >> another_game) && (another_game == 'j' || another_game == 'J'));
    }
    

    Die KI ist übrigens ungeheuer spielstark und hat mich bei einem Testspiel von 15 Runden 12x besiegt (davon 9x in Folge!) und 2x Unentschieden mit nur einem Sieg für mich. Also nur etwas für Hardcoregamer! 🕶



  • @SeppJ
    Du könntest die KI wohl noch deutlich boosten indem du ihr nen starken Hang zu Echse und Papier verpasst 😉



  • Arcoth schrieb:

    hustbaer schrieb:

    SeppJ schrieb:

    Die Frage sollte nicht lauten, wie du zwei lokale Variablen vergleichst (das geht nicht).

    😕

    Er meint von außerhalb. Man muss schon mitdenken.

    Ah. Ich hatte übersehen dass der OP genau das machen wollte. Was natürlich nicht geht, klar.


  • Mod

    hustbaer schrieb:

    @SeppJ
    Du könntest die KI wohl noch deutlich boosten indem du ihr nen starken Hang zu Echse und Papier verpasst 😉

    😃

    Gesture strong_non_interactive_choice()
    {
      bool kill_spock = rand() % 2;
      if (kill_spock)
        {
          bool lizard = rand() % 2;
          if (lizard) return Lizard; else return Paper;
        }
      return static_cast<Gesture>(rand() % 5);
    }
    


  • Nathan schrieb:

    patrick246 schrieb:

    std::transform(h_decision.begin(), h_decision.end(), h_decision.begin(), [](char c){return std::tolower(c);});
    if(h_decision == "schere")
    

    Wieso Lambda?

    Weil gcc den Typ von std::tolower nicht bestimmen wollte. Das lambda hat er aber gleich geschluckt und ich wollte mich nicht lange damit rumärgern.



  • Das liegt daran dass tolower überladen ist.
    int tolower(int); aus <cctype> und
    `template<class T>

    T tolower(T, const locale&);aus<locale>`

    Wenn man dann einfach nur tolower schreibt kann der Compiler ja nicht wissen welcher Overload gemeint ist - gibt ja keine Parameterliste anhand derer er Overload-Resolution machen könnte.

    -> Wenn nötig kann man es über nen static_cast<FunctionReferenceType>(FunctionName) eindeutig machen.
    http://ideone.com/vBDDjr



  • SeppJ schrieb:

    Es ist ganz schön schwierig, so auf ganz niedrigem Abstraktionsniveau, ohne Klassen, STL, Templates & Co. halbwegs sauber zu programmieren 🙂 .

    Ist doch supi geworden. Die meisten hauen so lange Abstraktion rein, bis die allein im Vordergrund steht.

    Hab ein paar Mini-Anregungen.

    [/quote]

    #include <iostream>
    #include <string>
    #include <cstdlib>
    #include <ctime>
    
    using namespace std;
    
    enum Gesture//Auf Englisch programmiert? Puh.
    {//Hätte "Move" als Name genommen, damit es den ganzen anderen games ähnlicher ist.
      Rock, Paper, Scissors, Lizard, Spock
    };//Was bringt dieses enum? Mir scheint, ein int ist gemeint.
    
    //Ich habe mir angewöhnt, das letzte Komma immer zu setzen, weil dann das Umsortieren
    //mit weniger Nachdenken geht.
    //{
    //  Rock, Paper, Scissors, Lizard, Spock,
    //};
    
    //Die komische Reihenfolge aus BigBangTheory und nicht die hübscha vom Original.
    //http://www.samkass.com/theories/RPSSL.html
    
    const char* gesture_to_string(Gesture gesture)
    {//Hier wäre switch angebracht.
      if (gesture == Rock) return "Stein";
      if (gesture == Paper) return "Papier";
      if (gesture == Scissors) return "Schere";
      if (gesture == Lizard) return "Echse";
      if (gesture == Spock) return "Spock";
      return "Fehler: Ungültige Geste";
      //Aber eigentlich wolltest Du in einem Array nachschauen.
      //Wird fast verhindert durch das enum.
      //Oder Du müßtest die Werte festnageln mit
      //{
      //  Rock=0, Paper=1, Scissors=2, Lizard=3, Spock=4
      //};//Was bringt dieses enum?
    
      //Übrigens das letzte mal, daß das enum verwendet wird!
    }
    
    void output_choice(const string &player_name, Gesture choice)
    {
      cout << "Spieler \"" << player_name << "\" hat \"" << gesture_to_string(choice) << "\" gewählt.\n";
    }
    
    Gesture interactive_choice(const string &player_name)
    {//Ob interactive oder nicht ist nicht der fette Bedeutungsträger.
    //Es spielen Mensch gegen Computer und das hier ist der Zug des Menschen.
    //Die Funktion hat drei Zwecke oder so.
      cout << player_name << " was ist deine Wahl?\n"
        "(1) Stein\n(2) Papier\n(3) Schere\n(4) Echse\n(5) Spock\n\n";
      int choice;
      do
        {
          cin >> choice;
          if (!cin || choice < 1 || choice > 5)
            {
              cout << "Bitte nur Zahlen zwischen 1 und 5!\n";
              if (!cin)
                {
                  cin.clear();
                  cin.ignore(1);
                  choice = 0;//so steuert man eigentlich nicht. 
                }
            }
        }
      while (choice < 1 || choice > 5);//die Bedingung war oben schonmal
      return static_cast<Gesture>(choice - 1);//*angst*
      //Aha, enum-Werte doch festnageln. Und das erklärt die TBBT-Reihenfolge.
      //Die gesture_to_string() bzw gesture_to_output() hat kein pendant input_to_gesture().
    }
    
    Gesture non_interactive_choice()
    {//Und das hier der Zug des Computers.
      return static_cast<Gesture>(rand() % 5);
      //Irgendwie lebt ein int in dem enum. 
    }
    
    void print_result(Gesture gesture1, Gesture gesture2)
    {
      const char* const result_string_matrix[5][5] = {
        {
          /* Rock, Rock */      "Unentschieden.",
          /* Rock, Paper */     "Papier bedeckt Stein.",
          /* Rock, Scissors */  "Stein schleift Schere.",
          /* Rock, Lizard */    "Stein zerquetscht Echse.",
          /* Rock, Spock */     "Spock verdampft Stein."
        },
        {
          /* Paper, Rock */      "Papier bedeckt Stein.",
          /* Paper, Paper */     "Unentschieden.",
          /* Paper, Scissors */  "Schere schneidet Papier.",
          /* Paper, Lizard */    "Echse frisst Papier.",
          /* Paper, Spock */     "Papier widerlegt Spock."
        },
        {
          /* Scissors, Rock */      "Stein schleift Schere.",
          /* Scissors, Paper */     "Schere schneidet Papier.",
          /* Scissors, Scissors */  "Unentschieden.",
          /* Scissors, Lizard */    "Schere köpft Echse.",
          /* Scissors, Spock */     "Spock zertrümmert Schere."
        },
        {
          /* Lizard, Rock */      "Stein zerquetscht Echse.",
          /* Lizard, Paper */     "Echse frisst Papier.",
          /* Lizard, Scissors */  "Schere köpft Echse.",
          /* Lizard, Lizard */    "Unentschieden.",
          /* Lizard, Spock */     "Echse vergiftet Spock."
        },
        {
          /* Spock, Rock */      "Spock verdampft Stein.",
          /* Spock, Paper */     "Papier widerlegt Spock.",
          /* Spock, Scissors */  "Spock zertrümmert Schere.",
          /* Spock, Lizard */    "Echse vergiftet Spock.",
          /* Spock, Spock */     "Unentschieden."
        }};
    //Jede Geste kann zwei andere zerstören. Ob man irgendwie das 
    //Zerstörungsverb abfragen könnte und daraus auch die folgende get_winner() basteln? 
      cout << result_string_matrix[gesture1][gesture2] << '\n';
    }
    
    int get_winner(Gesture gesture1, Gesture gesture2)
    {
      const int winner_matrix[5][5] = {
        {0, 2, 1, 1, 2},
        {1, 0, 2, 2, 1},
        {2, 1, 0, 1, 2},
        {2, 1, 2, 0, 1},
        {1, 2, 1, 2, 0}
      };
      return winner_matrix[gesture1][gesture2];
    //Hmm, unten die winner_matrix wäre hübscher mit der Original-Reihenfolge.
    //    {0, 2, 1, 2, 1},
    //    {1, 0, 2, 1, 2},
    //    {2, 1, 0, 2, 1},
    //    {1, 2, 1, 0, 2}
    //    {2, 1, 2, 1, 0},
    }
    /*
    int get_winner(Gesture gesture1, Gesture gesture2,string& vaporization_method)
    {
       vaporization_method=get_vaporization_method(gesture1,gesture2);
       if(vaporization_method!="") return 1;
       vaporization_method=get_vaporization_method(gesture2,gesture1);
       if(vaporization_method!="") return 2;
       return 0;
    }
    */
    
    void print_winner(int winner, const string& player1, const string& player2)
    {
      if (winner == 0) { cout << "Kein Spieler gewinnt.\n\n"; };
      if (winner == 1) { cout << '"' << player1 << "\" gewinnt.\n\n"; };
      if (winner == 2) { cout << '"' << player2 << "\" gewinnt.\n\n"; };
    }
    
    void one_player_game(const std::string &player1)
    {
      const string player2 = "KI";
      Gesture gesture1 = interactive_choice(player1);
      Gesture gesture2 = non_interactive_choice();
      output_choice(player1, gesture1);
      output_choice(player2, gesture2);
      print_result(gesture1, gesture2);
      print_winner(get_winner(gesture1, gesture2), player1, player2);
    }
    
    int main()
    {
      srand(time(0));
      std::string name;
      cout << "Name? ";
      getline(cin, name);
      cout << '\n';
    
      char another_game;
      do
        {
          one_player_game(name);
          cout << "Noch ein Spiel? J/j für Ja, alles andere für Nein. ";
        }
      while ((cin >> another_game) && (another_game == 'j' || another_game == 'J'));
    }
    


  • Vielen Dank das du dir dafür Zeit genommen hast :).
    Wie ich sehe haben wir hier BBT fans 😃


Log in to reply