novice_programmer
novice_programmer

Reputation: 37

Best way to make a border for a 2D array?

I am currently working with 2D arrays, and while I find them simple to work with, I often face challenges with creating borders for them and the steps to approach it. For example, I'm redoing a Battleship game I made in python. The python version doesn't have a border, but for the java version, I want to tackle the challenge.

I have tried creating the border in the method that initializes the board, but that lead to formatting issues when I called the board in the main method. Now I'm handling the border in the main with a nested for-loop, and while the results have gotten better, the border is still incomplete. I'm trying to create this border I found online:

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

But I haven't been successful. Here is my code:

public static String[][] Battlefield() {
    int row;
    int col;
    int cap_start = 65;

    //Makes board
    String[][] BattleBoard = new String[11][11];

    for (row = 0; row < BattleBoard.length; row++) {
        for (col = 0; col < BattleBoard[row].length; col++) {
            if (row == 0) {
                //System.out.print(
                //      "  " + Character.toString((char) cap_start) + "   ");
                BattleBoard[row][col] =
                        "  " + Character.toString((char) cap_start) + "   ";
                cap_start++;
            } else if (col == 0) {
                //Gives us 0-9
                //System.out.print(Integer.toString(row - 1) + " ");
                BattleBoard[row][col] = (Integer.toString(row - 1)) + "   ";
            } else {
                //System.out.print(" ");
                BattleBoard[row][col] = "   ";
            }
        }
    }
    return BattleBoard;
}
public static void main(String[] args) {
    Scanner userInput = new Scanner(System.in);
    Scanner colInput = new Scanner(System.in);
    Scanner rowInput = new Scanner(System.in);

    String player_col = "";
    String player_row = "";
    String[][] gameBoard = Battlefield();

    for (int row = 0; row < gameBoard.length; row++) {
        for (int col = 0; col < gameBoard[row].length; col++) {
            System.out.print(gameBoard[row][col] + "  |");
            if (row <= gameBoard.length - 1)
                System.out.print("+---+");
        }
        System.out.println();
    }
}

Upvotes: 1

Views: 1729

Answers (2)

user15402945
user15402945

Reputation:

You can represent each cell of the field as an almost square, consisting of two rows: an upper border and an element with a right border, using the box-drawing characters:

───┼
 X │

Screenshot:

almost square

The output consists of three parts: upper row of letters, then a field with a left column of numbers and a lower border row. As a result, the entire field with ships may look like this:

   │ A │ B │ C │ D │ E │ F │ G │ H │ I │ J │
───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
 1 │   │   │ X │   │   │   │ X │ X │ X │   │
───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
 2 │ X │   │   │   │   │   │   │   │   │   │
───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
 3 │   │   │ X │ X │ X │ X │   │   │   │   │
───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
 4 │   │   │   │   │   │   │   │   │   │ X │
───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
 5 │   │   │   │   │   │   │   │   │   │ X │
───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
 6 │   │   │ X │   │   │   │ X │   │   │ X │
───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
 7 │ X │   │   │   │   │   │ X │   │   │   │
───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
 8 │ X │   │   │   │   │   │   │   │   │   │
───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
 9 │   │   │   │   │ X │   │   │   │   │ X │
───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
10 │   │   │   │   │ X │   │   │   │   │   │
───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘

Screenshot:

field with ships

Try it online!

public static String[] outputField(String[][] field, int n) {
    return Stream.of(
            // upper row of letters
            Stream.of(IntStream.range(-1, n)
                // first an empty square
                .mapToObj(i -> i < 0 ? "   │" :
                    // then squares with letters
                    " " + Character.toString('A' + i) + " │")
                .collect(Collectors.joining())),
            // field with a left column of numbers
            IntStream.range(0, n)
                // row of the field, line of squares
                .mapToObj(i -> IntStream.range(0, n)
                    // first a square with a number, then squares of the field
                    .mapToObj(j -> new String[]{
                        // upper row of square with an upper border
                        (j == 0 ? "───┼" : "")
                                + "───" + (j < n - 1 ? "┼" : "┤"),
                        // lower row of square with element and right border
                        (j == 0 ? String.format("%2d", (i + 1)) + " │" : "")
                                + " " + field[i][j] + " │"})
                    // 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(-1, n)
                .mapToObj(i -> i < n - 1 ? "───┴" : "───┘")
                .collect(Collectors.joining())))
            .flatMap(Function.identity())
            .toArray(String[]::new);
}
public static void main(String[] args) {
    int n = 10;
    String[][] field = IntStream.range(0, n)
            .mapToObj(i -> new String[n])
            .peek(row -> Arrays.fill(row, " "))
            .toArray(String[][]::new);

    // four-pipe ship
    field[2][2] = field[2][3] = field[2][4] = field[2][5] = "X";
    // three-pipe ships
    field[0][6] = field[0][7] = field[0][8] = "X";
    field[3][9] = field[4][9] = field[5][9] = "X";
    // two-pipe ships
    field[5][6] = field[6][6] = "X";
    field[8][4] = field[9][4] = "X";
    field[6][0] = field[7][0] = "X";
    // one-pipe ships
    field[0][2] = "X";
    field[1][0] = "X";
    field[5][2] = "X";
    field[8][9] = "X";

    // output
    Arrays.stream(outputField(field, n)).forEach(System.out::println);
}

See also:
Formatting 2d array of numbers
How to draw a staircase with Java?

Upvotes: 1

Gilbert Le Blanc
Gilbert Le Blanc

Reputation: 51445

Here's something I put together.

       A     B     C     D     E     F     G     H     I     J     K     
    +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
  1 +     +     +     +     +     +     +     +     +     +     +     +
    +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
  2 +     +     +     +     +     +     +     +     +     +     +     +
    +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
  3 +     +     +     +     +     +     +     +     +     +     +     +
    +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
  4 +     +     +     +     +  S  +     +     +     +     +     +     +
    +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
  5 +     +     +     +     +  S  +     +     +     +     +     +     +
    +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
  6 +     +     +     +     +  S  +     +     +     +     +     +     +
    +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
  7 +     +     +     +     +  S  +     +     +     +     +     +     +
    +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
  8 +     +     +     +     +  S  +     +     +     +     +     +     +
    +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
  9 +     +     +     +     +     +     +     +     +     +     +     +
    +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
 10 +     +     +     +     +     +     +     +     +     +     +     +
    +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
 11 +     +     +     +     +     +     +     +     +     +     +     +
    +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+

I created a two-dimensional char grid to hold the ship's position, hits, misses, and water.

I used several StringBuilders to create the display of the grid. The display of the grid is made up of Strings. The actual grid array is the logical model.

I put one ship in the grid so you can see what it looks like.

I broke the displayGrid method into three subordinate methods. Divide the work and you can focus on each part of the display separately.

In Java, class names start with an upper-case letter. Field and method names start with a lower-case letter. Class names are usually noun-verb combinations. Method names are usually verb-noun combinations. Generally, it's a good idea to get out of the static world as quickly as you can.

Here's the complete runnable code.

public class BattleshipDisplay {

    public static void main(String[] args) {
        BattleshipDisplay bd = new BattleshipDisplay();
        char[][]  grid = bd.createGrid();
        System.out.println(bd.displayGrid(grid));
    }

    public char[][] createGrid() {
        char[][] grid = new char[11][11];
        
        for (int i = 0; i < grid.length; i++) {
            for (int j = 0; j < grid[i].length; j++) {
                grid[i][j] = ' ';
            }
        }
        
        grid[3][4] = 'S';
        grid[4][4] = 'S';
        grid[5][4] = 'S';
        grid[6][4] = 'S';
        grid[7][4] = 'S';
        
        return grid;
    }
    
    public String displayGrid(char[][] grid) {
        StringBuilder builder = new StringBuilder();
        String section = "+-----";
        
        builder.append(printHeaderLine(grid));
        builder.append(printDashedLine(grid, section));
        builder.append(printGrid(grid, section));
        
        return builder.toString();
    }

    private StringBuilder printHeaderLine(char[][] grid) {
        StringBuilder builder = new StringBuilder();
        
        builder.append("       ");
        for (int i = 0; i < grid.length; i++) {
            builder.append((char) ((int) 'A' + i));
            builder.append("     ");
        }
        
        builder.append(System.lineSeparator());
        return builder;
    }

    private StringBuilder printGrid(char[][] grid, String section) {
        StringBuilder builder = new StringBuilder();
        
        for (int i = 0; i < grid.length; i++) {
            builder.append(String.format("%3d", (i + 1)));
            builder.append(" ");
            for (int j = 0; j < grid[i].length; j++) {
                builder.append("+  ");
                builder.append(grid[i][j]);
                builder.append("  ");
            }
            
            builder.append("+");
            builder.append(System.lineSeparator());
            builder.append(printDashedLine(grid, section));
        }
        
        return builder;
    }
    
    private StringBuilder printDashedLine(char[][] grid, String section) {
        StringBuilder builder = new StringBuilder();
        
        builder.append("    ");
        for (int i = 0; i < grid.length; i++) {
            builder.append(section);
        }
        
        builder.append("+");
        builder.append(System.lineSeparator());
        
        return builder;
    }

}

Upvotes: 2

Related Questions