{"id":"multidimensional-arrays-neighbors","slug":"neighbors","title":"Neighbors: the cells around a cell","text":"In the game Minesweeper, a field of squares hides a few mines. Every square without a mine shows a number: how many of the squares around it hide a mine. A program can keep the mines in a `boolean[][]`, with `true` where a mine is, and work out each number from the grid.\n\n### The eight cells around a cell\n\nThe cells around row `row`, column `column` are in the rows `row - 1` to `row + 1` and the columns `column - 1` to `column + 1`: a block of 3 by 3 cells, without the one in the middle.\n\n| | column - 1 | column | column + 1 |\n|---|---|---|---|\n| **row - 1** | neighbor | neighbor | neighbor |\n| **row** | neighbor | the cell itself | neighbor |\n| **row + 1** | neighbor | neighbor | neighbor |\n\nTwo loops go through the block, and `continue` (from module 8) skips the cell in the middle. This version works in the middle of the field, and crashes at its edge:\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        boolean[][] mines = {\n            {true, false, false, false},\n            {false, false, true, false},\n            {true, true, false, false}\n        };\n        System.out.println(countAround(mines, 1, 1));\n        System.out.println(countAround(mines, 1, 2));\n        System.out.println(countAround(mines, 0, 3));\n    }\n\n    public static int countAround(boolean[][] mines, int row, int column) {\n        int count = 0;\n        for (int r = row - 1; r <= row + 1; r++) {\n            for (int c = column - 1; c <= column + 1; c++) {\n                if (r == row && c == column) {\n                    continue;\n                }\n                if (mines[r][c]) {\n                    count++;\n                }\n            }\n        }\n        return count;\n    }\n}\n```\n\n```output\n4\n1\n```\n\n```crash\nException in thread \"main\" java.lang.ArrayIndexOutOfBoundsException: Index -1 out of bounds for length 3\n\tat Main.countAround(Main.java:20)\n\tat Main.main(Main.java:10)\n```\n\nRow 1, column 1 has four mines around it: up and to the left, to the right, below, and below to the left. Row 0, column 3 is in the top right corner. The rows around it start at -1, and `mines[-1]` doesn't exist.\n\n### Staying inside the grid\n\nA cell on the edge has fewer neighbors: 5 on a side, 3 in a corner. Before the program reads a cell, it checks both indexes: the row from 0 to `mines.length - 1`, and the column from 0 to the length of that row minus one. Here that check is a method of its own, which also gives the rule a name: outside the field, there are no mines.\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        boolean[][] mines = {\n            {true, false, false, false},\n            {false, false, true, false},\n            {true, true, false, false}\n        };\n        System.out.println(hasMine(mines, 2, 0));\n        System.out.println(hasMine(mines, -1, 2));\n        System.out.println(hasMine(mines, 1, 4));\n    }\n\n    public static boolean hasMine(boolean[][] mines, int row, int column) {\n        if (row < 0 || row >= mines.length) {\n            return false;\n        }\n        if (column < 0 || column >= mines[row].length) {\n            return false;\n        }\n        return mines[row][column];\n    }\n}\n```\n\n```output\ntrue\nfalse\nfalse\n```\n\nThe order of the checks matters: `mines[row].length` would itself crash for row -1, so the row is checked first. In one condition, `r >= 0 && r < mines.length && c >= 0 && c < mines[r].length && mines[r][c]` does the same: `&&` stops at the first part that's false, so the parts after a bad index are never run.\n\n### Up, down, left and right\n\nSome grids count only four neighbors: the cells above, below, to the left and to the right. Two small arrays can list the steps to each of them, the same index in both arrays making one step:\n\n```java\nint[] rowSteps = {-1, 1, 0, 0};\nint[] columnSteps = {0, 0, -1, 1};\nfor (int i = 0; i < rowSteps.length; i++) {\n    int r = row + rowSteps[i];\n    int c = column + columnSteps[i];\n    // check that r and c are inside the grid, then use grid[r][c]\n}\n```\n\nStep -1 for the row is the cell above, step 1 below; step -1 for the column is the cell to the left, step 1 to the right. With eight pairs, the same loop would cover the diagonal neighbors too.\n","task":"Make `countAround` work for every cell of the field, at the edges and in the corners too: a place outside the field has no mine. Check the indexes in the loops, or write a method like `hasMine` and call it. The check runs:\n\n```java\nboolean[][] mines = {\n    {true, false, false, false},\n    {false, false, true, false},\n    {true, true, false, false}\n};\nSystem.out.println(countAround(mines, 0, 3));\nSystem.out.println(countAround(mines, 1, 1));\nSystem.out.println(countAround(mines, 2, 2));\nSystem.out.println(countAround(mines, 0, 0));\n```\n\nand expects:\n\n```\n1\n4\n2\n0\n```\n","kind":"code","seed":"public class Main {\n    public static void main(String[] args) {\n        boolean[][] mines = {\n            {true, false, false, false},\n            {false, false, true, false},\n            {true, true, false, false}\n        };\n        System.out.println(countAround(mines, 0, 3));\n        System.out.println(countAround(mines, 1, 1));\n        System.out.println(countAround(mines, 2, 2));\n        System.out.println(countAround(mines, 0, 0));\n    }\n\n    public static int countAround(boolean[][] mines, int row, int column) {\n        int count = 0;\n        for (int r = row - 1; r <= row + 1; r++) {\n            for (int c = column - 1; c <= column + 1; c++) {\n                if (r == row && c == column) {\n                    continue;\n                }\n                if (mines[r][c]) {\n                    count++;\n                }\n            }\n        }\n        return count;\n    }\n}\n","solution":"public class Main {\n    public static void main(String[] args) {\n        boolean[][] mines = {\n            {true, false, false, false},\n            {false, false, true, false},\n            {true, true, false, false}\n        };\n        System.out.println(countAround(mines, 0, 3));\n        System.out.println(countAround(mines, 1, 1));\n        System.out.println(countAround(mines, 2, 2));\n        System.out.println(countAround(mines, 0, 0));\n    }\n\n    public static int countAround(boolean[][] mines, int row, int column) {\n        int count = 0;\n        for (int r = row - 1; r <= row + 1; r++) {\n            for (int c = column - 1; c <= column + 1; c++) {\n                if (r == row && c == column) {\n                    continue;\n                }\n                if (r >= 0 && r < mines.length && c >= 0 && c < mines[r].length && mines[r][c]) {\n                    count++;\n                }\n            }\n        }\n        return count;\n    }\n}\n","hints":["Read `mines[r][c]` only when `r` is from 0 to `mines.length - 1` and `c` from 0 to `mines[r].length - 1`.","Put the checks in front of the cell in one condition: `r >= 0 && r < mines.length && c >= 0 && c < mines[r].length && mines[r][c]`. `&&` stops at the first false part, so a bad index is never used."],"tests":[{"name":"Test 1","stdin":"","call":"boolean[][] mines = {\n    {true, false, false, false},\n    {false, false, true, false},\n    {true, true, false, false}\n};\nSystem.out.println(countAround(mines, 0, 3));\nSystem.out.println(countAround(mines, 1, 1));\nSystem.out.println(countAround(mines, 2, 2));\nSystem.out.println(countAround(mines, 0, 0));\n","expect":"1\n4\n2\n0","hidden":false},{"name":"Test 2","stdin":"","call":"boolean[][] field = {\n    {true}\n};\nSystem.out.println(countAround(field, 0, 0));\n","expect":"0","hidden":true},{"name":"Test 3","stdin":"","call":"boolean[][] field = new boolean[2][5];\nfor (int row = 0; row < field.length; row++) {\n    for (int column = 0; column < field[row].length; column++) {\n        field[row][column] = true;\n    }\n}\nSystem.out.println(countAround(field, 0, 0) + \" \" + countAround(field, 1, 4) + \" \" + countAround(field, 0, 2) + \" \" + countAround(field, 1, 1));\n","expect":"3 3 5 5","hidden":true},{"name":"Test 4","stdin":"","call":"boolean[][] field = {\n    {true},\n    {true},\n    {false},\n    {true}\n};\nSystem.out.println(countAround(field, 0, 0) + \" \" + countAround(field, 2, 0) + \" \" + countAround(field, 3, 0));\n","expect":"1 2 0","hidden":true}],"require":[],"forbid":[{"pattern":"\\bcatch\\b","message":"Check the indexes before reading a cell, instead of catching the exception."}],"more":[{"task":"Now the whole field, as the game shows it at the end. Write a method `printField(boolean[][] mines)` that prints the field one row per line: `*` for a mine, and for every other square the number of mines around it, with nothing between the squares. `countAround` is ready, with the check of the indexes. For the field of this step, the check prints:\n\n```\n*211\n34*1\n**21\n```\n","kind":"code","seed":"public class Main {\n    public static void main(String[] args) {\n        boolean[][] mines = {\n            {true, false, false, false},\n            {false, false, true, false},\n            {true, true, false, false}\n        };\n        printField(mines);\n    }\n\n    // Write the printField method here.\n\n    public static int countAround(boolean[][] mines, int row, int column) {\n        int count = 0;\n        for (int r = row - 1; r <= row + 1; r++) {\n            for (int c = column - 1; c <= column + 1; c++) {\n                if (r == row && c == column) {\n                    continue;\n                }\n                if (r >= 0 && r < mines.length && c >= 0 && c < mines[r].length && mines[r][c]) {\n                    count++;\n                }\n            }\n        }\n        return count;\n    }\n}\n","solution":"public class Main {\n    public static void main(String[] args) {\n        boolean[][] mines = {\n            {true, false, false, false},\n            {false, false, true, false},\n            {true, true, false, false}\n        };\n        printField(mines);\n    }\n\n    public static void printField(boolean[][] mines) {\n        for (int row = 0; row < mines.length; row++) {\n            for (int column = 0; column < mines[row].length; column++) {\n                if (mines[row][column]) {\n                    System.out.print(\"*\");\n                } else {\n                    System.out.print(countAround(mines, row, column));\n                }\n            }\n            System.out.println();\n        }\n    }\n\n    public static int countAround(boolean[][] mines, int row, int column) {\n        int count = 0;\n        for (int r = row - 1; r <= row + 1; r++) {\n            for (int c = column - 1; c <= column + 1; c++) {\n                if (r == row && c == column) {\n                    continue;\n                }\n                if (r >= 0 && r < mines.length && c >= 0 && c < mines[r].length && mines[r][c]) {\n                    count++;\n                }\n            }\n        }\n        return count;\n    }\n}\n","hints":["The method starts `public static void printField(boolean[][] mines) {`. Go through the cells with a loop over the rows and, inside it, a loop over the columns of that row.","In each cell, `print` either `\"*\"` or `countAround(mines, row, column)`. After the inner loop, `println()` ends the row."],"tests":[{"name":"Test 1","stdin":"","call":"boolean[][] mines = {\n    {true, false, false, false},\n    {false, false, true, false},\n    {true, true, false, false}\n};\nprintField(mines);\n","expect":"*211\n34*1\n**21","hidden":false},{"name":"printField(new boolean[2][3]);","stdin":"","call":"printField(new boolean[2][3]);\n","expect":"000\n000","hidden":true},{"name":"Test 3","stdin":"","call":"boolean[][] mines = {\n    {false, true, false, false, true}\n};\nprintField(mines);\n","expect":"1*11*","hidden":true},{"name":"Test 4","stdin":"","call":"boolean[][] mines = new boolean[3][3];\nmines[1][1] = true;\nprintField(mines);\nboolean[][] full = {\n    {true, true},\n    {true, true}\n};\nprintField(full);\n","expect":"111\n1*1\n111\n**\n**","hidden":true}],"require":[],"forbid":[]},{"task":"A hiking map gives the height of the ground in each square, in meters. A square is a **hilltop** when it's higher than each of its neighbors above, below, to the left and to the right. The diagonal squares don't count here, and a square on the edge simply has fewer neighbors. Write a method `printHilltops(int[][] heights)` that prints every hilltop, row by row from the top and from left to right in each row, like `Row 1, column 1: 140 m` (rows and columns counted from 0), and then the number of hilltops. The check passes this map:\n\n```java\nint[][] heights = {\n    {120, 135, 130, 110},\n    {125, 140, 128, 132},\n    {118, 122, 126, 121}\n};\nprintHilltops(heights);\n```\n\nand expects:\n\n```\nRow 1, column 1: 140 m\nRow 1, column 3: 132 m\nHilltops: 2\n```\n","kind":"code","seed":"public class Main {\n    public static void main(String[] args) {\n        int[][] heights = {\n            {120, 135, 130, 110},\n            {125, 140, 128, 132},\n            {118, 122, 126, 121}\n        };\n        printHilltops(heights);\n    }\n\n    // Write the printHilltops method here.\n}\n","solution":"public class Main {\n    public static void main(String[] args) {\n        int[][] heights = {\n            {120, 135, 130, 110},\n            {125, 140, 128, 132},\n            {118, 122, 126, 121}\n        };\n        printHilltops(heights);\n    }\n\n    public static void printHilltops(int[][] heights) {\n        int[] rowSteps = {-1, 1, 0, 0};\n        int[] columnSteps = {0, 0, -1, 1};\n        int count = 0;\n        for (int row = 0; row < heights.length; row++) {\n            for (int column = 0; column < heights[row].length; column++) {\n                boolean hilltop = true;\n                for (int i = 0; i < rowSteps.length; i++) {\n                    int r = row + rowSteps[i];\n                    int c = column + columnSteps[i];\n                    if (r >= 0 && r < heights.length && c >= 0 && c < heights[r].length && heights[r][c] >= heights[row][column]) {\n                        hilltop = false;\n                    }\n                }\n                if (hilltop) {\n                    System.out.println(\"Row \" + row + \", column \" + column + \": \" + heights[row][column] + \" m\");\n                    count++;\n                }\n            }\n        }\n        System.out.println(\"Hilltops: \" + count);\n    }\n}\n","hints":["Go through every square. For each one, start from `boolean hilltop = true;` and look at the four neighbors, with the step arrays of this step or with four separate checks.","A neighbor that's inside the map and at least as high (`>=`) as the square means it's not a hilltop. After the four neighbors, print the square if it's still a hilltop, and count it."],"tests":[{"name":"Test 1","stdin":"","call":"int[][] heights = {\n    {120, 135, 130, 110},\n    {125, 140, 128, 132},\n    {118, 122, 126, 121}\n};\nprintHilltops(heights);\n","expect":"Row 1, column 1: 140 m\nRow 1, column 3: 132 m\nHilltops: 2","hidden":false},{"name":"Test 2","stdin":"","call":"int[][] heights = {\n    {100, 100},\n    {100, 100}\n};\nprintHilltops(heights);\n","expect":"Hilltops: 0","hidden":true},{"name":"Test 3","stdin":"","call":"int[][] heights = {\n    {3, 5, 4, 6}\n};\nprintHilltops(heights);\n","expect":"Row 0, column 1: 5 m\nRow 0, column 3: 6 m\nHilltops: 2","hidden":true},{"name":"Test 4","stdin":"","call":"int[][] heights = {\n    {9, 1, 9},\n    {1, 5, 1},\n    {9, 1, 9}\n};\nprintHilltops(heights);\n","expect":"Row 0, column 0: 9 m\nRow 0, column 2: 9 m\nRow 1, column 1: 5 m\nRow 2, column 0: 9 m\nRow 2, column 2: 9 m\nHilltops: 5","hidden":true},{"name":"Test 5","stdin":"","call":"int[][] heights = {\n    {10, 20, 30},\n    {20, 30, 40},\n    {30, 40, 50},\n    {20, 60, 40}\n};\nprintHilltops(heights);\n","expect":"Row 2, column 2: 50 m\nRow 3, column 1: 60 m\nHilltops: 2","hidden":true}],"require":[],"forbid":[]}]}