2
\$\begingroup\$

This code is part of my Hangman game. One of my minor issues is how to properly print out the hangman.

Could you please give me hints on how to make the code less hardcoded? This code is so redundant, shoot me...

Any comments are welcome.

class HangmanState

static void show(int count, PrintStream out) {
    switch(count){
        case 1: {
            showOne(out);
            break;
        }
        case 2: {
            showTwo(out);
            break;
        }
        case 3: {
            showThree(out);
            break;
        }
        case 4: {
            showFour(out);
            break;
        }
        case 5: {
            showFive(out);
            break;
        }case 6: {
            showSix(out);
            break;
        }
        case 7: {
            showSeven(out);
            break;
        }
        case 8: {
            showEight(out);
            break;
        }
        case 9: {
            showNine(out);
            break;
        }case 10: {
            showTen(out);
            break;
        }default: {
            showZero(out);
            break;
        }
    }
}

private static  void showZero(PrintStream out) {
    out.println("             ");
    out.println("             ");
    out.println("             ");
    out.println("             ");
    out.println("             ");
    out.println("             ");
    out.println(" _______________");
    out.println(" |    0/10      |");
    out.println(" |              |");
}


private static void showOne(PrintStream out) {
    out.println("             ");
    out.println("            |");
    out.println("            |");
    out.println("            |");
    out.println("            |");
    out.println("            |");
    out.println(" ___________|___");
    out.println(" |    1/10      |");
    out.println(" |              |");
}

private static void showTwo(PrintStream out) {
    out.println("    ________");
    out.println("            |");
    out.println("            |");
    out.println("            |");
    out.println("            |");
    out.println("            |");
    out.println(" ___________|___");
    out.println(" |    2/10      |");
    out.println(" |              |");
}

private static void showThree(PrintStream out) {
    out.println("    ________");
    out.println("           \\|");
    out.println("            |");
    out.println("            |");
    out.println("            |");
    out.println("            |");
    out.println(" ___________|___");
    out.println(" |    3/10      |");
    out.println(" |              |");
}


private static void showFour(PrintStream out) {
    out.println("    ________");
    out.println("    |      \\|");
    out.println("            |");
    out.println("            |");
    out.println("            |");
    out.println("            |");
    out.println(" ___________|___");
    out.println(" |    4/10      |");
    out.println(" |              |");
}

private static void showFive(PrintStream out) {
    out.println("    ________");
    out.println("    |      \\|");
    out.println("    o       |");
    out.println("            |");
    out.println("            |");
    out.println("            |");
    out.println(" ___________|___");
    out.println(" |    5/10      |");
    out.println(" |              |");
}

private static void showSix(PrintStream out) {
    out.println("    ________");
    out.println("    |      \\|");
    out.println("    o       |");
    out.println("    |       |");
    out.println("    |       |");
    out.println("            |");
    out.println(" ___________|___");
    out.println(" |    6/10      |");
    out.println(" |              |");
}

private static void showSeven(PrintStream out) {
    out.println("    ________");
    out.println("    |      \\|");
    out.println("    o       |");
    out.println("    |\\      |");
    out.println("    |       |");
    out.println("            |");
    out.println(" ___________|___");
    out.println(" |    7/10      |");
    out.println(" |              |");
}

private static void showEight(PrintStream out) {
    out.println("    ________");
    out.println("    |      \\|");
    out.println("    o       |");
    out.println("   /|\\      |");
    out.println("    |       |");
    out.println("            |");
    out.println(" ___________|___");
    out.println(" |    8/10      |");
    out.println(" |              |");
}

private static void showNine(PrintStream out) {
    out.println("    ________");
    out.println("    |      \\|");
    out.println("    o       |");
    out.println("   /|\\      |");
    out.println("    |       |");
    out.println("   /        |");
    out.println(" ___________|___");
    out.println(" |    9/10      |");
    out.println(" |              |");
}

private static void showTen(PrintStream out) {
    out.println("    ________");
    out.println("    |      \\|");
    out.println("    o       |");
    out.println("   /|\\      |");
    out.println("    |       |");
    out.println("   / \\      |");
    out.println(" ___________|___");
    out.println(" |   10/10      |");
    out.println(" |   R.I.P      |");
}
\$\endgroup\$
2
\$\begingroup\$

You can effectively compress the data by defining two strings, representing a format and a mask.

private static final String IMG_FMT =
    "    ________%n" +
    "    |      \\|%n" +
    "    o       |%n" +
    "   /|\\      |%n" +
    "    |       |%n" +
    "   / \\      |%n" +
    " ___________|___%n" +
    " |   %2d/10      |%n" +
    " |   R.I.P      |%n";

private static final String IMG_FMT_MASK =
    "    2222222200" +
    "    4      3100" +
    "    5       100" +
    "   867      100" +
    "    6       100" +
    "   9 a      100" +
    " 00000000000100000" +
    " 0   000000      000" +
    " 0   aaaaa      000";

static { assert(IMG_FMT.length() == IMG_FMT_MASK.length()); }

public static void show(int stage, PrintStream out) {
    char m = Character.forDigit(stage, 36);
    StringBuilder s = new StringBuilder(IMG_FMT.length());
    for (int i = 0; i < IMG_FMT.length(); i++) {
        s.append((IMG_FMT_MASK.charAt(i) <= m) ? IMG_FMT.charAt(i) : ' ');
    }
    out.printf(s.toString(), stage);
}

A caveat, though, is that the animation must be additive. Specifically, you want the base of the vertical post to change from - initially to a | character, and that cannot be accomplished using this technique without a nasty hack.

\$\endgroup\$
  • \$\begingroup\$ using a mask - thats a nice technique!!! i never would have had such an idea!!! great! \$\endgroup\$ – Martin Frank Mar 1 at 9:12
2
\$\begingroup\$

The drawings may be arbitrarily complex. As you grow the program, you might want to add color, animation, who knows what.

Thus, your drawings are resources, and should be treated as such.

This answer provides code, links, and explanations. In short:

  • create one or more (your call) text files

  • store the drawings in some format (your call) in the text files

  • open a reader on the appropriate resource:

    InputStream in = getClass().getResourceAsStream("/file.txt"); 
    BufferedReader reader = new BufferedReader(new InputStreamReader(in));
    
  • read in the data, parse the format, and render the artwork

  • PROFIT!!

Note: to start with, the right format is probably "here are my chars" and you just read them and echo to the screen. If you create one file per image, you can generate the file name as "imageNN.txt" and your rendering code becomes 5 or 6 lines.

Update:

Now that I'm on a computer, not a phone, consider this:

static final String GALLOWS_FORMAT = "images/gallows%02d.txt";

// ... other code ...

static void show(int count, PrintStream out) {
    final String filespec = String.format(GALLOWS_FORMAT, count);  
    InputStream in = getClass().getResourceAsStream(filespec);
    BufferedReader gallows = new BufferedReader(new InputStreamReader(in));

    String line;

    while ((line = gallows.readLine()) != null) {
        out.println(line)
    }

    gallows.close();
}
\$\endgroup\$
  • \$\begingroup\$ i would have not got the idea to move this part into an ressource... that's quite obvious once you read it, but i was not able to do it... i think that would be the preffered way, especially when i take your hint about 'growing' (colors new shapes etc...) thanks! \$\endgroup\$ – Martin Frank Mar 18 at 12:17
1
\$\begingroup\$

Use a Map

Since Java 8 it is possible to treat methods as higher order functions, what makes it possible to store them as a value inside a Map

Map<Integer, Consume<OutputStream> countByConsumer = new HashMap<>();
countByConsumer.put(1, BaseTest::showOne);
countByConsumer.put(2, BaseTest::showTwo);

Than you can simply use get inside show

static void show(int count, PrintStream out) {
    Consumer<PrintStream> printStreamConsumer = countByConsumer.get(count);
    printStreamConsumer.accept(out);
}

The advantage of this method is that you get ride of the huge switch

Use OOP

Use the State-Pattern

If you want a oop solution, i think the state-pattern would be the way to go. There for you would have the class Hangman which have multiple HealthStates

class Hangman {
    private HealthState healthState;

    // constructor

    void setHealthState(HealthState healthState) {
        this.healthState = healthState;
    }

    void display(HealthState healthState, PrintStream out) {
        healthState.display(out)
    }
}
class OneHealth implements HealthState {

    private Hangman hangman;

    // constructor

    @Override
    public void display(PrintStream out) {
        out.println("             ");
        out.println("            |");
        out.println("            |");
        out.println("            |");
        out.println("            |");
        out.println("            |");
        out.println(" ___________|___");
        out.println(" |    1/10      |");
        out.println(" |              |");
        hangman.setHealthState(new TwoHealth());
    }
}

class TwoHealth implements HealthState {

     private Hangman hangman;

    // constructor

    @Override
    public void display(PrintStream out) {
        /*...*/
        hangman.setHealthState(new ThreeHealth());
    }
}
\$\endgroup\$
  • \$\begingroup\$ i don't think it's a good idea to set the state during display... but really: using methods as higher order functions is a real bumper - thats a very good hint on how to handle that (since this is not the first time i ran into a problem like this) \$\endgroup\$ – Martin Frank Mar 1 at 5:23
  • \$\begingroup\$ yes, you are right. Maybe it would be better to return a List or a custom object \$\endgroup\$ – Roman Mar 1 at 6:12

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.