1

I was looking for answers here (Java: how to "restart" a static class?), but it doesn't seem to answer my question.

I have a class that generates a somewhat random string from a list of words. The words are then output onto a sign in the game, via read(). I can do things two ways: if buildingText(), verbText() and nounText() are not static, I get a new string every time I access the sign. If those three are static, I get a string that doesn't change, even after the game is restarted.

How can I change this code so that reset() creates a new random string?

I've been trying to use booleans and surround the switch statements with if, but that doesn't seem possible.

Here's the code:

public class Sign {

private static final String TXT_PLACE_NAME      = buildingText();
private static final String TXT_VERBING         = verbText();
private static final String TXT_NOUN            = nounText();


protected static final String SIGNS =
        "Welcome to the  "+ "\n \n "+ TXT_PLACE_NAME+ " of the "+ TXT_VERBING + TXT_NOUN + "";



public void reset(){
    //still working on this. As it stands, will only reset if you exit the program
    //could be worse things
}

public void read(int pos) {
    GameScene.show(new WndMessage(SIGNS));


}

public static String buildingText() {

    String buildingType;

        switch (Random.Int(1, 4)) {
            case 1:
                buildingType = "Inn";
                break;
            case 2:
                buildingType = "Inn";
                break;
            case 3:
                buildingType = "Tavern";
                break;
            case 4:
                buildingType = "Pub";
                break;
            default:
                buildingType = "Inn";
                break;
        }

        return buildingType;
    }

public static String verbText()
{
    String verbName;
    switch (Random.Int(1,20))
    {
        case 1: verbName = " Dancing";
            break;
        case 2: verbName = " Prancing";
            break;
        case 3: verbName = " Eating";
            break;
        case 4: verbName = " Jigging";
            break;
        case 5: verbName = " Digging";
            break;
        case 6: verbName = " Flogging";
            break;
        case 7: verbName = " Floating";
            break;
        case 8: verbName = " Flying";
            break;
        case 9: verbName = " Laughing";
            break;
        case 10: verbName = " Smiling";
            break;
        case 11: verbName = " Drowning";
            break;
        case 12: verbName = " Golden";
            break;
        case 13: verbName = " Silver";
            break;
        case 14: verbName = " Copper";
            break;
        case 15: verbName = " Farming";
            break;
        case 16: verbName = " Running";
            break;
        case 17: verbName = " Sewing";
            break;
        case 18: verbName = " Black";
            break;
        case 19: verbName = " White";
            break;
        case 20: verbName = " Fighting";
            break;
        default: verbName = " Gesticulating";
            break;
    }
    return verbName;
}

public static String nounText()
{
    String nounName;
    switch (Random.Int(1,20))
    {
        case 1: nounName = " Pony";
            break;
        case 2: nounName = " Horse";
            break;
        case 3: nounName = " Griffin";
            break;
        case 4: nounName = " Dragon";
            break;
        case 5: nounName = " Wench";
            break;
        case 6: nounName = " Bastard";
            break;
        case 7: nounName = " Ogre";
            break;
        case 8: nounName = " Troll";
            break;
        case 9: nounName = " Ox";
            break;
        case 10: nounName = " Cow";
            break;
        case 11: nounName = " Cock";
            break;
        case 12: nounName = " Hen";
            break;
        case 13: nounName = " Ram";
            break;
        case 14: nounName = " Ewe";
            break;
        case 15: nounName = " Dog";
            break;
        case 16: nounName = " Merchant";
            break;
        case 17: nounName = " Fisherman";
            break;
        case 18: nounName = " Arborist";
            break;
        case 19: nounName = " Archer";
            break;
        case 20: nounName = " Gallbladder";
            break;
        default: nounName = " Pancreas";
            break;
    }
    return nounName;
}
}

Edit:

This is kind of a 'best of' solution. It incorporates elements of the two solutions below and yields the desired results. Please feel free to critique the formatting and organization!

public class Sign {


protected static String SIGNS;
protected static final String SIGNS_FORMAT = "Welcome to the %s of the %s %s";

private static final String[] BUILDING_TYPES = new String[]{
        "Inn",
        "Inn",
        "Tavern",
        "Pub",
        "Inn"
};

private static final String[] VERB_NAMES = new String[] {
        "Dancing",
        "Prancing",
        "Eating",
        "Jigging",
        "Digging",
        "Flogging",
        "Floating",
        "Flying",
        "Laughing",
        "Smiling",
        "Drowning",
        "Golden",
        "Silver",
        "Copper",
        "Farming",
        "Running",
        "Sewing",
        "Black",
        "White",
        "Fighting",
        "Gesticulating"
};

private static final String[] NOUN_NAMES = new String[] {
        "Pony",
        "Horse",
        "Griffin",
        "Dragon",
        "Wench",
        "Bastard",
        "Ogre",
        "Troll",
        "Ox",
        "Cow",
        "Cock",
        "Hen",
        "Ram",
        "Ewe",
        "Dog",
        "Merchant",
        "Fisherman",
        "Arborist",
        "Archer",
        "Gallbladder",
        "Pancreas"
};

private String currentSign = getNewSign();

public void reset(){
    buildingText();
    verbText();
    nounText();
    SIGNS = currentSign;
}

public void read(int pos) {
    //referenced by pos in order to make the sign catch fire later on
    GameScene.show(new WndMessage(SIGNS));
}

private String getNewSign(){
    return String.format(SIGNS_FORMAT, buildingText(), verbText(), nounText());
}

private String buildingText() {
    return BUILDING_TYPES[Random.Int(0, BUILDING_TYPES.length - 1)];
}

private String verbText() {
    return VERB_NAMES[Random.Int(0, VERB_NAMES.length - 1)];
}

private String nounText() {
    return NOUN_NAMES[Random.Int(0, NOUN_NAMES.length - 1)];
}

}

Community
  • 1
  • 1
  • Why not move this behavior into an object? Then you can just construct a new instance of that object. – dimo414 Jun 22 '16 at 01:45

3 Answers3

1

As you are using static final Strings the JVM creates those strings during the startup. In order to do what you want use a singleton pattern which returns an instance of the string. Then the reset() method can reset the instance you are using whenever you need.

U.V.
  • 572
  • 4
  • 11
0

It feels a bit like you're trying to abuse static variables, but you can do it this way.

public class Sign {

// These are no longer final as you need to change them
private static String TXT_PLACE_NAME;
private static String TXT_VERBING;
private static String TXT_NOUN;
protected static String SIGNS;


// Since they're not final reset can change them.
public void reset(){
    TXT_PLACE_NAME      = buildingText();
    TXT_VERBING         = verbText();
    TXT_NOUN            = nounText();
    SIGNS = "Welcome to the  "+ "\n \n "+ TXT_PLACE_NAME+ " of the "+ TXT_VERBING + TXT_NOUN + "";
}

// This ensures that they get initialized initially
static {
    reset();
}

// ...

}
Michael Anderson
  • 70,661
  • 7
  • 134
  • 187
  • This is great. Thank you very much! It would have taken me a very long time to think of doing this. I'm trying to move away from using static variables- I think I'm getting there, albeit slowly. – user5352515 Jun 22 '16 at 16:32
  • Your solution works exactly as I wanted it to. Thank you once more, Sir. – user5352515 Jun 22 '16 at 16:50
0

From your code, you're using an instance-method reset() and read(), so I assume that you'd be creating different instances of Sign.

So why not let each Sign object keep their own sign message, and refactor your code to something like this:

public class Sign {

    protected static final String SIGNS_FORMAT = "Welcome to the %s of the %s %s";

    private static final String[] BUILDING_TYPES = new String[]{
            "Inn",
            "Inn",
            "Tavern",
            "Pub",
            "Inn"
    };

    private static final String[] VERB_NAMES = new String[] {
            "Dancing",
            "Prancing",
            "Eating",
            "Jigging",
            "Digging",
            "Flogging",
            "Floating",
            "Flying",
            "Laughing",
            "Smiling",
            "Drowning",
            "Golden",
            "Silver",
            "Copper",
            "Farming",
            "Running",
            "Sewing",
            "Black",
            "White",
            "Fighting",
            "Gesticulating"
    };

    private static final String[] NOUN_NAMES = new String[] {
            "Pony",
            "Horse",
            "Griffin",
            "Dragon",
            "Wench",
            "Bastard",
            "Ogre",
            "Troll",
            "Ox",
            "Cow",
            "Cock",
            "Hen",
            "Ram",
            "Ewe",
            "Dog",
            "Merchant",
            "Fisherman",
            "Arborist",
            "Archer",
            "Gallbladder",
            "Pancreas"
    };

    private String currentSign = getNewSign();

    public void reset(){
        currentSign = getNewSign();
    }

    public void read(int pos) {
        GameScene.show(new WndMessage(currentSign));
        // the `pos` argument is not used?
    }

    private String getNewSign(){
        return String.format(SIGNS_FORMAT, buildingText(), verbText(), nounText());
    }

    private String buildingText() {
        return BUILDING_TYPES[Random.Int(0, BUILDING_TYPES.length - 1)];
    }

    private String verbText() {
        return VERB_NAMES[Random.Int(0, VERB_NAMES.length - 1)];
    }

    private String nounText() {
        return NOUN_NAMES[Random.Int(0, NOUN_NAMES.length - 1)];
    }
}

Note that I have no idea what Random.Int is and assume that the it takes a inclusive range Random.Int(lowerBound, upperBound). The JDK method should be java.util.Random.nextInt(bound) instead.

kazenorin
  • 1,455
  • 8
  • 16
  • You've got it. Random.Int is just a gussied up version of JDK's Random.Int(lowerBound, upperBound). I really, really like this idea you've proposed. I've been shy about using this style of string and had all but forgotten about using %s. – user5352515 Jun 22 '16 at 16:32