Als ziemlich unerfahrener Java-Programmierer habe ich mich der großen Herausforderung gestellt, ein einfaches Textadventure zu schreiben. Es überrascht nicht, dass ich bereits auf Schwierigkeiten gestoßen bin!
Ich versuche, meiner Location-Klasse eine Eigenschaft zum Speichern der darin enthaltenen Exits zu geben. Ich habe dafür ein boolesches Array verwendet, um im Wesentlichen Wahr/Falsch-Werte zu speichern, die jeden Ausgang darstellen. Davon bin ich nicht ganz überzeugt
a) Dies ist der effizienteste Weg, dies zu tun und
b) dass ich den richtigen Code verwende, um das Array zu füllen.
Ich würde mich über jedes Feedback freuen, auch wenn es sich um eine vollständige Codeüberholung handelt!
Derzeit erzeuge ich beim Instanziieren eines Standorts einen String, den ich an die setExits-Methode sende:
String e = "N S U";
secretRoom.setExits(e);
In der Location-Klasse sieht setExits so aus:
public void setExits(String e) {
if (e.contains("N"))
bexits[0] = true;
else if (e.contains("W"))
bexits[1] = true;
else if (e.contains("S"))
bexits[2] = true;
else if (e.contains("E"))
bexits[3] = true;
else if (e.contains("U"))
bexits[4] = true;
else if (e.contains("D"))
bexits[5] = true;
}
Ich bin ehrlich, ich finde, das sieht besonders klobig aus, aber mir fiel keine andere Möglichkeit ein. Ich bin mir jetzt auch nicht ganz sicher, wie ich die getExits-Methode schreiben soll …
Jede Hilfe wäre willkommen!
Mann, wenn nur alle “grünen” Programmierer so Fragen stellen könnten. Darf ich auch vorschlagen Code-Review für Fragen wie diese, die nur nach Verbesserung fragen? Viel Glück.
– MarioDS
9. Juli 2014 um 10:46 Uhr
@MDeSchaepmeester: schlecht auf Englisch … was bedeutet grüner Java-Coder meint?? :Ö
– NoobEditor
9. Juli 2014 um 10:48 Uhr
@NoobEditor – Es bedeutet “neu”.
– Rudi Kershaw
9. Juli 2014 um 10:49 Uhr
Haben Sie dieses Projekt speziell ausgewählt, um Java besser zu lernen, oder weil Textabenteuer großartig sind? Für ersteres gut, Sie werden viel lernen! Aber wenn es letzteres ist, kann ich Inform 7 oder TADS empfehlen?
– Paul z
9. Juli 2014 um 18:06 Uhr
Danke für die Komplimente und Ratschläge Jungs! @PaulZ, ich habe beschlossen, ein Textabenteuer zu machen, um besser in Java zu werden (und weil sie großartig sind!). Ich habe einen Online-Kurs gemacht, der nicht so toll war, also dachte ich, ich würde einfach den Sprung wagen und den Rest selbst beibringen.
– Lordkanzler
10. Juli 2014 um 10:52 Uhr
Gexizid
Die effizienteste und Ausdrucksweise ist die folgende:
Verwenden enums als Exits und verwenden Sie an EnumSet um sie zu speichern. EnumSet ist ein effizienter Set Implementierung, die ein Bitfeld verwendet, um die Aufzählungskonstanten darzustellen.
So können Sie es tun:
public enum Exit { North, West, South, East, Up, Down; }
EnumSet<Exit> set = EnumSet.noneOf(Exit.class); // An empty set.
// Now you can simply add or remove exits, everything will be stored compactly
set.add(Exit.North); // Add exit
set.contains(Exit.West); // Test if an exit is present
set.remove(Exit.South); //Remove an exit
Das Enum-Set speichert alle Exits in einem einzigen long intern, sodass Ihr Code ausdrucksstark und schnell ist und viel Speicherplatz spart.
Ich liebe die Einfachheit dieser Antwort! Um den Code etwas besser lesbar zu machen, würde ich auch jede Enum-Richtung zum vollständigen Namen und nicht zum ersten Buchstaben machen. Dh public enum Exit { North, West, South, East, Up, Down; }
– Dylan Watson
9. Juli 2014 um 14:40 Uhr
Sehr elegante Lösung. ich habe noch nie gesehen EnumSet früher so verwendet, aber es sieht nach einer großartigen Redewendung aus, an die man sich gewöhnen muss.
@maaartinus: Da bin ich mir nicht sicher! Ich schätze, weil der Enum-Satz des Typs Exit immer dieselbe Klasse (RegularEnumSet) sein wird, könnte das JIT sehr gut in der Lage sein, alle virtuellen Aufrufe zu eliminieren und alles einzufügen. Verwenden int um einige virtuelle Anrufe loszuwerden, die sehr wahrscheinlich herausoptimiert werden, riecht sehr nach vorzeitiger Optimierung.
– Gexizid
10. Juli 2014 um 8:22 Uhr
@gexicide Einverstanden, es könnte möglich sein. Ein Benchmark würde uns sagen, ob jemand neugierig genug war. Selbst wenn nicht, würde ich mindestens zweimal überlegen, bevor ich etwas anderes verwende EnumSet hier.
– maaartinus
10. Juli 2014 um 8:32 Uhr
Ross Drew
Gibt es einen Grund, warum Sie dies mit tun Strings und kommen nicht vorbei booleansdh
public void setExits(boolean N, boolean E, boolean S, boolean W, boolean U, boolean D)
Oder Setter haben?
public void setNorthOpen(boolean open)
{
bexits[4] = open;
}
Zweitens, warum speichern Sie die Ausgänge als ein Array von booleschen Werten, es ist eine kleine endliche Menge, warum nicht einfach
boolean N,S,E,W,U,D;
Dann müssen Sie nicht nachverfolgen, welche Nummer im Array jede Richtung ist.
Ebenfalls
Dies ist eine richtige Antwort (wenn auch nicht ganz optimal wie die von @gexicide), aber ich ermutige jeden, sich die anderen Antworten hier anzusehen, um einen interessanten Blick darauf zu werfen, wie Dinge in Java auf unterschiedliche Weise erledigt werden können.
Zum späteren Nachschlagen
Code, der funktioniert, gehört dazu Code-Review, nicht Stapelüberlauf. Obwohl, wie @kajacx betonte, dieser Code eigentlich nicht funktionieren sollte.
Danke @Ross, ich mag das Aussehen der von Ihnen vorgeschlagenen Setter. Wie ich bereits erwähnt habe, bin ich sehr neu in diesem Bereich, also stolpere ich irgendwie durch! Danke trotzdem, ich schätze deine Hilfe.
– Lordkanzler
9. Juli 2014 um 10:52 Uhr
Vielen Dank auch für den Punkt zur Codeüberprüfung – ich wusste das nicht, werde es aber für zukünftige Referenzen merken.
– Lordkanzler
9. Juli 2014 um 10:52 Uhr
Einige der Antworten hier sind wirklich gut, wenn Sie dabei bleiben wollen Strings, aber wenn Sie keinen besonderen Grund dafür haben, würde ich vorschlagen, zu allen zu wechseln booleans wie in meinem Beispiel.
– Ross Drew
9. Juli 2014 um 10:53 Uhr
setExits(false, true, false, true) wird schrecklich zu lesen sein und die in einer anderen Antwort vorgeschlagene Enum-Variante ist einfach überlegen.
– OliverS
9. Juli 2014 um 13:07 Uhr
Ich stimme zu, mehrere Agumente sind nicht großartig, deshalb habe ich die Accessor-Methoden vorgeschlagen. Ich stimme auch zu, dass idealerweise die EnumSet ist die schönste Option, aber ich hatte gelesen, dass das OP “grün” war, und dachte, etwas Einfaches als Sprungbrett weg von dem offensichtlich Schmerzhaften String Passieren war die bessere Option. Normalerweise hätte ich meine Antwort erweitert, um fortgeschrittener zu sein, aber @gexicide hat in der Zwischenzeit geantwortet, und ich möchte nicht antworten, stehlen, und beide sind jetzt für jeden hier, der es möchte. Down-Voting, weil es nicht die absolut optimale Antwort ist, ist nicht wirklich richtig, oder?
– Ross Drew
10. Juli 2014 um 8:27 Uhr
kajacx
Okay, zuerst einmal deine setExits() Methode wird nicht wie beabsichtigt funktionieren, verkettetes if-elseif wird maximal 1 Codezweig ausführen, zum Beispiel:
if (e.contains("N"))
bexits[0] = true;
else if (e.contains("W"))
bexits[1] = true;
Selbst wenn e enthält beides N und Wnur bexits[0] wird gesetzt. Auch diese Methode fügt nur Exits hinzu (z. B. Aufrufen von setExits("") löscht keine bestehenden Exits.
Außerdem würde ich mich definitiv nicht daran erinnern, dass Norden auf Index 0 liegt, Westen auf 1, … also ist es üblich, Ihre Indizes mit endgültigen statischen Konstanten zu benennen:
public static final int NORTH = 0;
public static final int WEST = 1;
...
Dann kannst du in deine schreiben setExits Methode:
Wenn Sie Ihren Code noch übersichtlicher haben möchten, können Sie schließlich eine Exits Klasse, die verfügbare Ausgänge darstellt und von einem booleschen Array unterstützt wird. Dann könnten Sie an der Stelle, an der Sie Ihren String erstellen, stattdessen diese Klasse erstellen und sich die Arbeit sparen, einen String zu generieren und dann zu analysieren.
BEARBEITEN:
Als @gexicide antwortet, gibt es eine wirklich praktische Klasse EnumSet was wahrscheinlich besser für die Darstellung der Ausgänge geeignet wäre als ein bollean-Array.
public static final int fühlt sich an wie Java 1.4 und wurde stattdessen durch Enums ersetzt
– EpicPandaForce
9. Juli 2014 um 10:59 Uhr
Sie werden das als Index verwenden, um auf ein Array zuzugreifen, ich mag es besser, als enum zu verwenden und die ID von enum oder etwas zu greifen, um den Index zu erhalten.
– kajacx
9. Juli 2014 um 11:02 Uhr
Das ist genau das, was meine Antwort unten verwendet hat. Nun, es ist wahr, dass Sie verwenden müssten Directions.NORTH.ordinal() für den Index einer bestimmten Richtung …
– EpicPandaForce
9. Juli 2014 um 11:04 Uhr
Andererseits ist die EnumSet sieht wirklich cool aus, kannte diese Klasse nicht, ich werde sie der Antwort hinzufügen.
– kajacx
9. Juli 2014 um 11:05 Uhr
Tim B
Das EnumSet In der anderen Antwort ist der beste Weg, dies zu tun. Ich wollte nur noch eine Sache für die Zukunft hinzufügen, wenn Sie anfangen, nicht nur zu prüfen, ob Sie umziehen können, sondern wohin Sie umziehen.
Ebenso gut wie EnumSet Sie haben auch EnumMap.
Wenn Sie eine Raumklasse/Schnittstelle definieren, können Sie innerhalb der Raumklasse haben
Map<Direction, Room> exits = new EnumMap<>(Direction.class);
Sie können nun Ihre Links wie folgt in die Karte einfügen:
exits.put(Direction.NORTH, theRoomNorthOfMe);
Dann kann Ihr Code zum Wechseln zwischen Räumen sehr allgemein sein:
Room destination=currentRoom.getExit(directionMoved);
if (destination == null) {
// Cannot move that way
} else {
// Handle move to destination
}
Niekname
Ich würde eine Exit-Aufzählung erstellen und für die Standortklasse einfach eine Liste von Exit-Objekten festlegen.
also wäre es sowas wie:
public enum Exit { N, S, E, W, U, D }
List<Exit> exits = parseExits(String exitString);
location.setExits(exits);
Du meinst: NWES? 😉
– Rob Audenaerde
9. Juli 2014 um 10:43 Uhr
Dies erfordert immer noch denselben Code, der gerade verschoben wurde parseExits
– Ross Drew
9. Juli 2014 um 10:45 Uhr
+1 Für Aufzählungen. Solch ein mächtiges Werkzeug und so regelmäßig zu wenig genutzt.
– Rudi Kershaw
9. Juli 2014 um 10:46 Uhr
Ha ha! ‘U’ steht für ‘Oben’. Anscheinend gebe ich mich mit einfachen Kompassrichtungen nicht zufrieden…
– Lordkanzler
9. Juli 2014 um 10:47 Uhr
Ich bin mir nicht sicher, ob ich schon auf die Enums gestoßen bin – ich werde ein bisschen lesen und sehen, ob dies der richtige Weg für mich ist. Danke für den Hinweis!
– Lordkanzler
9. Juli 2014 um 10:54 Uhr
Robby Cornelissen
Angesichts dessen, wie Ihr Code aussieht, ist dies die am besten lesbare Implementierung, die mir einfallen könnte:
public class Exits {
private static final char[] DIRECTIONS = "NSEWUD".toCharArray();
public static void main(String... args) {
String input = "N S E";
boolean[] exits = new boolean[DIRECTIONS.length];
for(int i = 0; i< exits.length; i++) {
if (input.indexOf(DIRECTIONS[i]) >= 0) {
exits[i] = true;
}
}
}
}
Davon abgesehen gibt es eine Reihe saubererer Lösungen. Persönlich würde ich mit enums und an gehen EnumSet.
Übrigens ist Ihr ursprünglicher Code falsch, da er fast einen Wert im Array auf true setzt.
Du meinst: NWES? 😉
– Rob Audenaerde
9. Juli 2014 um 10:43 Uhr
Dies erfordert immer noch denselben Code, der gerade verschoben wurde parseExits
– Ross Drew
9. Juli 2014 um 10:45 Uhr
+1 Für Aufzählungen. Solch ein mächtiges Werkzeug und so regelmäßig zu wenig genutzt.
– Rudi Kershaw
9. Juli 2014 um 10:46 Uhr
Ha ha! ‘U’ steht für ‘Oben’. Anscheinend gebe ich mich mit einfachen Kompassrichtungen nicht zufrieden…
– Lordkanzler
9. Juli 2014 um 10:47 Uhr
Ich bin mir nicht sicher, ob ich schon auf die Enums gestoßen bin – ich werde ein bisschen lesen und sehen, ob dies der richtige Weg für mich ist. Danke für den Hinweis!
– Lordkanzler
9. Juli 2014 um 10:54 Uhr
TG
Wenn Sie Exits als Zeichenfolge definieren, sollten Sie sie verwenden. Ich würde es so machen:
public class LocationWithExits {
public static final String NORTH_EXIT="[N]";
public static final String SOUTH_EXIT="[S]";
public static final String EAST_EXIT="[E]";
public static final String WEST_EXIT="[W]";
private final String exitLocations;
public LocationWithExits(String exitLocations) {
this.exitLocations = exitLocations;
}
public boolean hasNorthExit(){
return exitLocations.contains(NORTH_EXIT);
}
public static void main(String[] args) {
LocationWithExits testLocation=new LocationWithExits(NORTH_EXIT+SOUTH_EXIT);
System.out.println("Has exit on north?: "+testLocation.hasNorthExit());
}
}
Die Verwendung eines Arrays von booleschen Werten kann viele Probleme verursachen, wenn Sie vergessen, was genau Bexits bedeutet[0]. Ist es für Norden oder Süden? usw.
oder Sie können einfach Aufzählungen und eine Liste der verfügbaren Ausgänge verwenden. Dann in der Methode testen, ob die Liste einen bestimmten Aufzählungswert enthält
11755000cookie-checkFüllen eines booleschen Arrays in Javayes
Mann, wenn nur alle “grünen” Programmierer so Fragen stellen könnten. Darf ich auch vorschlagen Code-Review für Fragen wie diese, die nur nach Verbesserung fragen? Viel Glück.
– MarioDS
9. Juli 2014 um 10:46 Uhr
@MDeSchaepmeester: schlecht auf Englisch … was bedeutet grüner Java-Coder meint?? :Ö
– NoobEditor
9. Juli 2014 um 10:48 Uhr
@NoobEditor – Es bedeutet “neu”.
– Rudi Kershaw
9. Juli 2014 um 10:49 Uhr
Haben Sie dieses Projekt speziell ausgewählt, um Java besser zu lernen, oder weil Textabenteuer großartig sind? Für ersteres gut, Sie werden viel lernen! Aber wenn es letzteres ist, kann ich Inform 7 oder TADS empfehlen?
– Paul z
9. Juli 2014 um 18:06 Uhr
Danke für die Komplimente und Ratschläge Jungs! @PaulZ, ich habe beschlossen, ein Textabenteuer zu machen, um besser in Java zu werden (und weil sie großartig sind!). Ich habe einen Online-Kurs gemacht, der nicht so toll war, also dachte ich, ich würde einfach den Sprung wagen und den Rest selbst beibringen.
– Lordkanzler
10. Juli 2014 um 10:52 Uhr