3
\$\begingroup\$

I'm doing a Java text based game as a course project.

Everything is fine but the part where it shows a conversation, then gives you 2-4 options, then each actions will lead to different text and stats changes.

For now I can only come up with declaring a string array to store all the text, looping through the text until the multiple choice is given, then declaring an int to store the choice of the player, switch the choice to give different text and stats bonuses.

This is quite inefficient and takes a lot of lines, so I wonder if there is a better way to do that.

int[] statsChanged = new int[] {0, 0, 0, 0};                   
int i;
String[] event = eventDial.getFirstNight();
for (i = 0; i < 7; i++) {
    say(event[i]);
    next();
}
int choice = -1;
while (choice > 2 || choice < 0) {
    try {
        say(event[7]);
        choice = input.nextInt();
    } catch (InputMismatchException e) {
        next();
    }
    switch (choice) {
        case 0:
            say(event[8]); say(event[9]);
            statsChanged[0] = 2;
            break;
        case 1:
            say(event[10]); say (event[11]);
            statsChanged[1] = 2;
            break;
        case 2:
            say(event[12]);
            break;
    }
}
say(event[13]);
return statsChanged;

event is the string array that stores the text. statchanges stores all the bonuses to 4 main stats. next() is just an empty input. (input.nextLine()) say(str) is System.out.println(String str);

\$\endgroup\$
  • 2
    \$\begingroup\$ Edit your question and add more code for context, please. \$\endgroup\$ – barq Feb 4 '15 at 16:12
  • \$\begingroup\$ Please add code for next(), say() and the wrapper function for the code you pasted. \$\endgroup\$ – barq Feb 4 '15 at 16:20
1
\$\begingroup\$

Style: Avoid multiple statements in one line, as you did here:

say(event[8]); say(event[9]);

Variable naming:

String[] event = ...;

It would be better to name the array events or eventArray, as you are storing multiple events.

int[] statsChanged = new int[] {0, 0, 0, 0};

statsChanged sounds like you only have true or false options, however you are assigning integer values to the elements, which have more than two options. Therefore a name such as statsLevels would be more appropriate.

Iterating through an array. Instead of:

int i;
for (i = 0; i < 7; i++) {
    say(event[i]);
    next();
}

do

for (String e:event) {
    say(event);
    next();
}
\$\endgroup\$
0
\$\begingroup\$

If you choose different data structures over an array you can simplyfy the whole switch(choice) processing. If you use a map and a list then you can do something like this:

// This setup and initialisation goes to wherever you define events
Map<Integer, List<String>> sayMap = new HashMap<Integer, List<String>>(100) ; 
sayMap.put(0, Arrays.asList(new String[] {"string1", "string2"})) ;
sayMap.put(1, Arrays.asList(new String[] {"string3", "string4", "string5"})) ;

// And this replaces your switch statement
for (String s : sayMap.get(choice)) {
    say(s) ;
}

The idea is to create a data structure that maps a choice onto a list of strings that you can then loop over rather than hard-coding them in the switch statement. Another refinement would be to create the sayMap from a file and so remove the the hard coded sayMap.puts(...) calls from the program.

I can't tell what your going to do next but another thing you could look at is holding a list of objects rather than simple strings in the Map. Then you could start to give more complex behaviour to the choices that get made.

For example, create a class to encapsulate the actions:

class ChoiceAction {
    private String sayString ;

    public String getSayString() {
        return sayString;
    }

    public void doSomething() {
        System.out.println(getSayString()) ;
    }

    public ChoiceAction(String sayString) {
        super();
        this.sayString = sayString;
    }
}

Then you can change the code to something like this:

Map<Integer, List<ChoiceAction>> sayMap2 = new HashMap<Integer, List<ChoiceAction>>(100) ; 
sayMap2.put(0, Arrays.asList(new ChoiceAction[] {new ChoiceAction("string1"), new ChoiceAction("string2")})) ;
for (ChoiceAction ca : sayMap2.get(0)) {
    ca.doSomething() ;
}

You can add actions to the ChoiceAction class as needed.

\$\endgroup\$
  • \$\begingroup\$ I appreciate this approach, but does this mean for every event I have to declare one HashMap? \$\endgroup\$ – Shelune Feb 4 '15 at 21:47
  • \$\begingroup\$ No - if you look at how the Map works in the first example code you'll see that the one Map holds events for both the 0 and 1 choices. You can extend this as far as you need. \$\endgroup\$ – Jackson Feb 5 '15 at 8:58
  • \$\begingroup\$ well from what I understand then each HashMap (event) holds the key to several consequences (0, 1, 2) and return that. But for each event I still need to declare a HashMap for it. So if I have like 20 events then I need 20 HashMap right? \$\endgroup\$ – Shelune Feb 5 '15 at 19:07
  • \$\begingroup\$ I don't think you need more than one hashmap, the idea is to use the Map to provide an way to lookup which events are linked to a choice. You could keep your array of events and change the Map to Map<Integer, List<Integer>> where you map a choice to a list of indexes in you event[]. \$\endgroup\$ – Jackson Feb 6 '15 at 10:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.