Hangman

Hallo zusammen,
ich hoffe ich bin hier richtig und mir kann jemand weiter helfen.
Und zwar möchte ich das Spiel Hangman im Java Editor programmieren.
Ich habe auch schon einiges gemacht aber so ganz will es doch noch nicht funktionieren. Kann mir bitte jemand sagen woran es liegt ? Oder den Fehler vlt direkt verbessern ?
Ich weiß das es bestimmt auch einfachere Wege geben würde wie meinen. Aber ich bin Anfänger und bekomme es nicht besser hin.

Das Hauptproblem ist falsche und gleiche Buchstaben zu erkennen.
Ich programmiere mit Java Editor.
Wenn ihr Lösungen habt, dann bitte auf dem selben Niveau das ihr hier seht.

Java:
/**
  *
  * Beschreibung
  *
  * @version 1.0 vom 25.06.2019
  * @author
  */
   import java.util.Scanner;
   import java.util.Arrays; 

public class Hangman2 {
 
  public static void main(String[] args) {
    
    
    Scanner tastatur;
    tastatur = new Scanner(System.in);
    
    String benutzerwort;
    String buchstabe;
    int leben = 3;
    boolean weiter = true;
    boolean richtig = false;
    
    //Begrüßung und Worteingabe
    System.out.println("Wilkommen bei Hangman. \n\nDein Ziel ist es das Wort zu erraten. Gibst du einen falschen Buchstaben ein, verlierst du ein Leben. \nDu hast insgesamt " + leben + " Leben. Viel Spaß!");
    System.out.print("\nGibt das zu erratene Wort ein: ");
    
    benutzerwort = tastatur.next();                 
    String wort[] = benutzerwort.split("");
    
    String errateneBuchstaben[] = new String [wort.length];
    String errateneBuchstaben1[] = new String [wort.length];
    System.out.println("-----------------------------------------------------------------------------------------------------------------------");
    for (int i = 0 ;i < errateneBuchstaben.length; i++ ) {
      errateneBuchstaben[i] = " _ ";
      
    } // end of for
    
    
    while (weiter) {
      for (int i=0 ;i < errateneBuchstaben.length; i++ ) {
        System.out.print(errateneBuchstaben[i]);
         errateneBuchstaben1[i] = errateneBuchstaben[i];
      } // end of for
      System.out.println("\nDu hast noch " + leben + " Leben.");
      System.out.print("\nGib ein Buchstabe ein: ");
      buchstabe = tastatur.next();
      
      for (int i=0; i<wort.length; i++ ) {
        if (buchstabe.equalsIgnoreCase(wort[i])) {
           errateneBuchstaben[i] = wort[i];
          if (Arrays.equals(errateneBuchstaben, errateneBuchstaben1)) {
            System.out.println("Diesen Buchstaben hast du schon eingegeben");
            richtig = false;
            
          } // end of if
          else {
            errateneBuchstaben[i] = wort[i];
            richtig = true;
            
          } // end of if-else
        } // end of if
        
        
      } // end of for
      if (richtig) {
        if (Arrays.equals(errateneBuchstaben,wort)) {
          System.out.println("Herzlichen Glückwunsch! Du hast das Wort erraten und gewonnen.");
          weiter = false;

        } // end of if
        
      } // end of if
      
      else {
         leben--;
          if (leben==0) {
            System.out.println("Du hast keine Leben mehr und verloren!");
            weiter = false;
          } // end of if
      } // end of if-else
      
      /*for (int i = 0 ;i < errateneBuchstaben1.length; i++ ) {
        errateneBuchstaben1[i] = errateneBuchstaben[i];
        
        
      } // end of for */
      
    } // end of while
    
    
    
    
    
  } // end of main

} // end of class Hangman2

Danke schonmal im Vorraus!
 
Tut mir leid. Meine Rechschreibung ist nicht gut.
Es erkennt nicht wenn ein gleicher Buchstabe eingegeben wird oder ein falscher.
Bzw. erkennt einen gleichen Buchstaben auch als falschen Buchstaben an.
 
K

kneitzel

Gast
Also Dein Fehler scheint zu sein, dass du die Variable richtig nur auf true setzt aber nicht auf false wenn das Ergebnis falsch ist.

Du könntest die Variable richtig immer nach dem Lesen eines Zeichens von der Tastatur auf false setzen.

Oder, da die Variable ja nur in der Schleife benötigt wird, deklarierst Du diese auch erst dort.

Das Ergebnis könnte da wie folgt aussehen:
Java:
   import java.util.Scanner;
   import java.util.Arrays;

public class Hangman2 {

  public static void main(String[] args) {
   
   
    Scanner tastatur;
    tastatur = new Scanner(System.in);
   
    String benutzerwort;
    String buchstabe;
    int leben = 3;
    boolean weiter = true;
    //boolean richtig = false;
   
    //Begrüßung und Worteingabe
    System.out.println("Wilkommen bei Hangman. \n\nDein Ziel ist es das Wort zu erraten. Gibst du einen falschen Buchstaben ein, verlierst du ein Leben. \nDu hast insgesamt " + leben + " Leben. Viel Spaß!");
    System.out.print("\nGibt das zu erratene Wort ein: ");
   
    benutzerwort = tastatur.next();                
    String wort[] = benutzerwort.split("");
   
    String errateneBuchstaben[] = new String [wort.length];
    String errateneBuchstaben1[] = new String [wort.length];
    System.out.println("-----------------------------------------------------------------------------------------------------------------------");
    for (int i = 0 ;i < errateneBuchstaben.length; i++ ) {
      errateneBuchstaben[i] = " _ ";
     
    } // end of for
    while (weiter) {
      for (int i=0 ;i < errateneBuchstaben.length; i++ ) {
        System.out.print(errateneBuchstaben[i]);
         errateneBuchstaben1[i] = errateneBuchstaben[i];
      } // end of for
      System.out.println("\nDu hast noch " + leben + " Leben.");
      System.out.print("\nGib ein Buchstabe ein: ");
      buchstabe = tastatur.next();
     
      boolean richtig=false; // Setze richtig auf false als default Wert!    
      for (int i=0; i<wort.length; i++ ) {
        if (buchstabe.equalsIgnoreCase(wort[i])) {
          errateneBuchstaben[i] = wort[i];
          if (Arrays.equals(errateneBuchstaben, errateneBuchstaben1)) {
            System.out.println("Diesen Buchstaben hast du schon eingegeben");
            // richtig = false; // Unnötig, da default false ist.
           
          } // end of if
          else {
            // errateneBuchstaben[i] = wort[i]; Wurde schon oben gemacht!
            richtig = true;
           
          } // end of if-else
        } // end of if
       
      } // end of for
      if (richtig) {
        if (Arrays.equals(errateneBuchstaben,wort)) {
          System.out.println("Herzlichen Glückwunsch! Du hast das Wort erraten und gewonnen.");
          weiter = false;

        } // end of if
       
      } // end of if
     
      else {
         leben--;
          if (leben==0) {
            System.out.println("Du hast keine Leben mehr und verloren!");
            weiter = false;
          } // end of if
      } // end of if-else
     
      /*for (int i = 0 ;i < errateneBuchstaben1.length; i++ ) {
        errateneBuchstaben1[i] = errateneBuchstaben[i];
       
       
      } // end of for */
     
    } // end of while
  } // end of main
} // end of class Hangman2

Hab da in dem einen else auch noch eine Zeile auskommentiert. Dieser Befehl wurde ja vor dem if eh schon gemacht, daher muss das nicht noch einmal gemacht werden.

Das eine richtig=false wurde nur ausgeführt, wenn der Buchstabe bereits eingegeben wurde.
Und wegen der Rechtschreibung: Deine Beiträge sind gut lesbar, daher ist das vollkommen ok.

Was mich noch interessiert:
Wenn der Spieler zwei Mal einen richtigen Buchstaben eingibt: Ist die zweite Eingabe dann ein Fehler oder soll das nicht als Fehler gezählt werden? Eigentlich sollte es doch nicht als Fehler gezählt werden. Wenn es nicht als Fehler gezählt werden soll, dann müsste das richtig=false aus der else Schleife raus.
 
Also Dein Fehler scheint zu sein, dass du die Variable richtig nur auf true setzt aber nicht auf false wenn das Ergebnis falsch ist.

Du könntest die Variable richtig immer nach dem Lesen eines Zeichens von der Tastatur auf false setzen.

Oder, da die Variable ja nur in der Schleife benötigt wird, deklarierst Du diese auch erst dort.

Das Ergebnis könnte da wie folgt aussehen:
Java:
   import java.util.Scanner;
   import java.util.Arrays;

public class Hangman2 {

  public static void main(String[] args) {
  
  
    Scanner tastatur;
    tastatur = new Scanner(System.in);
  
    String benutzerwort;
    String buchstabe;
    int leben = 3;
    boolean weiter = true;
    //boolean richtig = false;
  
    //Begrüßung und Worteingabe
    System.out.println("Wilkommen bei Hangman. \n\nDein Ziel ist es das Wort zu erraten. Gibst du einen falschen Buchstaben ein, verlierst du ein Leben. \nDu hast insgesamt " + leben + " Leben. Viel Spaß!");
    System.out.print("\nGibt das zu erratene Wort ein: ");
  
    benutzerwort = tastatur.next();               
    String wort[] = benutzerwort.split("");
  
    String errateneBuchstaben[] = new String [wort.length];
    String errateneBuchstaben1[] = new String [wort.length];
    System.out.println("-----------------------------------------------------------------------------------------------------------------------");
    for (int i = 0 ;i < errateneBuchstaben.length; i++ ) {
      errateneBuchstaben[i] = " _ ";
    
    } // end of for
    while (weiter) {
      for (int i=0 ;i < errateneBuchstaben.length; i++ ) {
        System.out.print(errateneBuchstaben[i]);
         errateneBuchstaben1[i] = errateneBuchstaben[i];
      } // end of for
      System.out.println("\nDu hast noch " + leben + " Leben.");
      System.out.print("\nGib ein Buchstabe ein: ");
      buchstabe = tastatur.next();
    
      boolean richtig=false; // Setze richtig auf false als default Wert!   
      for (int i=0; i<wort.length; i++ ) {
        if (buchstabe.equalsIgnoreCase(wort[i])) {
          errateneBuchstaben[i] = wort[i];
          if (Arrays.equals(errateneBuchstaben, errateneBuchstaben1)) {
            System.out.println("Diesen Buchstaben hast du schon eingegeben");
            // richtig = false; // Unnötig, da default false ist.
          
          } // end of if
          else {
            // errateneBuchstaben[i] = wort[i]; Wurde schon oben gemacht!
            richtig = true;
          
          } // end of if-else
        } // end of if
      
      } // end of for
      if (richtig) {
        if (Arrays.equals(errateneBuchstaben,wort)) {
          System.out.println("Herzlichen Glückwunsch! Du hast das Wort erraten und gewonnen.");
          weiter = false;

        } // end of if
      
      } // end of if
    
      else {
         leben--;
          if (leben==0) {
            System.out.println("Du hast keine Leben mehr und verloren!");
            weiter = false;
          } // end of if
      } // end of if-else
    
      /*for (int i = 0 ;i < errateneBuchstaben1.length; i++ ) {
        errateneBuchstaben1[i] = errateneBuchstaben[i];
      
      
      } // end of for */
    
    } // end of while
  } // end of main
} // end of class Hangman2

Hab da in dem einen else auch noch eine Zeile auskommentiert. Dieser Befehl wurde ja vor dem if eh schon gemacht, daher muss das nicht noch einmal gemacht werden.

Das eine richtig=false wurde nur ausgeführt, wenn der Buchstabe bereits eingegeben wurde.
Und wegen der Rechtschreibung: Deine Beiträge sind gut lesbar, daher ist das vollkommen ok.

Was mich noch interessiert:
Wenn der Spieler zwei Mal einen richtigen Buchstaben eingibt: Ist die zweite Eingabe dann ein Fehler oder soll das nicht als Fehler gezählt werden? Eigentlich sollte es doch nicht als Fehler gezählt werden. Wenn es nicht als Fehler gezählt werden soll, dann müsste das richtig=false aus der else Schleife raus.
Super vielen Dank.
Ja genau, bei einem doppelt eingegebenen Buchstaben soll nur die Fehlermeldung dem Spieler angezeigt werden, aber kein Fehler gezählt werden.
Wo genau muss ich da was ändern? Wenn ich richtig = false aus else raus mache, erkennt es mir gar keine Fehler mehr.
 

mihe7

Top Contributor
@FragenÜberFragen das Problem ist, dass Du versuchst, mit einer einzigen booleschen Variable auf einen Schlag mehr als zwei Fälle abzudecken:
1. Buchstabe kommt im gesuchten Wort vor und ist in der Lösung noch nicht vorhanden.
2. Buchstabe kommt im gesuchten Wort vor und ist in der Lösung bereits vorhanden
3. Buchstabe kommt im gesuchten Wort nicht vor
4. Wort wurde vollständig erraten, d. h. Wort und Lösung stimmen überein

Bei den Fällen 1 bis 3 geht es grundsätzlich darum, ob der Buchstabe im gesuchten Wort vorkommt.

Eine Skizze zu einem Algorithmus zur Abdeckung aller Fälle könnte so aussehen:
Code:
sicherung := Kopie von lösung
ermittle alle Vorkommen von buchstabe in wort und ersetze die entsprechenden Zeichen in lösung
Wurde dabei wenigstens ein Zeichen ersetzt?
Ja:
    Sind sicherung und lösung identisch?
    Ja:
        Gib Meldung aus, dass der Buchstabe bereits einmal eingegeben wurde
    Nein:
        Sind lösung und wort identisch?
        Ja: ENDE
Nein (es wurde kein Zeichen ersetzt):
    Behandle Fehleingabe
    Sind weitere Eingaben möglich?
    Nein: ENDE

Der wesentlichen Punkte sind dabei das Finden von Vorkommen von buchstabe in wort, die Ersetzung in lösung und die Information, ob wenigstens ein Zeichen ersetzt wurde. Das ist aber recht einfach:
Java:
boolean richtig = false;
for (int i=0; i<wort.length; i++ ) {
    if (buchstabe.equalsIgnoreCase(wort[i])) {
        errateneBuchstaben[i] = wort[i];
        richtig = true;
    }
}
Die Information, ob wenigstens ein Zeichen ersetzt wurde, steckt damit in der Variablen "richtig". Also kann der Algorithmus weiter umgesetzt werden, im Anschluss an den Code oben folgt:
Java:
if (richtig) {
    if (Arrays.equals(errateneBuchstaben, errateneBuchstaben1)) {
        System.out.println("Diesen Buchstaben hast du schon eingegeben");
    } else if (Arrays.equals(errateneBuchstaben,wort)) {
        System.out.println("Herzlichen Glückwunsch! Du hast das Wort erraten und gewonnen.");
        weiter = false;
    }  
} else {
    leben--;
    if (leben == 0) {
        System.out.println("Du hast keine Leben mehr und verloren!");
        weiter = false;
    }
}
 
K

kneitzel

Gast
Ich bin schockiert und führe das mal auf die unerträgliche Hitze zurück :p
Ja, zusammen mit der späten Stunde. Aber es wurde einfach nicht kühl genug zum schlafen ...

@FragenÜberFragen Die Ausführungen von @mrBrown waren ja recht ausführlich. Meine Überlegung war, den else Block um dem richtig = true; zu entfernen. Also sowas:
Java:
          if (Arrays.equals(errateneBuchstaben, errateneBuchstaben1)) {
            System.out.println("Diesen Buchstaben hast du schon eingegeben");
            // richtig = false;
           
          } // end of if
          // else {
            // errateneBuchstaben[i] = wort[i]; Wurde schon oben gemacht!
            richtig = true;
           
          // } // end of if-else

Die Variable richtig speichert damit nur die zwei Fälle:
- Geratener Buchstabe kommt vor
- Geratener Buchstabe kommt nicht vor

Ach ja: ganz wichtig ist in meinen Augen, dass man den Code etwas aufräumt. Ich habe Zeilen einfach auskommentiert. Das ist eigentlich ein Unding - die Zeilen löscht man dann richtig.
Wenn das Einrücken richtig ist, dann braucht man auch am Ende eines Blocks keinen Kommentar, was beendet wurde. Der Kommentar kann also gelöscht werden.

Damit es übersichtlicher wird, kann man dann die Methode in mehrere Methoden aufteilen. Und Variablen kann man noch so umbenennen, dass man besser versteht, was da drin ist. Eine 1 anhängen ist z.B. immer eine schlechte Idee. Statt dessen könnte man z.B. "Kopie" oder so sagen, aber ich selbst finde es besser lesbar, wenn man auf sowas evtl. ganz verzichtet.
Hier dient es ja nur, um zu erkennen, ob ein Buchstabe geändert wurde, d.h. du machst
- eine Kopie des Arrays (immer!)
- prüfst alle Werte der beiden Arrays miteinander (bei richtig geratenem Buchstaben)
Statt dessen wäre es doch einfacher, wenn man sich das alles sparen würde und man nur den überein stimmenden Buchstaben bei richtig geratenem Buchstaben prüft

So eine Funktion zusammen mit einer Enumeration für das Ergebnis könnte dann z.B so aussehen:
Java:
  /**
   * Führt den Rate-Vorgang für eine definierte Stelle des Wortes aus und gibt nach einer ggf notwendigen Anpassung des
   * bisherigen Ergebnisses das Ergebnis des Rate-Vorgangs zurück.
   * @param originalWort Das zu eratene Wort.
   * @param bisherigesErgebnis Das bisherige Ergebnis.
   * @param geratenerBuchstabe Der geratene Buchstabe.
   * @param position Die Position, die geprüft werden soll.
   * @return Ergebnis des Rate-Vorgangs (doppelt erraten, richtig erraten oder falsch geraten).
   */
  static private Ergebnis rateBuchstabe(String[] originalWort, String[] bisherigesErgebnis, String geratenerBuchstabe, int position) {
    if (originalWort[position].equals(geratenerBuchstabe)) {
      if (bisherigesErgebnis[position].equals(geratenerBuchstabe)) {
        return Ergebnis.BUCHSTABE_DOPPELT_ERRATEN;
      }
     
      bisheriges_Ergebnis[position] = geratenerBuchstabe;
      return Ergebnis.BUCHSTABE_RICHTIG_ERRATEN;
    }
   
    return Ergebnis.BUCHSTABE_FALSCH_GERATEN;
  }

  /**
   * Ergebnis eines Rate-Vorgangs
   */
  enum Ergebnis {
    /**
     * Es wurde ein Buchstabe richtig erraten.
     */
    BUCHSTABE_RICHTIG_ERRATEN,

    /**
     * Ein vorhandener Buchstabe wurde erneut geraten.
     */
    BUCHSTABE_DOPPELT_ERRATEN,

    /**
     * Der geratene Bichstabe kommt nicht im Wort vor.
     */
    BUCHSTABE_FALSCH_GERATEN
  }

Die Methode ist hier jetzt auch noch static. Generell sollte man versuchen, von statischen Methoden weg zu kommen. Aber ich habe das halt als erste Umformung geschrieben - mit dem ganzen Code noch in der statischen main Methode.

Ich hoffe, dass dies nicht zu viel für den Anfang war. Aber ich wollte mal einen kleinen Anreiz setzen, dass man dies weiter verschönert und Du dies vielleicht dazu nutzt, noch mehr Elemente der Java Sprache zu erlernen...
 
Ah okey. Super vielen Dank.
Jetzt läuft das Programm so wie ich mir das vorstelle. : )
Ich wollte in dem Fall in einer If zu viele Fälle gleichzeitig abdecken. Mit euren Veränderungen funktioniert es jetzt und es wird alles richtig erkannt.

Das mit den mehreren Methoden werde ich mir mal anschauen und vlt in meiner nächsten Programmierung verwenden.


Hat jetzt zufällig noch jemand eine Idee wie ich die Oberfläche dazu mit GUI gestalte?
(Hoffe das führt hier jetzt nicht zu weit)
 

mihe7

Top Contributor
Hat jetzt zufällig noch jemand eine Idee wie ich die Oberfläche dazu mit GUI gestalte?
(Hoffe das führt hier jetzt nicht zu weit)
Das führt tatsächlich zu weit. Eine GUI zu programmieren, macht erst Sinn, wenn man die Grundlagen halbwegs drauf hat. Was Du machen kannst: JOptionPane.showInputDialog für die Eingabe und JOptionPane.showMessageDialog für die Ausgabe verwenden. Die Dialoge sind modal, so dass Du sie direkt in Deinem Code einsetzen kannst.

Doku siehe https://docs.oracle.com/javase/8/docs/api/index.html?javax/swing/JOptionPane.html und https://docs.oracle.com/javase/tutorial/uiswing/components/dialog.html
 
Das führt tatsächlich zu weit. Eine GUI zu programmieren, macht erst Sinn, wenn man die Grundlagen halbwegs drauf hat. Was Du machen kannst: JOptionPane.showInputDialog für die Eingabe und JOptionPane.showMessageDialog für die Ausgabe verwenden. Die Dialoge sind modal, so dass Du sie direkt in Deinem Code einsetzen kannst.

Doku siehe https://docs.oracle.com/javase/8/docs/api/index.html?javax/swing/JOptionPane.html und https://docs.oracle.com/javase/tutorial/uiswing/components/dialog.html
Okey danke.
Auch das schau ich mir mal an.
 

Ähnliche Java Themen

Neue Themen


Oben