Aufgabe: Im Folgenden ist der Code des selbstlernenden Spiels „Tiere Raten“ abgedruckt. Der Code ist noch nicht lauffähig. Damit das Spiel gespielt werden kann, müssen in der Klasse „Tiere Raten“ einige Dinge ergänzt werden. Hinweise zu der Farbwahl der Texte/Wörter: Orange ist angegeben, wo etwas ergänzt werden soll. Einige Abschnitte sind grau gedruckt. Um den Code ergänzen zu können, ist es nicht notwendig, dass diese verstanden werden. Methoden sind rot angegeben. Die Aufrufe der Methoden, sind in grünem Text gedruckt. Kommentare sind blau geschrieben. 1 Klasse "Frageknoten" import java.util.StringTokenizer; public class Frageknoten { int fragenummer; String frage; boolean istAntwortJ; String antwortJ; int fragenummerJ; boolean istAntwortN; String antwortN; int fragenummerN; // Die Parameter werden dem Frageknoten übergeben und den Variablen zugeordnet. public Frageknoten(int neueFragenummer, String neueFrage, String neueAntwortJ, String neueAntwortN) { fragenummer = neueFragenummer; frage = neueFrage; istAntwortJ = true; antwortJ = neueAntwortJ; istAntwortN = true; antwortN = neueAntwortN; } 2 // Hier werden die Parameter für oben eingelesen - bzw. übergeben. Es wird eine Tabelle von der Form | fragenummer | frage | istAntwort für ja | Antwort oder neueFragenummer | istAntwort für nein | Antwort oder neueFragenummer | eingelesen. Achtun: Hier haben wir einen anderen „Fragknoten“ als oben – es werden andere Parameter übergeben. public Frageknoten(String zeile) { //Der StringTokenizer liest eine Zeile ein - von ; zu ;. StringTokenizer st = new StringTokenizer(zeile, ";"); //Der erste eingelesene String wird in einen int umgewandelt und als fragenummer abgespeichert fragenummer = Integer.parseInt(st.nextToken()); //Der nächste String wird auf "frage" abgespeichert. frage = st.nextToken(); //Der nächste String wird auf faJ abgespeichert. String faJ = st.nextToken(); //Je nachdem, ob faJ "F" oder etwas anderes lautet, wird "istAntwortJ" auf true oder false gesetzt. if (faJ.equals("F")) istAntwortJ = false; else istAntwortJ = true; //Wenn die Antwort gegeben werden kann, kann diese auf antwortJ gesetzt werden, sonst wird die neue Fragenummer gegeben. if (istAntwortJ) antwortJ = st.nextToken(); else fragenummerJ = Integer.parseInt(st.nextToken()); String faN = st.nextToken(); if (faN.equals("F")) istAntwortN = false; else istAntwortN = true; 3 if (istAntwortN) antwortN = st.nextToken(); else fragenummerN = Integer.parseInt(st.nextToken()); } //Aufbau der Zeile String alsZeile() { String zeile = ""; zeile += fragenummer + ";"; zeile += frage + ";"; if (istAntwortJ) zeile += "A;" + antwortJ; else zeile += "F;" + fragenummerJ; zeile += ";"; if (istAntwortN) zeile += "A;" + antwortN; else zeile += "F;" + fragenummerN; return zeile; } } 4 Klasse "TiereRaten" // Die Fragen sind unter "fragen.txt" gespeichert. Ganz einfache Startfragen sind unter "frage2.txt" gespeichert. import java.io.*; import java.util.TreeMap; import java.util.Scanner; import java.util.Iterator; public class TiereRaten { //Wir betrachten den Knoten der aktuellen Frage Frageknoten aktuelleFrage; //Liste, in welcher alle Fragen zwischengespeichert werden TreeMap fragen; //brauchen wir, um eingegebenen Text einzulesen Scanner scanner = new Scanner(System.in); public TiereRaten(String dateiname) { // Damit wird das Teminal bei einem Neustart wieder geleert. System.out.print((char) 12); //Hier wird das eigentliche Spiel aufgerufen. Es wird nach dem Dateinamen gefragt, damit man weiss, welche Datei eingelesen werden soll. Methode ergänzen(dateiname); } void spielen(String dateiname) { //Das Try braucht es nur, damit man allfällige Fehler beim Einlesen abfangen kann: catch try { //Es wird ein "TreeMap" erstellt, in welchem dann die Fragen abgelegt werden. fragen = new TreeMap(); //Es wird beim Einlesen der Fragen gefragt, aus welcher Datei die Fragen übernommen werden sollen: dateiname Methode ergänzen(dateiname); 5 while(true) { //Das eigentliche Spiel Methode ergänzen (); Methode ergänzen (); if (Methode ergänzen ()==false) break; } } //Gibt an, falls es beim Einlesen einen Fehler gibt. Wenn dies im "Try" geschieht. catch (IOException e) { e.printStackTrace(); //Dies wird bei einem Einlesefehler ausgegeben. System.out.println("Beim Einlesen ist ein Fehler aufgetreten."); } } //Es wird gefragt, aus welcher Datei die Fragen eingelesen werden sollen. void fragenEinlesen(String dateiname) { try { //Der Reader wird gebraucht, um Daten aus einem .txt-File einlesen zu können. BufferedReader in = new BufferedReader(new FileReader(dateiname)); while (true) { //Das Lesen geschieht zeilenweise String zeile = in.readLine(); //Bei einer leeren Zeile wird abgebrochen ansonsten läuft die while(true)Schleife weiter. if (zeile == null ) break; //Jede Zeile wird zu einem Frageknoten (Das Einlesen geschieht in der Klasse Frageknoten!) Frageknoten frageknoten = new Frageknoten(zeile); //Alle Fragezeilen werden der Reihe nach dem TreeMap übergeben. //Mit dem .put werden die Daten in den TreeMap übertragen fragen.put(frageknoten.fragenummer, frageknoten); } } 6 //Gibt an, falls es beim Einlesen einen Fehler gibt. Wenn dies im "Try" geschieht. catch (IOException e) { e.printStackTrace(); //Ausgabe, falls beim Einlesen ein Fehler aufgetreten ist. System.out.println("Beim Einlesen ist ein Fehler aufgetreten."); } } //Hier (throws IOExeption) werden die Einlesefehler nicht behandelt - wenn es ein solcher gibt, geht das Programm einen Schritt zurück, bis zu einer Stelle, wo die Einlesefehler abgefangen werden. void spielLoop() throws IOException { // Frage 1 aus dem TreeMap als aktuelle Frage setzen aktuelleFrage = (Frageknoten)fragen.get(1); System.out.println(""); System.out.println("Beantworte im Folgenden alle Fragen mit j für Ja und n für Nein:"); while(true) { System.out.println(""); System.out.println(aktuelleFrage.frage); String antwort = scanner.nextLine(); //Wenn die Frage mit Ja beantwortet wurde. //== funktioniert bei Strings nicht. Da braucht man .equals("") if ( antwort.equals("j") ) { //Wenn es eine Antwort gibt: if (aktuelleFrage.istAntwortJ) { //Aufruf der Methode "" mit dem Parameter true Methode ergänzen(true); break; } //Wenn es keine Antwort gibt. else //Neue Frage wird zur aktuellen Frage aktuelleFrage = (Frageknoten)fragen.get(aktuelleFrage.fragenummerJ); } 7 //Wenn die Frage mit Nein beantwortet wurde. else if (ergänzen) { //Wenn es eine Antwort gibt: if (ergänzen) { //Aufruf der Methode "" mit dem Parameter false Methode ergänzen(false); break; } //Wenn es keine Antwort gibt: else //Neue Frage wird zur aktuellen Frage. aktuelleFrage = (Frageknoten)fragen.get(aktuelleFrage.fragenummerN); } //Mit q kann man aussteigen. else if (antwort.equals("q") ) return; } } //Methode, welche fragt, ob der Baum angesehen werden will. void fragebaumAnsehen() { System.out.println(""); System.out.println("Möchtest du den Fragenbaum sehen (j/n)?"); String baumAnsehen = scanner.nextLine(); if (baumAnsehen.equals("j") ) { System.out.println(""); //Diese Methode zeigt den Baum an. Methode ergänzen( true, (Frageknoten)fragen.get(1), 0); } } 8 //Methode, in welcher gefragt wird, ob es ein neues Spiel geben soll. boolean neuesSpiel() { System.out.println(""); System.out.println("Möchtest du noch einmal spielen? (j/n)?"); //Liest die Antwort (j/n) ein und speichert sie auf "nochmals" ergänzen; //Bei "Strings" geht "==" nicht. if (nochmals.equals("j")) return true; else { System.out.println(""); System.out.println("Möchtest du deine Fragen speichern (j/n)?"); //Hier wird eingelesen, ob der Spielverlauf gespeichert werden möchte. String speichern = scanner.nextLine(); if (ergänzen) { System.out.println("Gib einen Dateinamen ein:"); String dateinameNeu = scanner.nextLine(); //Methode, in welcher die neuen (und aktuellen) Fragen gespeichert werden dateiSchreiben(dateinameNeu); } return false; } } 9 //Hier wird die Antwort überprüft. void antwortPruefen(boolean jaAntwort) { String antwortTier; //Wenn die letzte Frage mit Ja beantwortet wurde und eine Antwort vorhanden ist. if (jaAntwort) antwortTier = aktuelleFrage.antwortJ; //Wenn die letzte Frage mit nein beantwortet wurde und die Antwort vorhanden ist. else antwortTier = aktuelleFrage.antwortN; System.out.println(""); System.out.println("Ist das Tier an das du denkst ein(e) " + ergänzen + "?"); String aw = scanner.nextLine(); if ( aw.equals("j") ) { System.out.println(""); //Antwort, wenn die Antwort korrekt war. System.out.println("Ich weiss alles!!"); System.out.println(""); } //Wenn das geratene Tier nicht korrekt war: else if ( aw.equals("n") ) Methode ergänzen(jaAntwort, antwortTier); } void neuesTierLernen(boolean jaAntwort, String antwortTier) { System.out.println(""); System.out.println("An welches Tier hast du dir dann gedacht? Gib das Tier ein: "); String neuesTier = scanner.nextLine(); System.out.println(""); System.out.println("Gib eine Frage ein, die ein(e) " + antwortTier + " von einem " + neuesTier + " unterscheidet:"); String neueFrage = scanner.nextLine(); System.out.println(""); System.out.println("Wir die Frage für den/die/das " + neuesTier + " mit Ja beantwortet (j/n)?"); 10 String zuordnung = scanner.nextLine(); String jaTier, neinTier; //Wenn die neue Frage mit Ja zum neuen Tier führt: if ( zuordnung.equals("j") ) { ergänzen; ergänzen; } //Wenn die neue Frage mit Nein zum neuen Tier führt: else { ergänzen; ergänzen; } //Ruft die neue Methode auf, welche der neuen Frage eine neue Nummer gibt. int neueFragenummer = gibNeueFragenummer(); //Es wird ein neuer Frageknoten erstellt. Frageknoten neuerFrageknoten = new Frageknoten(neueFragenummer, neueFrage, jaTier, neinTier ); //Die neue Frage wird in den TreeMap eingelesen. fragen.put(neueFragenummer, neuerFrageknoten); //Anpassung der aktuellen Frage - falls es bei Ja eine (falsche) Antwort gab. if (jaAntwort) { //Jetzt gibt es keine Antwort mehr, sondern eine neuen Frage. aktuelleFrage.istAntwortJ = false; //Die Antwort wird gelöscht. aktuelleFrage.antwortJ = null; //Der neuen Frage zur aktuelle Frage wird die neue Fragenummer zugeordnet. aktuelleFrage.fragenummerJ = neueFragenummer; } //Anpassung der aktuellen Frage - falls es bei Nein eine (falsche) Antwort gab. else { aktuelleFrage.istAntwortN = false; aktuelleFrage.antwortN = null; aktuelleFrage.fragenummerN = neueFragenummer; } } 11 //Methode, welche eine neue Fragenummer zuordnet. int gibNeueFragenummer() { //Hier wird der letzte Frageknoten als "letzte Frage" abgespeichert. Frageknoten letzteFrage = (Frageknoten) fragen.get(fragen.lastKey()); //Es wird eine neue Fragenummer generiert, welche um eines höher ist, als die Nummer der letzten Frage. return letzteFrage.fragenummer + 1; } //Methode, welche die neue Frage abspeichert - unter "dateiname" void dateiSchreiben(String dateiname) { //Fehler beim Schreiben werden abgefangen. try { PrintWriter datei = new PrintWriter( new FileWriter( dateiname)); Iterator itr = fragen.values().iterator(); //So lange es weitere Zeilen gibt, werden die Frageknoten als Zeilen abgespeichert. while(itr.hasNext()) { Frageknoten fk = (Frageknoten)itr.next(); datei.println(fk.alsZeile()); } //Speichert die gelesenen Daten in die Datei. datei.flush(); } catch ( IOException e ){ System.out.println( "Konnte Datei nicht erstellen" ); } } 12 //Methode, welche den Baum anzeigt. void frageBaumAnzeigen(boolean jaFrage, Frageknoten frageknoten, int baumtiefe) { //Methode, welche angibt, wie weit der Einzug bei den einzelen Baumzeilen sein soll (ähnlich Tabulator) Methode ergänzen(baumtiefe); System.out.println( (jaFrage? "Ja" : "Nein") + "-Frage: " + frageknoten.frage); if (frageknoten.istAntwortJ) { einruecken(baumtiefe+1); System.out.println("Ja-Antwort:" + frageknoten.antwortJ); } else frageBaumAnzeigen(true, (Frageknoten)fragen.get(frageknoten.fragenummerJ), baumtiefe+1); if (frageknoten.istAntwortN) { einruecken(baumtiefe+1); System.out.println("Nein-Antwort:" + frageknoten.antwortN); } else frageBaumAnzeigen(false, (Frageknoten)fragen.get(frageknoten.fragenummerN), baumtiefe+1); } //"Tabulator" void einruecken(int tiefe) { for (int i = 0; i < tiefe*4; i++ ) System.out.write(' '); } } 13