简体   繁体   中英

How to draw an ASCII staircase with Java?

I've been trying to get this done in Java. And this is a complex thing to draw, at least for me.

Q1 Write a simple Java program that prints a staircase or a figure as shown below:

 +---+ | | +---+---+ | | | +---+---+---+ | | | | +---+---+---+---+ | | | | | +---+---+---+---+---+ | | | | | | +---+---+---+---+---+

I have come up with a solution but it is not even halfway there. This is the code I have come up with

public class DrawStairs {
    public static final int HEIGHT = 5;
    public static final int TOTALHEIGHT = HEIGHT * 5;
    public static void main(String[] args) {
        //Main Outer Loop
        for (int i = 1; i <= HEIGHT; i++) {
            //Loop for the spaces before, then print the head
            for (int j = 1; j <= TOTALHEIGHT + (i * (-5)); j++) {
                System.out.print(" ");
            }
            printTop();
            //Loop for spaces after, then print asterisk
            for (int j = 1; j <= (i - 1); j++) {
                System.out.print("---+");
            }
            System.out.println(" ");
            //Loop for the spaces before, then print the body
            for (int j = 1; j <= TOTALHEIGHT + (i * (-5)); j++) {
                System.out.print(" ");
            }
            printMiddle();
            //Loop for spaces after, then print asterisk
            for (int j = 1; j <= (i - 1) * 5; j++) {
                System.out.print(" ");
            }
            //Loop for spaces before, then print the legs
            for (int j = 1; j <= TOTALHEIGHT + (i * (-5)); j++) {
                System.out.print(" ");
            }
            printBottom();
            //Loop for spaces after, then print asterisk
            for (int j = HEIGHT; j <= 0; --j) {
                System.out.print("---+");
            }
            System.out.println("|");
        }
        // for loop for printing the floor of asterisks
        for (int i = 1; i <= HEIGHT; i++) {
            System.out.print("+---+");
        }
    }
    public static void printTop() {
        System.out.print("+---+");
    }
    public static void printMiddle() {
        System.out.print("|   |");
    }
    public static void printBottom() {
        // System.out.print("+---+");
    }
}

And this is what it does.

                    +---+ 
                    |   |                    |
               +---+---+ 
               |   |                    |
          +---+---+---+ 
          |   |                    |
     +---+---+---+---+ 
     |   |                    |
+---+---+---+---+---+ 
|   |                    |
+---++---++---++---++---+

Can anyone please help me and guide me with my code? I'd like if someone can tell me what's wrong and what should be changed.

This is my solution to the problem. Thanks for the puzzle;)

public class Staircase {
    public static final int SIZE = 5;
    public static final int STAIR_WIDTH = 5;
    public static final String TREAD = "-";
    public static final String RISER = "|";
    public static final String NOSING = "+";
    public static final String HOLLOW = " ";

    public static void main(String[] args)
    {
        StringBuilder step = new StringBuilder();
        for (int i = 0; i < (STAIR_WIDTH - 2); ++i) { step.append(TREAD); }
        StringBuilder hollow = new StringBuilder();
        for (int i = 0; i < (STAIR_WIDTH - 2); ++i) { hollow.append(HOLLOW); }

        StringBuilder tread = new StringBuilder();
        for (int i = 0; i < SIZE; ++i) { tread.append(NOSING + step); }
        tread.append(NOSING);

        StringBuilder riser = new StringBuilder();
        for (int i = 0; i < SIZE; ++i) { riser.append(RISER + hollow); }
        riser.append(RISER);

        for (int i = 0; i < SIZE; ++i) {
            int offset = tread.length() - (((STAIR_WIDTH - 1) * i) + STAIR_WIDTH);
            printSpaces(offset);
            System.out.println(tread.substring(offset));
            printSpaces(offset);
            System.out.println(riser.substring(offset));
        }
        System.out.println(tread);
    }

    public static void printSpaces(int count)
    {
        for (int i = 0; i < count; ++i)
            System.out.print(" ");
    }
}
public class Staircase {
    // You can change the height to any number and check
    public static final int HEIGHT = 5;

    public static void main(String[] args) {
        Staircase stairs = new Staircase();
        for (int j = 0; j < HEIGHT; j++) {
            stairs.printSpace(j);
            stairs.printTop(j);
            stairs.printSpace(j);
            stairs.printMiddle(j);
        }
       stairs.printTop(HEIGHT-1); // added for bottom line stairs 
    }

    public void printSpace(int j) {
        for (int i = j; i < HEIGHT - 1; i++) {
            System.out.print("   ");
        }
    }

    public void printTop(int j) {

        for (int k = 0; k <= j; k++) {
            System.out.print("+--");
        }

        System.out.print("+");
        System.out.println("");
    }

    public void printMiddle(int j) {
        for (int k = 0; k <= j; k++) {
            System.out.print("|  ");
        }
        System.out.print("|");
        System.out.println("");
    }
}

Yet another answer, so you can see the many, many ways that this problem can be solved. This one uses a single paint loop, and avoids use of constants:

public static void drawStaircase(int steps, 
      String stepTop, String stepLeft, String stepEmpty) {
    String endOfTopStep = stepTop.substring(0,1);  // "+---" => "+"
    String endOfMidStep = stepLeft.substring(0,1); // "|---" => "|"
    for (int row=0; row<steps;row++) {
        // paint a top-of-step row
        for (int col=0; col<steps; col++) {
            boolean isEmpty = row+col+1 < steps;
            System.out.print(isEmpty ? stepEmpty : stepTop);
        }
        System.out.println(endOfTopStep);
        
        // paint a middle-of-step row
        for (int col=0; col<steps; col++) {
            boolean isEmpty = row+col+1 < steps;
            System.out.print(isEmpty ? stepEmpty : stepLeft);
        }
        System.out.println(endOfMidStep);
    }
    // paint bottom border
    for (int col=0; col<steps; col++) {
        System.out.print(stepTop);
    }
    System.out.println(endOfTopStep);
}

public static void main(String ...args) {
    drawStaircase(4, "+---", "|   ", "    ");
}

I created this code to illustrate how to take a problem and break it down step by step until you can solve each step.

Here are the results from one of my many test results.

                +---+
                |   |
            +---+---+
            |   |   |
        +---+---+---+
        |   |   |   |
    +---+---+---+---+
    |   |   |   |   |
+---+---+---+---+---+
|   |   |   |   |   |
+---+---+---+---+---+

The first thing I did was create a method to produce a blank segment. I used the StringBuilder class to make it easier to build line segments and concatenate them.

Once I got that working, I created methods to create a step (landing) and a joist.

Next, I created a method to create one line of the output.

Finally, I created a method to create the entire staircase.

Here's the complete runnable code. It may not be the most efficient code, but I hope that it's among the most understandable code.

public class Staircase {

    public static void main(String[] args) {
        Staircase sc = new Staircase();
        System.out.println(sc.createStaircase(5));
    }

    public String createStaircase(int steps) {
        StringBuilder builder = new StringBuilder();
        int blankSteps = 0;
        String step = createStepSegment();
        String joist = createJoistSegment();

        for (int i = 1; i <= steps; i++) {
            blankSteps = Math.max(0, steps - i);
            builder.append(createLine(step, steps, blankSteps));
            builder.append(createLine(joist, steps, blankSteps));
        }
        builder.append(createLine(step, steps, blankSteps));

        return builder.toString();
    }

    private StringBuilder createLine(String string, int steps, int blankSteps) {
        StringBuilder builder = new StringBuilder();

        int width = string.length() * blankSteps;
        builder.append(createBlankSegment(width));

        int boxSteps = steps - blankSteps;
        for (int i = 0; i < boxSteps; i++) {
            builder.append(string);
        }

        builder.append(string.charAt(0));
        builder.append(System.lineSeparator());

        return builder;
    }

    private String createStepSegment() {
        return "+---";
    }

    private String createJoistSegment() {
        return "|   ";
    }

    private StringBuilder createBlankSegment(int length) {
        StringBuilder builder = new StringBuilder();

        for (int i = 0; i < length; i++) {
            builder.append(" ");
        }

        return builder;
    }

}

You can use streams to build a staircase:

int m = 5;
String[] arr = IntStream.range(0, m).mapToObj(i -> {
    String[] arr1 = new String[m];
    String[] arr2 = new String[m];
    String[] arr3 = new String[m];
    IntStream.range(0, m).forEach(j -> {
        if (i + j >= m - 1) {
            if (j == m - 1) {
                arr1[j] = "+---+";
                arr2[j] = "|   |";
                arr3[j] = "+---+";
            } else {
                arr1[j] = "+---";
                arr2[j] = "|   ";
                arr3[j] = "+---";
            }
        } else {
            arr1[j] = "    ";
            arr2[j] = "    ";
        }
    });
    if (i == m - 1) {
        return Stream.of(arr1, arr2, arr3);
    } else {
        return Stream.of(arr1, arr2);
    }
}).flatMap(Function.identity())
        .map(row -> String.join("", row))
        .toArray(String[]::new);
// output
Arrays.stream(arr).forEach(System.out::println);
                +---+
                |   |
            +---+---+
            |   |   |
        +---+---+---+
        |   |   |   |
    +---+---+---+---+
    |   |   |   |   |
+---+---+---+---+---+
|   |   |   |   |   |
+---+---+---+---+---+

You can represent a staircase as a 2d array of zeros and ones like this:

[0, 0, 0, 0, 0, 1]
[0, 0, 0, 0, 1, 1]
[0, 0, 0, 1, 1, 1]
[0, 0, 1, 1, 1, 1]
[0, 1, 1, 1, 1, 1]
[1, 1, 1, 1, 1, 1]

Then you can represent non-empty cells of this array as an almost square , consisting of two rows: a row with an upper border and a row with a left border . Empty cells are just two rows of spaces of the same length.

+---
|   

Then you can concatenate the cells of each row into one line, and output them line by line. Result consists of two parts: rows of a 2d array with a right border and a lower border row:

n=6
                    +---+
                    |   |
                +---+---+
                |   |   |
            +---+---+---+
            |   |   |   |
        +---+---+---+---+
        |   |   |   |   |
    +---+---+---+---+---+
    |   |   |   |   |   |
+---+---+---+---+---+---+
|   |   |   |   |   |   |
+---+---+---+---+---+---+

Try it online!

int n = 6;
// 2d array of zeros and ones
int[][] field = IntStream.range(0, n)
        .mapToObj(i -> IntStream.range(0, n)
                .map(j -> i + j < n - 1 ? 0 : 1)
                .toArray())
        .toArray(int[][]::new);
String[] staircase = Stream.concat(
        // rows of a 2d array with a right border
        Arrays.stream(field)
                .map(row -> IntStream.range(0, n)
                        .mapToObj(i -> new String[]{
                                // upper row of square with an upper border
                                row[i] == 0 ? "    " : "+---"
                                        // add a right border to the last element
                                        + (i < n - 1 ? "" : "+"),
                                // lower row of square with a left border
                                row[i] == 0 ? "    " : "|   "
                                        // add a right border to the last element
                                        + (i < n - 1 ? "" : "|")})
                        // reduce Stream<String[]> to a single array String[]
                        .reduce((arr1, arr2) -> IntStream.range(0, 2)
                                .mapToObj(j -> arr1[j] + arr2[j])
                                .toArray(String[]::new))
                        .orElse(new String[]{}))
                .flatMap(Arrays::stream),
        // lower border row
        Stream.of(IntStream.range(0, n)
                .mapToObj(i -> "+---" + (i < n - 1 ? "" : "+"))
                .collect(Collectors.joining())))
        .toArray(String[]::new);
// output
System.out.println("n=" + n);
Arrays.stream(staircase).forEach(System.out::println);

See also: Best way to make a border for a 2D array?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM