{"id":"game-of-life","title":"The Game of Life","summary":"A grid of cells that live and die by four simple rules. Count each cell's neighbors, work out the next generation, let the board wrap around at its edges, read patterns from a file, and watch a glider travel, one printed generation after another.","after":"multidimensional-arrays","intro":"The **Game of Life** was invented by the mathematician John Horton Conway around 1970. It isn't a game you play: you set up a pattern and watch what happens. The board is a grid of **cells**, and each cell is either alive or dead. Every cell has eight **neighbors**: the cells above, below, to the left, to the right and on the four diagonals. From one **generation** to the next, every cell follows the same rules at the same time:\n\n- A live cell with 2 or 3 live neighbors stays alive.\n- A live cell with fewer than 2 live neighbors dies, as if lonely, and one with more than 3 dies, as if overcrowded.\n- A dead cell with exactly 3 live neighbors comes alive.\n- Any other dead cell stays dead.\n\nThat's all, and yet some patterns blink, some stay still, some die out, and some travel across the board. In this project you write a program that reads a pattern from a file and prints a few generations of it as text, with `O` for a live cell and `.` for a dead one.\n\nWhen it's finished, the program reads three lines: the name of a pattern file, how many generations to show, and `wrap` or `edges` (whether the board wraps around at its edges). With this `glider.txt`, where the lines that start with `!` are comments,\n\n```text\n!Name: Glider\n!It moves one cell down and one to the right every four generations.\n.O....\n..O...\nOOO...\n......\n......\n```\n\nand the input `glider.txt`, `4` and `wrap`, it prints:\n\n```text\nGeneration 0: 5 alive\n.O....\n..O...\nOOO...\n......\n......\n\nGeneration 1: 5 alive\n......\nO.O...\n.OO...\n.O....\n......\n\nGeneration 2: 5 alive\n......\n..O...\nO.O...\n.OO...\n......\n\nGeneration 3: 5 alive\n......\n.O....\n..OO..\n.OO...\n......\n\nGeneration 4: 5 alive\n......\n..O...\n...O..\n.OOO..\n......\n```\n\nAfter four generations the glider has its first shape again, one row lower and one column further right.\n\n### What you need\n\nEverything up to the end of part 12. Above all two-dimensional arrays, nested loops and the cells around a cell (module 47), and also classes with a constructor and `toString` (modules 17 and 18), StringBuilder (module 39), and reading a file with `Files.readAllLines` and `throws IOException` (module 42).\n\n### How you build it\n\nThe program has two classes: `Board`, which keeps the cells in a `boolean[][]` and knows the rules, and `Main`, which reads the pattern and prints the generations. Most of the work is in `Board`, and the checks of the first milestones call its methods directly.\n\n1. **A grid of cells:** create the board, bring cells to life, and show it as text.\n2. **Counting neighbors:** how many live cells are around a cell, and whether it lives on.\n3. **One generation:** the whole board takes one step, every cell at the same time.\n4. **Wrapping around:** the edges of the board meet, so a glider leaves on one side and comes back on the other.\n5. **Patterns from a file:** read a board from a text file of `O` and `.`.\n6. **Generations as text:** `main` puts it all together, and stops early when nothing changes.\n","milestones":[{"id":"grid","title":"A grid of cells","task":"`Board.java` has the field for the cells: `cells` is a `boolean[][]`, where `true` means the cell is alive. `Main` already uses some of these methods, so the program compiles once you've written them all. Write in `Board`:\n\n1. A constructor `Board(int rows, int columns)` that creates a grid of that many rows and columns, with every cell dead.\n2. `getRows()` and `getColumns()`, which return the number of rows and of columns. The boards always have at least one row and one column.\n3. `setAlive(int row, int column)`, which makes that cell alive, and `isAlive(int row, int column)`, which returns whether it's alive. Rows and columns are counted from 0, as array indexes are.\n4. `countAlive()`, which returns how many cells of the board are alive.\n5. `toString()`, which returns the board one row per line: `O` (the capital letter) for a live cell and `.` for a dead one. Put a line break (`\\n`) between the rows, but not after the last one, so `System.out.println(board)` prints no empty line at the end.\n\nThe check runs:\n\n```java\nBoard board = new Board(3, 5);\nboard.setAlive(0, 1);\nboard.setAlive(1, 2);\nboard.setAlive(2, 4);\nSystem.out.println(board.getRows() + \" by \" + board.getColumns());\nSystem.out.println(board);\nSystem.out.println(board.countAlive());\nSystem.out.println(board.isAlive(1, 2));\nSystem.out.println(board.isAlive(2, 3));\n```\n\nand expects:\n\n```\n3 by 5\n.O...\n..O..\n....O\n3\ntrue\nfalse\n```\n","kind":"code","seed":"// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Board board = new Board(4, 6);\n        board.setAlive(0, 1);\n        board.setAlive(1, 2);\n        board.setAlive(2, 0);\n        board.setAlive(2, 1);\n        board.setAlive(2, 2);\n        System.out.println(board);\n        System.out.println(board.countAlive() + \" cells are alive.\");\n    }\n}\n\n// ==== Board.java ====\npublic class Board {\n    private boolean[][] cells;\n\n}\n","solution":"// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Board board = new Board(4, 6);\n        board.setAlive(0, 1);\n        board.setAlive(1, 2);\n        board.setAlive(2, 0);\n        board.setAlive(2, 1);\n        board.setAlive(2, 2);\n        System.out.println(board);\n        System.out.println(board.countAlive() + \" cells are alive.\");\n    }\n}\n\n// ==== Board.java ====\npublic class Board {\n    private boolean[][] cells;\n\n    public Board(int rows, int columns) {\n        this.cells = new boolean[rows][columns];\n    }\n\n    public int getRows() {\n        return this.cells.length;\n    }\n\n    public int getColumns() {\n        return this.cells[0].length;\n    }\n\n    public void setAlive(int row, int column) {\n        this.cells[row][column] = true;\n    }\n\n    public boolean isAlive(int row, int column) {\n        return this.cells[row][column];\n    }\n\n    public int countAlive() {\n        int count = 0;\n        for (int row = 0; row < getRows(); row++) {\n            for (int column = 0; column < getColumns(); column++) {\n                if (this.cells[row][column]) {\n                    count++;\n                }\n            }\n        }\n        return count;\n    }\n\n    public String toString() {\n        StringBuilder text = new StringBuilder();\n        for (int row = 0; row < getRows(); row++) {\n            if (row > 0) {\n                text.append(\"\\n\");\n            }\n            for (int column = 0; column < getColumns(); column++) {\n                if (this.cells[row][column]) {\n                    text.append(\"O\");\n                } else {\n                    text.append(\".\");\n                }\n            }\n        }\n        return text.toString();\n    }\n}\n","hints":["The constructor only has to create the array: a new `boolean` array starts all `false`, so every cell is dead. The getters need no fields of their own: the number of rows is the array's length, and the number of columns is the length of one row. `countAlive` and `toString` both go through every cell with two loops, rows outside and columns inside.","In code: `this.cells = new boolean[rows][columns];`, then `this.cells.length` and `this.cells[0].length`. In `toString`, append `\"\\n\"` to a StringBuilder before every row except the first one (`if (row > 0)`)."],"tests":[{"name":"A small board","stdin":"","call":"Board board = new Board(3, 5);\nboard.setAlive(0, 1);\nboard.setAlive(1, 2);\nboard.setAlive(2, 4);\nSystem.out.println(board.getRows() + \" by \" + board.getColumns());\nSystem.out.println(board);\nSystem.out.println(board.countAlive());\nSystem.out.println(board.isAlive(1, 2));\nSystem.out.println(board.isAlive(2, 3));\n","expect":"3 by 5\n.O...\n..O..\n....O\n3\ntrue\nfalse","hidden":false},{"name":"An empty board","stdin":"","call":"Board board = new Board(2, 7);\nSystem.out.println(board.getRows() + \" by \" + board.getColumns());\nSystem.out.println(board);\nSystem.out.println(board.countAlive());\nSystem.out.println(board.isAlive(1, 6));\n","expect":"2 by 7\n.......\n.......\n0\nfalse","hidden":true},{"name":"The same cell twice, and the corners","stdin":"","call":"Board board = new Board(4, 4);\nboard.setAlive(3, 3);\nboard.setAlive(3, 3);\nboard.setAlive(0, 0);\nboard.setAlive(0, 3);\nSystem.out.println(board);\nSystem.out.println(board.countAlive());\nSystem.out.println(board.isAlive(0, 3));\nSystem.out.println(board.isAlive(3, 0));\n","expect":"O..O\n....\n....\n...O\n3\ntrue\nfalse","hidden":true},{"name":"One column","stdin":"","call":"Board board = new Board(5, 1);\nboard.setAlive(1, 0);\nboard.setAlive(4, 0);\nSystem.out.println(board.getRows() + \" by \" + board.getColumns());\nSystem.out.println(board);\nSystem.out.println(board.countAlive());\n","expect":"5 by 1\n.\nO\n.\n.\nO\n2","hidden":true}],"require":[{"pattern":"new\\s+boolean\\s*\\[","message":"Create the grid in the constructor with `new boolean[rows][columns]`."}],"forbid":[]},{"id":"neighbors","title":"Counting neighbors","task":"Whether a cell lives on depends on its eight neighbors. Add two methods to `Board`:\n\n1. `countNeighbors(int row, int column)` returns how many of the eight cells around that cell are alive. The cell itself doesn't count. A cell on the edge of the board has fewer neighbors: a place outside the board counts as a dead cell.\n2. `willLive(int row, int column)` returns whether the cell is alive in the next generation, by the rules of the game:\n   - a live cell stays alive with 2 or 3 live neighbors, and dies otherwise;\n   - a dead cell comes alive with exactly 3 live neighbors, and stays dead otherwise.\n\nThe check runs:\n\n```java\nBoard board = new Board(4, 5);\nboard.setAlive(1, 1);\nboard.setAlive(1, 2);\nboard.setAlive(1, 3);\nboard.setAlive(0, 4);\nSystem.out.println(board);\nSystem.out.println(board.countNeighbors(1, 2));\nSystem.out.println(board.countNeighbors(0, 2));\nSystem.out.println(board.countNeighbors(0, 0));\nSystem.out.println(board.countNeighbors(3, 4));\nSystem.out.println(board.willLive(1, 2));\nSystem.out.println(board.willLive(1, 1));\nSystem.out.println(board.willLive(0, 2));\nSystem.out.println(board.willLive(2, 2));\n```\n\nand expects:\n\n```\n....O\n.OOO.\n.....\n.....\n2\n3\n1\n0\ntrue\nfalse\ntrue\ntrue\n```\n","kind":"code","seed":"// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Board board = new Board(4, 6);\n        board.setAlive(0, 1);\n        board.setAlive(1, 2);\n        board.setAlive(2, 0);\n        board.setAlive(2, 1);\n        board.setAlive(2, 2);\n        System.out.println(board);\n        System.out.println(board.countAlive() + \" cells are alive.\");\n    }\n}\n\n// ==== Board.java ====\npublic class Board {\n    private boolean[][] cells;\n\n    public Board(int rows, int columns) {\n        this.cells = new boolean[rows][columns];\n    }\n\n    public int getRows() {\n        return this.cells.length;\n    }\n\n    public int getColumns() {\n        return this.cells[0].length;\n    }\n\n    public void setAlive(int row, int column) {\n        this.cells[row][column] = true;\n    }\n\n    public boolean isAlive(int row, int column) {\n        return this.cells[row][column];\n    }\n\n    public int countAlive() {\n        int count = 0;\n        for (int row = 0; row < getRows(); row++) {\n            for (int column = 0; column < getColumns(); column++) {\n                if (this.cells[row][column]) {\n                    count++;\n                }\n            }\n        }\n        return count;\n    }\n\n    public String toString() {\n        StringBuilder text = new StringBuilder();\n        for (int row = 0; row < getRows(); row++) {\n            if (row > 0) {\n                text.append(\"\\n\");\n            }\n            for (int column = 0; column < getColumns(); column++) {\n                if (this.cells[row][column]) {\n                    text.append(\"O\");\n                } else {\n                    text.append(\".\");\n                }\n            }\n        }\n        return text.toString();\n    }\n}\n","solution":"// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Board board = new Board(4, 6);\n        board.setAlive(0, 1);\n        board.setAlive(1, 2);\n        board.setAlive(2, 0);\n        board.setAlive(2, 1);\n        board.setAlive(2, 2);\n        System.out.println(board);\n        System.out.println(board.countAlive() + \" cells are alive.\");\n    }\n}\n\n// ==== Board.java ====\npublic class Board {\n    private boolean[][] cells;\n\n    public Board(int rows, int columns) {\n        this.cells = new boolean[rows][columns];\n    }\n\n    public int getRows() {\n        return this.cells.length;\n    }\n\n    public int getColumns() {\n        return this.cells[0].length;\n    }\n\n    public void setAlive(int row, int column) {\n        this.cells[row][column] = true;\n    }\n\n    public boolean isAlive(int row, int column) {\n        return this.cells[row][column];\n    }\n\n    public int countAlive() {\n        int count = 0;\n        for (int row = 0; row < getRows(); row++) {\n            for (int column = 0; column < getColumns(); column++) {\n                if (this.cells[row][column]) {\n                    count++;\n                }\n            }\n        }\n        return count;\n    }\n\n    public int countNeighbors(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 < getRows() && c >= 0 && c < getColumns() && this.cells[r][c]) {\n                    count++;\n                }\n            }\n        }\n        return count;\n    }\n\n    public boolean willLive(int row, int column) {\n        int neighbors = countNeighbors(row, column);\n        if (this.cells[row][column]) {\n            return neighbors == 2 || neighbors == 3;\n        }\n        return neighbors == 3;\n    }\n\n    public String toString() {\n        StringBuilder text = new StringBuilder();\n        for (int row = 0; row < getRows(); row++) {\n            if (row > 0) {\n                text.append(\"\\n\");\n            }\n            for (int column = 0; column < getColumns(); column++) {\n                if (this.cells[row][column]) {\n                    text.append(\"O\");\n                } else {\n                    text.append(\".\");\n                }\n            }\n        }\n        return text.toString();\n    }\n}\n","hints":["Go through the block of 3 by 3 cells with two loops, from `row - 1` to `row + 1` and from `column - 1` to `column + 1`, and skip the cell in the middle with `continue`, as module 47 did for the mines.","Read `this.cells[r][c]` only when `r` is from 0 to `getRows() - 1` and `c` from 0 to `getColumns() - 1`. Put those checks first in one condition joined with `&&`, then the cell itself.","In `willLive`, count the neighbors once and keep the number in a variable. Then return `neighbors == 2 || neighbors == 3` for a live cell, and `neighbors == 3` for a dead one."],"tests":[{"name":"A row of three","stdin":"","call":"Board board = new Board(4, 5);\nboard.setAlive(1, 1);\nboard.setAlive(1, 2);\nboard.setAlive(1, 3);\nboard.setAlive(0, 4);\nSystem.out.println(board);\nSystem.out.println(board.countNeighbors(1, 2));\nSystem.out.println(board.countNeighbors(0, 2));\nSystem.out.println(board.countNeighbors(0, 0));\nSystem.out.println(board.countNeighbors(3, 4));\nSystem.out.println(board.willLive(1, 2));\nSystem.out.println(board.willLive(1, 1));\nSystem.out.println(board.willLive(0, 2));\nSystem.out.println(board.willLive(2, 2));\n","expect":"....O\n.OOO.\n.....\n.....\n2\n3\n1\n0\ntrue\nfalse\ntrue\ntrue","hidden":false},{"name":"A full board","stdin":"","call":"Board board = new Board(3, 3);\nfor (int row = 0; row < 3; row++) {\n    for (int column = 0; column < 3; column++) {\n        board.setAlive(row, column);\n    }\n}\nSystem.out.println(board.countNeighbors(1, 1));\nSystem.out.println(board.countNeighbors(0, 0));\nSystem.out.println(board.countNeighbors(2, 1));\nSystem.out.println(board.countNeighbors(1, 2));\nSystem.out.println(board.willLive(1, 1));\nSystem.out.println(board.willLive(0, 0));\nSystem.out.println(board.willLive(0, 1));\n","expect":"8\n3\n5\n5\nfalse\ntrue\nfalse","hidden":true},{"name":"Two neighbors are not enough to be born","stdin":"","call":"Board board = new Board(3, 4);\nboard.setAlive(0, 0);\nboard.setAlive(2, 0);\nboard.setAlive(2, 3);\nSystem.out.println(board.countNeighbors(1, 0));\nSystem.out.println(board.willLive(1, 0));\nSystem.out.println(board.countNeighbors(1, 1));\nSystem.out.println(board.willLive(1, 1));\nSystem.out.println(board.willLive(2, 3));\nSystem.out.println(board.countNeighbors(0, 3));\n","expect":"2\nfalse\n2\nfalse\nfalse\n0","hidden":true},{"name":"Four neighbors are too many","stdin":"","call":"Board board = new Board(3, 3);\nboard.setAlive(0, 1);\nboard.setAlive(1, 0);\nboard.setAlive(1, 1);\nboard.setAlive(1, 2);\nboard.setAlive(2, 1);\nSystem.out.println(board.countNeighbors(1, 1));\nSystem.out.println(board.willLive(1, 1));\nSystem.out.println(board.willLive(0, 1));\nSystem.out.println(board.willLive(0, 0));\nSystem.out.println(board.countNeighbors(2, 2));\n","expect":"4\nfalse\ntrue\ntrue\n3","hidden":true},{"name":"A single row","stdin":"","call":"Board board = new Board(1, 4);\nboard.setAlive(0, 0);\nboard.setAlive(0, 1);\nboard.setAlive(0, 3);\nSystem.out.println(board.countNeighbors(0, 2));\nSystem.out.println(board.countNeighbors(0, 0));\nSystem.out.println(board.willLive(0, 2));\n","expect":"2\n1\nfalse","hidden":true}],"require":[],"forbid":[{"pattern":"\\bcatch\\b","message":"Check the indexes before reading a cell, instead of catching the exception."}]},{"id":"generation","title":"One generation","task":"Now the whole board takes a step. Every cell changes **at the same time**: the next generation is worked out from the current one alone. So the program can't change the cells one by one in `cells`, because a cell it has already changed would give its neighbors the wrong count. Build the next generation in a new array instead, and put it in place when it's complete.\n\n1. Add a field `generation`, an `int` that is 0 for a new board.\n2. Write `step()`, which creates a new `boolean[][]` of the same size, fills it with `willLive` for every cell, and then makes it the board's `cells`. It also adds one to `generation`.\n3. Write `getGeneration()`, which returns how many steps the board has taken.\n\nTo watch it in your own program, add `board.step();` and another `System.out.println(board);` at the end of `main`. The check runs:\n\n```java\nBoard board = new Board(5, 5);\nboard.setAlive(2, 1);\nboard.setAlive(2, 2);\nboard.setAlive(2, 3);\nboard.step();\nSystem.out.println(board);\nSystem.out.println(board.getGeneration());\nboard.step();\nSystem.out.println(board);\nSystem.out.println(board.getGeneration());\n```\n\nand expects a **blinker**, a row of three that turns into a column and back:\n\n```\n.....\n..O..\n..O..\n..O..\n.....\n1\n.....\n.....\n.OOO.\n.....\n.....\n2\n```\n","kind":"code","seed":"// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Board board = new Board(4, 6);\n        board.setAlive(0, 1);\n        board.setAlive(1, 2);\n        board.setAlive(2, 0);\n        board.setAlive(2, 1);\n        board.setAlive(2, 2);\n        System.out.println(board);\n        System.out.println(board.countAlive() + \" cells are alive.\");\n    }\n}\n\n// ==== Board.java ====\npublic class Board {\n    private boolean[][] cells;\n\n    public Board(int rows, int columns) {\n        this.cells = new boolean[rows][columns];\n    }\n\n    public int getRows() {\n        return this.cells.length;\n    }\n\n    public int getColumns() {\n        return this.cells[0].length;\n    }\n\n    public void setAlive(int row, int column) {\n        this.cells[row][column] = true;\n    }\n\n    public boolean isAlive(int row, int column) {\n        return this.cells[row][column];\n    }\n\n    public int countAlive() {\n        int count = 0;\n        for (int row = 0; row < getRows(); row++) {\n            for (int column = 0; column < getColumns(); column++) {\n                if (this.cells[row][column]) {\n                    count++;\n                }\n            }\n        }\n        return count;\n    }\n\n    public int countNeighbors(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 < getRows() && c >= 0 && c < getColumns() && this.cells[r][c]) {\n                    count++;\n                }\n            }\n        }\n        return count;\n    }\n\n    public boolean willLive(int row, int column) {\n        int neighbors = countNeighbors(row, column);\n        if (this.cells[row][column]) {\n            return neighbors == 2 || neighbors == 3;\n        }\n        return neighbors == 3;\n    }\n\n    public String toString() {\n        StringBuilder text = new StringBuilder();\n        for (int row = 0; row < getRows(); row++) {\n            if (row > 0) {\n                text.append(\"\\n\");\n            }\n            for (int column = 0; column < getColumns(); column++) {\n                if (this.cells[row][column]) {\n                    text.append(\"O\");\n                } else {\n                    text.append(\".\");\n                }\n            }\n        }\n        return text.toString();\n    }\n}\n","solution":"// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Board board = new Board(4, 6);\n        board.setAlive(0, 1);\n        board.setAlive(1, 2);\n        board.setAlive(2, 0);\n        board.setAlive(2, 1);\n        board.setAlive(2, 2);\n        System.out.println(board);\n        System.out.println(board.countAlive() + \" cells are alive.\");\n    }\n}\n\n// ==== Board.java ====\npublic class Board {\n    private boolean[][] cells;\n    private int generation;\n\n    public Board(int rows, int columns) {\n        this.cells = new boolean[rows][columns];\n        this.generation = 0;\n    }\n\n    public int getRows() {\n        return this.cells.length;\n    }\n\n    public int getColumns() {\n        return this.cells[0].length;\n    }\n\n    public void setAlive(int row, int column) {\n        this.cells[row][column] = true;\n    }\n\n    public boolean isAlive(int row, int column) {\n        return this.cells[row][column];\n    }\n\n    public int countAlive() {\n        int count = 0;\n        for (int row = 0; row < getRows(); row++) {\n            for (int column = 0; column < getColumns(); column++) {\n                if (this.cells[row][column]) {\n                    count++;\n                }\n            }\n        }\n        return count;\n    }\n\n    public int countNeighbors(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 < getRows() && c >= 0 && c < getColumns() && this.cells[r][c]) {\n                    count++;\n                }\n            }\n        }\n        return count;\n    }\n\n    public boolean willLive(int row, int column) {\n        int neighbors = countNeighbors(row, column);\n        if (this.cells[row][column]) {\n            return neighbors == 2 || neighbors == 3;\n        }\n        return neighbors == 3;\n    }\n\n    public void step() {\n        boolean[][] next = new boolean[getRows()][getColumns()];\n        for (int row = 0; row < getRows(); row++) {\n            for (int column = 0; column < getColumns(); column++) {\n                next[row][column] = willLive(row, column);\n            }\n        }\n        this.cells = next;\n        this.generation++;\n    }\n\n    public int getGeneration() {\n        return this.generation;\n    }\n\n    public String toString() {\n        StringBuilder text = new StringBuilder();\n        for (int row = 0; row < getRows(); row++) {\n            if (row > 0) {\n                text.append(\"\\n\");\n            }\n            for (int column = 0; column < getColumns(); column++) {\n                if (this.cells[row][column]) {\n                    text.append(\"O\");\n                } else {\n                    text.append(\".\");\n                }\n            }\n        }\n        return text.toString();\n    }\n}\n","hints":["The new array has the same size as the board, `getRows()` by `getColumns()`, and `willLive` already does all the work for each cell. It reads only `cells`, which doesn't change until the loops are done.","`boolean[][] next = new boolean[getRows()][getColumns()];`, then two loops with `next[row][column] = willLive(row, column);`. After the loops, `this.cells = next;` puts the new generation in place, and `this.generation++;` counts the step."],"tests":[{"name":"A blinker","stdin":"","call":"Board board = new Board(5, 5);\nboard.setAlive(2, 1);\nboard.setAlive(2, 2);\nboard.setAlive(2, 3);\nboard.step();\nSystem.out.println(board);\nSystem.out.println(board.getGeneration());\nboard.step();\nSystem.out.println(board);\nSystem.out.println(board.getGeneration());\n","expect":".....\n..O..\n..O..\n..O..\n.....\n1\n.....\n.....\n.OOO.\n.....\n.....\n2","hidden":false},{"name":"A glider moves","stdin":"","call":"Board board = new Board(6, 6);\nboard.setAlive(0, 1);\nboard.setAlive(1, 2);\nboard.setAlive(2, 0);\nboard.setAlive(2, 1);\nboard.setAlive(2, 2);\nfor (int i = 0; i < 4; i++) {\n    board.step();\n}\nSystem.out.println(board);\nSystem.out.println(board.getGeneration() + \" \" + board.countAlive());\n","expect":"......\n..O...\n...O..\n.OOO..\n......\n......\n4 5","hidden":true},{"name":"A block stays","stdin":"","call":"Board board = new Board(4, 5);\nboard.setAlive(1, 1);\nboard.setAlive(1, 2);\nboard.setAlive(2, 1);\nboard.setAlive(2, 2);\nboard.step();\nboard.step();\nboard.step();\nSystem.out.println(board);\nSystem.out.println(board.getGeneration());\n","expect":".....\n.OO..\n.OO..\n.....\n3","hidden":true},{"name":"A lonely cell dies","stdin":"","call":"Board board = new Board(3, 3);\nboard.setAlive(1, 1);\nSystem.out.println(board.getGeneration());\nboard.step();\nSystem.out.println(board);\nSystem.out.println(board.getGeneration() + \" \" + board.countAlive());\n","expect":"0\n...\n...\n...\n1 0","hidden":true}],"require":[{"pattern":"new\\s+boolean\\s*\\[","min":2,"message":"Build the next generation in a new array, `new boolean[getRows()][getColumns()]`, in `step()`."}],"forbid":[]},{"id":"wrapping","title":"Wrapping around","task":"A glider on the board you have now soon reaches an edge, turns into a block and stops. Many Life programs let the edges **wrap around** instead: the row above the top row is the bottom row, and the column to the left of the first column is the last column. The board becomes like the surface of a doughnut, with no edges at all, and a glider that leaves on one side comes back on the other.\n\n1. Add a field `wrapping`, a `boolean` that is `false` for a new board, and a method `setWrapping(boolean wrapping)` that sets it.\n2. When `wrapping` is `true`, `countNeighbors` wraps around: on a board of 5 rows, row -1 is row 4 and row 5 is row 0, and the same for the columns. When it's `false`, the method counts as before.\n\n`willLive` and `step` use `countNeighbors`, so they wrap too, with no change. The check runs:\n\n```java\nBoard board = new Board(5, 5);\nboard.setAlive(1, 0);\nboard.setAlive(2, 0);\nboard.setAlive(3, 0);\nboard.setWrapping(true);\nSystem.out.println(board.countNeighbors(2, 4));\nSystem.out.println(board.countNeighbors(0, 0));\nboard.step();\nSystem.out.println(board);\n```\n\nand expects a blinker on the left edge to turn across it:\n\n```\n3\n1\n.....\n.....\nOO..O\n.....\n.....\n```\n","kind":"code","seed":"// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Board board = new Board(4, 6);\n        board.setAlive(0, 1);\n        board.setAlive(1, 2);\n        board.setAlive(2, 0);\n        board.setAlive(2, 1);\n        board.setAlive(2, 2);\n        System.out.println(board);\n        System.out.println(board.countAlive() + \" cells are alive.\");\n    }\n}\n\n// ==== Board.java ====\npublic class Board {\n    private boolean[][] cells;\n    private int generation;\n\n    public Board(int rows, int columns) {\n        this.cells = new boolean[rows][columns];\n        this.generation = 0;\n    }\n\n    public int getRows() {\n        return this.cells.length;\n    }\n\n    public int getColumns() {\n        return this.cells[0].length;\n    }\n\n    public void setAlive(int row, int column) {\n        this.cells[row][column] = true;\n    }\n\n    public boolean isAlive(int row, int column) {\n        return this.cells[row][column];\n    }\n\n    public int countAlive() {\n        int count = 0;\n        for (int row = 0; row < getRows(); row++) {\n            for (int column = 0; column < getColumns(); column++) {\n                if (this.cells[row][column]) {\n                    count++;\n                }\n            }\n        }\n        return count;\n    }\n\n    public int countNeighbors(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 < getRows() && c >= 0 && c < getColumns() && this.cells[r][c]) {\n                    count++;\n                }\n            }\n        }\n        return count;\n    }\n\n    public boolean willLive(int row, int column) {\n        int neighbors = countNeighbors(row, column);\n        if (this.cells[row][column]) {\n            return neighbors == 2 || neighbors == 3;\n        }\n        return neighbors == 3;\n    }\n\n    public void step() {\n        boolean[][] next = new boolean[getRows()][getColumns()];\n        for (int row = 0; row < getRows(); row++) {\n            for (int column = 0; column < getColumns(); column++) {\n                next[row][column] = willLive(row, column);\n            }\n        }\n        this.cells = next;\n        this.generation++;\n    }\n\n    public int getGeneration() {\n        return this.generation;\n    }\n\n    public String toString() {\n        StringBuilder text = new StringBuilder();\n        for (int row = 0; row < getRows(); row++) {\n            if (row > 0) {\n                text.append(\"\\n\");\n            }\n            for (int column = 0; column < getColumns(); column++) {\n                if (this.cells[row][column]) {\n                    text.append(\"O\");\n                } else {\n                    text.append(\".\");\n                }\n            }\n        }\n        return text.toString();\n    }\n}\n","solution":"// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Board board = new Board(4, 6);\n        board.setAlive(0, 1);\n        board.setAlive(1, 2);\n        board.setAlive(2, 0);\n        board.setAlive(2, 1);\n        board.setAlive(2, 2);\n        System.out.println(board);\n        System.out.println(board.countAlive() + \" cells are alive.\");\n    }\n}\n\n// ==== Board.java ====\npublic class Board {\n    private boolean[][] cells;\n    private int generation;\n    private boolean wrapping;\n\n    public Board(int rows, int columns) {\n        this.cells = new boolean[rows][columns];\n        this.generation = 0;\n        this.wrapping = false;\n    }\n\n    public int getRows() {\n        return this.cells.length;\n    }\n\n    public int getColumns() {\n        return this.cells[0].length;\n    }\n\n    public void setAlive(int row, int column) {\n        this.cells[row][column] = true;\n    }\n\n    public boolean isAlive(int row, int column) {\n        return this.cells[row][column];\n    }\n\n    public int countAlive() {\n        int count = 0;\n        for (int row = 0; row < getRows(); row++) {\n            for (int column = 0; column < getColumns(); column++) {\n                if (this.cells[row][column]) {\n                    count++;\n                }\n            }\n        }\n        return count;\n    }\n\n    public int countNeighbors(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                int checkRow = r;\n                int checkColumn = c;\n                if (this.wrapping) {\n                    checkRow = (r + getRows()) % getRows();\n                    checkColumn = (c + getColumns()) % getColumns();\n                }\n                if (checkRow >= 0 && checkRow < getRows() && checkColumn >= 0 && checkColumn < getColumns() && this.cells[checkRow][checkColumn]) {\n                    count++;\n                }\n            }\n        }\n        return count;\n    }\n\n    public boolean willLive(int row, int column) {\n        int neighbors = countNeighbors(row, column);\n        if (this.cells[row][column]) {\n            return neighbors == 2 || neighbors == 3;\n        }\n        return neighbors == 3;\n    }\n\n    public void step() {\n        boolean[][] next = new boolean[getRows()][getColumns()];\n        for (int row = 0; row < getRows(); row++) {\n            for (int column = 0; column < getColumns(); column++) {\n                next[row][column] = willLive(row, column);\n            }\n        }\n        this.cells = next;\n        this.generation++;\n    }\n\n    public int getGeneration() {\n        return this.generation;\n    }\n\n    public void setWrapping(boolean wrapping) {\n        this.wrapping = wrapping;\n    }\n\n    public String toString() {\n        StringBuilder text = new StringBuilder();\n        for (int row = 0; row < getRows(); row++) {\n            if (row > 0) {\n                text.append(\"\\n\");\n            }\n            for (int column = 0; column < getColumns(); column++) {\n                if (this.cells[row][column]) {\n                    text.append(\"O\");\n                } else {\n                    text.append(\".\");\n                }\n            }\n        }\n        return text.toString();\n    }\n}\n","hints":["The remainder `%` wraps a number around: `(r + getRows()) % getRows()` turns -1 into the last row and `getRows()` into 0, and leaves every row in between as it is. Adding `getRows()` first matters, because in Java `-1 % 5` is -1, not 4.","Work out the row and column to read before the check: when `wrapping` is on, replace `r` and `c` with their wrapped values. A wrapped index is always inside the board, so the check that keeps out the places outside can stay as it is."],"tests":[{"name":"A blinker on the edge","stdin":"","call":"Board board = new Board(5, 5);\nboard.setAlive(1, 0);\nboard.setAlive(2, 0);\nboard.setAlive(3, 0);\nboard.setWrapping(true);\nSystem.out.println(board.countNeighbors(2, 4));\nSystem.out.println(board.countNeighbors(0, 0));\nboard.step();\nSystem.out.println(board);\n","expect":"3\n1\n.....\n.....\nOO..O\n.....\n.....","hidden":false},{"name":"The same blinker without wrapping","stdin":"","call":"Board board = new Board(5, 5);\nboard.setAlive(1, 0);\nboard.setAlive(2, 0);\nboard.setAlive(3, 0);\nSystem.out.println(board.countNeighbors(2, 4));\nboard.step();\nSystem.out.println(board);\n","expect":"0\n.....\n.....\nOO...\n.....\n.....","hidden":true},{"name":"A glider goes all the way around","stdin":"","call":"Board board = new Board(5, 5);\nboard.setAlive(0, 1);\nboard.setAlive(1, 2);\nboard.setAlive(2, 0);\nboard.setAlive(2, 1);\nboard.setAlive(2, 2);\nboard.setWrapping(true);\nfor (int i = 0; i < 10; i++) {\n    board.step();\n}\nSystem.out.println(board);\nfor (int i = 0; i < 10; i++) {\n    board.step();\n}\nSystem.out.println(board);\nSystem.out.println(board.getGeneration() + \" \" + board.countAlive());\n","expect":"...OO\n.....\n.....\n....O\n..O.O\n.O...\n..O..\nOOO..\n.....\n.....\n20 5","hidden":true},{"name":"Four corners","stdin":"","call":"Board board = new Board(4, 6);\nboard.setAlive(0, 0);\nboard.setAlive(0, 5);\nboard.setAlive(3, 0);\nboard.setAlive(3, 5);\nSystem.out.println(board.countNeighbors(0, 0));\nboard.setWrapping(true);\nSystem.out.println(board.countNeighbors(0, 0));\nSystem.out.println(board.countNeighbors(3, 5));\nSystem.out.println(board.countNeighbors(2, 3));\nboard.setWrapping(false);\nSystem.out.println(board.countNeighbors(3, 5));\n","expect":"0\n3\n3\n0\n0","hidden":true}],"require":[],"forbid":[{"pattern":"\\bcatch\\b","message":"Work out the wrapped row and column before reading a cell, instead of catching the exception."}]},{"id":"pattern-file","title":"Patterns from a file","task":"Setting cells one by one is slow. Life patterns are often kept in text files that look like a printed board, and many Life programs read files like this one:\n\n```text\n!Name: Glider\n!It moves one cell down and one to the right every four generations.\n.O\n..O\nOOO\n......\n```\n\nA line that starts with `!` is a comment. Every other line is a row of the board, from the top: `O` is a live cell, and any other character a dead one. The rows can have different lengths. The board is as wide as the longest row, and a shorter row continues with dead cells. An empty line is a row of dead cells.\n\nWrite a method `public static Board readPattern(String fileName) throws IOException` in `Main` that reads the file and returns its board. The files in the checks have at least one row that isn't empty. When the file can't be read, the method doesn't catch the exception: it leaves it to the caller, which is what `throws IOException` says. The check gives the program the file above as `glider.txt` and runs:\n\n```java\nBoard board = readPattern(\"glider.txt\");\nSystem.out.println(board.getRows() + \" by \" + board.getColumns());\nSystem.out.println(board);\nSystem.out.println(board.countAlive());\n```\n\nand expects:\n\n```\n4 by 6\n.O....\n..O...\nOOO...\n......\n5\n```\n","kind":"code","seed":"// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Board board = new Board(4, 6);\n        board.setAlive(0, 1);\n        board.setAlive(1, 2);\n        board.setAlive(2, 0);\n        board.setAlive(2, 1);\n        board.setAlive(2, 2);\n        System.out.println(board);\n        System.out.println(board.countAlive() + \" cells are alive.\");\n    }\n}\n\n// ==== Board.java ====\npublic class Board {\n    private boolean[][] cells;\n    private int generation;\n    private boolean wrapping;\n\n    public Board(int rows, int columns) {\n        this.cells = new boolean[rows][columns];\n        this.generation = 0;\n        this.wrapping = false;\n    }\n\n    public int getRows() {\n        return this.cells.length;\n    }\n\n    public int getColumns() {\n        return this.cells[0].length;\n    }\n\n    public void setAlive(int row, int column) {\n        this.cells[row][column] = true;\n    }\n\n    public boolean isAlive(int row, int column) {\n        return this.cells[row][column];\n    }\n\n    public int countAlive() {\n        int count = 0;\n        for (int row = 0; row < getRows(); row++) {\n            for (int column = 0; column < getColumns(); column++) {\n                if (this.cells[row][column]) {\n                    count++;\n                }\n            }\n        }\n        return count;\n    }\n\n    public int countNeighbors(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                int checkRow = r;\n                int checkColumn = c;\n                if (this.wrapping) {\n                    checkRow = (r + getRows()) % getRows();\n                    checkColumn = (c + getColumns()) % getColumns();\n                }\n                if (checkRow >= 0 && checkRow < getRows() && checkColumn >= 0 && checkColumn < getColumns() && this.cells[checkRow][checkColumn]) {\n                    count++;\n                }\n            }\n        }\n        return count;\n    }\n\n    public boolean willLive(int row, int column) {\n        int neighbors = countNeighbors(row, column);\n        if (this.cells[row][column]) {\n            return neighbors == 2 || neighbors == 3;\n        }\n        return neighbors == 3;\n    }\n\n    public void step() {\n        boolean[][] next = new boolean[getRows()][getColumns()];\n        for (int row = 0; row < getRows(); row++) {\n            for (int column = 0; column < getColumns(); column++) {\n                next[row][column] = willLive(row, column);\n            }\n        }\n        this.cells = next;\n        this.generation++;\n    }\n\n    public int getGeneration() {\n        return this.generation;\n    }\n\n    public void setWrapping(boolean wrapping) {\n        this.wrapping = wrapping;\n    }\n\n    public String toString() {\n        StringBuilder text = new StringBuilder();\n        for (int row = 0; row < getRows(); row++) {\n            if (row > 0) {\n                text.append(\"\\n\");\n            }\n            for (int column = 0; column < getColumns(); column++) {\n                if (this.cells[row][column]) {\n                    text.append(\"O\");\n                } else {\n                    text.append(\".\");\n                }\n            }\n        }\n        return text.toString();\n    }\n}\n","solution":"// ==== Main.java ====\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\nimport java.util.ArrayList;\n\npublic class Main {\n    public static void main(String[] args) {\n        Board board = new Board(4, 6);\n        board.setAlive(0, 1);\n        board.setAlive(1, 2);\n        board.setAlive(2, 0);\n        board.setAlive(2, 1);\n        board.setAlive(2, 2);\n        System.out.println(board);\n        System.out.println(board.countAlive() + \" cells are alive.\");\n    }\n\n    public static Board readPattern(String fileName) throws IOException {\n        ArrayList<String> rows = new ArrayList<>();\n        int columns = 0;\n        for (String line : Files.readAllLines(Paths.get(fileName))) {\n            if (line.startsWith(\"!\")) {\n                continue;\n            }\n            rows.add(line);\n            if (line.length() > columns) {\n                columns = line.length();\n            }\n        }\n\n        Board board = new Board(rows.size(), columns);\n        for (int row = 0; row < rows.size(); row++) {\n            String line = rows.get(row);\n            for (int column = 0; column < line.length(); column++) {\n                if (line.charAt(column) == 'O') {\n                    board.setAlive(row, column);\n                }\n            }\n        }\n        return board;\n    }\n}\n\n// ==== Board.java ====\npublic class Board {\n    private boolean[][] cells;\n    private int generation;\n    private boolean wrapping;\n\n    public Board(int rows, int columns) {\n        this.cells = new boolean[rows][columns];\n        this.generation = 0;\n        this.wrapping = false;\n    }\n\n    public int getRows() {\n        return this.cells.length;\n    }\n\n    public int getColumns() {\n        return this.cells[0].length;\n    }\n\n    public void setAlive(int row, int column) {\n        this.cells[row][column] = true;\n    }\n\n    public boolean isAlive(int row, int column) {\n        return this.cells[row][column];\n    }\n\n    public int countAlive() {\n        int count = 0;\n        for (int row = 0; row < getRows(); row++) {\n            for (int column = 0; column < getColumns(); column++) {\n                if (this.cells[row][column]) {\n                    count++;\n                }\n            }\n        }\n        return count;\n    }\n\n    public int countNeighbors(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                int checkRow = r;\n                int checkColumn = c;\n                if (this.wrapping) {\n                    checkRow = (r + getRows()) % getRows();\n                    checkColumn = (c + getColumns()) % getColumns();\n                }\n                if (checkRow >= 0 && checkRow < getRows() && checkColumn >= 0 && checkColumn < getColumns() && this.cells[checkRow][checkColumn]) {\n                    count++;\n                }\n            }\n        }\n        return count;\n    }\n\n    public boolean willLive(int row, int column) {\n        int neighbors = countNeighbors(row, column);\n        if (this.cells[row][column]) {\n            return neighbors == 2 || neighbors == 3;\n        }\n        return neighbors == 3;\n    }\n\n    public void step() {\n        boolean[][] next = new boolean[getRows()][getColumns()];\n        for (int row = 0; row < getRows(); row++) {\n            for (int column = 0; column < getColumns(); column++) {\n                next[row][column] = willLive(row, column);\n            }\n        }\n        this.cells = next;\n        this.generation++;\n    }\n\n    public int getGeneration() {\n        return this.generation;\n    }\n\n    public void setWrapping(boolean wrapping) {\n        this.wrapping = wrapping;\n    }\n\n    public String toString() {\n        StringBuilder text = new StringBuilder();\n        for (int row = 0; row < getRows(); row++) {\n            if (row > 0) {\n                text.append(\"\\n\");\n            }\n            for (int column = 0; column < getColumns(); column++) {\n                if (this.cells[row][column]) {\n                    text.append(\"O\");\n                } else {\n                    text.append(\".\");\n                }\n            }\n        }\n        return text.toString();\n    }\n}\n","hints":["`Files.readAllLines(Paths.get(fileName))` returns the file's lines (module 42). Go through them once to keep the lines that don't start with `!` in an `ArrayList<String>`, and to find the length of the longest one.","Then create `new Board(rows.size(), longest)`, and for each row go through the characters of its line: `setAlive(row, column)` where `line.charAt(column) == 'O'`. Loop to `line.length()`, not to the width of the board, and a short line leaves the rest of its row dead.","The method needs `import java.io.IOException;`, `import java.nio.file.Files;` and `import java.nio.file.Paths;` at the top of `Main.java`, and `import java.util.ArrayList;` for the list."],"tests":[{"name":"A glider from a file","stdin":"","call":"Board board = readPattern(\"glider.txt\");\nSystem.out.println(board.getRows() + \" by \" + board.getColumns());\nSystem.out.println(board);\nSystem.out.println(board.countAlive());\n","files":{"glider.txt":"!Name: Glider\n!It moves one cell down and one to the right every four generations.\n.O\n..O\nOOO\n......\n"},"expect":"4 by 6\n.O....\n..O...\nOOO...\n......\n5","hidden":false},{"name":"Two blocks and an empty line","stdin":"","call":"Board board = readPattern(\"blocks.txt\");\nSystem.out.println(board.getRows() + \" by \" + board.getColumns());\nSystem.out.println(board);\nSystem.out.println(board.countAlive());\n","files":{"blocks.txt":"!Two blocks\nOO.\nOO\n\n...OO\n!They never change.\n...OO\n"},"expect":"5 by 5\nOO...\nOO...\n.....\n...OO\n...OO\n8","hidden":true},{"name":"Other characters are dead","stdin":"","call":"Board board = readPattern(\"shapes/beacon.txt\");\nSystem.out.println(board.getRows() + \" by \" + board.getColumns());\nSystem.out.println(board);\nboard.step();\nSystem.out.println(board);\n","files":{"shapes/beacon.txt":"OO..\nO-..\n..xO\n..OO\n"},"expect":"4 by 4\nOO..\nO...\n...O\n..OO\nOO..\nOO..\n..OO\n..OO","hidden":true},{"name":"One live cell","stdin":"","call":"Board board = readPattern(\"one.txt\");\nSystem.out.println(board.getRows() + \" by \" + board.getColumns());\nSystem.out.println(board);\n","files":{"one.txt":"O\n"},"expect":"1 by 1\nO","hidden":true},{"name":"A file that isn't there","stdin":"","call":"try {\n    readPattern(\"missing.txt\");\n    System.out.println(\"The method returned.\");\n} catch (Exception e) {\n    System.out.println(\"The method threw an exception.\");\n}\n","expect":"The method threw an exception.","hidden":true}],"require":[],"forbid":[{"pattern":"\\bcatch\\b","message":"Let `readPattern` throw the IOException (`throws IOException` in its header), instead of catching it."}]},{"id":"generations","title":"Generations as text","task":"Time to put it all together in `main`. Replace the example board in `main` with a program that reads three lines of input:\n\n1. the name of a pattern file,\n2. how many generations to show after the first one,\n3. `wrap` for a board that wraps around at its edges, or `edges` for one that doesn't.\n\nThe program reads the board with `readPattern` and prints generation 0, then takes a step and prints the next generation, until it has shown the number of generations that was asked for. Each generation starts with a line such as `Generation 2: 5 alive` (its number and how many cells are alive), followed by the board. An empty line comes before every generation except the first.\n\nTwo more things:\n\n- Some patterns stop changing, such as a block, or a board where everything has died. Change `step()` in `Board` to return a `boolean`: `true` when at least one cell changed, and `false` when the new generation is exactly the old one. When a step changes nothing, the program prints the empty line and `Nothing changes after generation 3.` (with the number of the last generation it printed), and stops.\n- When the file can't be read, the program prints `Could not read nothing.txt.` (with the name that was given) and nothing else.\n\nWith this `blinker.txt`\n\n```text\n!Blinker\n.....\n.OOO.\n.....\n```\n\nand the input `blinker.txt`, `2` and `edges`, the program prints:\n\n```\nGeneration 0: 3 alive\n.....\n.OOO.\n.....\n\nGeneration 1: 3 alive\n..O..\n..O..\n..O..\n\nGeneration 2: 3 alive\n.....\n.OOO.\n.....\n```\n","kind":"code","seed":"// ==== Main.java ====\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\nimport java.util.ArrayList;\n\npublic class Main {\n    public static void main(String[] args) {\n        Board board = new Board(4, 6);\n        board.setAlive(0, 1);\n        board.setAlive(1, 2);\n        board.setAlive(2, 0);\n        board.setAlive(2, 1);\n        board.setAlive(2, 2);\n        System.out.println(board);\n        System.out.println(board.countAlive() + \" cells are alive.\");\n    }\n\n    public static Board readPattern(String fileName) throws IOException {\n        ArrayList<String> rows = new ArrayList<>();\n        int columns = 0;\n        for (String line : Files.readAllLines(Paths.get(fileName))) {\n            if (line.startsWith(\"!\")) {\n                continue;\n            }\n            rows.add(line);\n            if (line.length() > columns) {\n                columns = line.length();\n            }\n        }\n\n        Board board = new Board(rows.size(), columns);\n        for (int row = 0; row < rows.size(); row++) {\n            String line = rows.get(row);\n            for (int column = 0; column < line.length(); column++) {\n                if (line.charAt(column) == 'O') {\n                    board.setAlive(row, column);\n                }\n            }\n        }\n        return board;\n    }\n}\n\n// ==== Board.java ====\npublic class Board {\n    private boolean[][] cells;\n    private int generation;\n    private boolean wrapping;\n\n    public Board(int rows, int columns) {\n        this.cells = new boolean[rows][columns];\n        this.generation = 0;\n        this.wrapping = false;\n    }\n\n    public int getRows() {\n        return this.cells.length;\n    }\n\n    public int getColumns() {\n        return this.cells[0].length;\n    }\n\n    public void setAlive(int row, int column) {\n        this.cells[row][column] = true;\n    }\n\n    public boolean isAlive(int row, int column) {\n        return this.cells[row][column];\n    }\n\n    public int countAlive() {\n        int count = 0;\n        for (int row = 0; row < getRows(); row++) {\n            for (int column = 0; column < getColumns(); column++) {\n                if (this.cells[row][column]) {\n                    count++;\n                }\n            }\n        }\n        return count;\n    }\n\n    public int countNeighbors(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                int checkRow = r;\n                int checkColumn = c;\n                if (this.wrapping) {\n                    checkRow = (r + getRows()) % getRows();\n                    checkColumn = (c + getColumns()) % getColumns();\n                }\n                if (checkRow >= 0 && checkRow < getRows() && checkColumn >= 0 && checkColumn < getColumns() && this.cells[checkRow][checkColumn]) {\n                    count++;\n                }\n            }\n        }\n        return count;\n    }\n\n    public boolean willLive(int row, int column) {\n        int neighbors = countNeighbors(row, column);\n        if (this.cells[row][column]) {\n            return neighbors == 2 || neighbors == 3;\n        }\n        return neighbors == 3;\n    }\n\n    public void step() {\n        boolean[][] next = new boolean[getRows()][getColumns()];\n        for (int row = 0; row < getRows(); row++) {\n            for (int column = 0; column < getColumns(); column++) {\n                next[row][column] = willLive(row, column);\n            }\n        }\n        this.cells = next;\n        this.generation++;\n    }\n\n    public int getGeneration() {\n        return this.generation;\n    }\n\n    public void setWrapping(boolean wrapping) {\n        this.wrapping = wrapping;\n    }\n\n    public String toString() {\n        StringBuilder text = new StringBuilder();\n        for (int row = 0; row < getRows(); row++) {\n            if (row > 0) {\n                text.append(\"\\n\");\n            }\n            for (int column = 0; column < getColumns(); column++) {\n                if (this.cells[row][column]) {\n                    text.append(\"O\");\n                } else {\n                    text.append(\".\");\n                }\n            }\n        }\n        return text.toString();\n    }\n}\n","solution":"// ==== Main.java ====\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\nimport java.util.ArrayList;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        String fileName = scanner.nextLine();\n        int generations = Integer.parseInt(scanner.nextLine());\n        String edges = scanner.nextLine();\n\n        Board board;\n        try {\n            board = readPattern(fileName);\n        } catch (IOException e) {\n            System.out.println(\"Could not read \" + fileName + \".\");\n            return;\n        }\n        board.setWrapping(edges.equals(\"wrap\"));\n\n        printGeneration(board);\n        while (board.getGeneration() < generations) {\n            System.out.println();\n            if (!board.step()) {\n                System.out.println(\"Nothing changes after generation \" + (board.getGeneration() - 1) + \".\");\n                return;\n            }\n            printGeneration(board);\n        }\n    }\n\n    public static void printGeneration(Board board) {\n        System.out.println(\"Generation \" + board.getGeneration() + \": \" + board.countAlive() + \" alive\");\n        System.out.println(board);\n    }\n\n    public static Board readPattern(String fileName) throws IOException {\n        ArrayList<String> rows = new ArrayList<>();\n        int columns = 0;\n        for (String line : Files.readAllLines(Paths.get(fileName))) {\n            if (line.startsWith(\"!\")) {\n                continue;\n            }\n            rows.add(line);\n            if (line.length() > columns) {\n                columns = line.length();\n            }\n        }\n\n        Board board = new Board(rows.size(), columns);\n        for (int row = 0; row < rows.size(); row++) {\n            String line = rows.get(row);\n            for (int column = 0; column < line.length(); column++) {\n                if (line.charAt(column) == 'O') {\n                    board.setAlive(row, column);\n                }\n            }\n        }\n        return board;\n    }\n}\n\n// ==== Board.java ====\npublic class Board {\n    private boolean[][] cells;\n    private int generation;\n    private boolean wrapping;\n\n    public Board(int rows, int columns) {\n        this.cells = new boolean[rows][columns];\n        this.generation = 0;\n        this.wrapping = false;\n    }\n\n    public int getRows() {\n        return this.cells.length;\n    }\n\n    public int getColumns() {\n        return this.cells[0].length;\n    }\n\n    public void setAlive(int row, int column) {\n        this.cells[row][column] = true;\n    }\n\n    public boolean isAlive(int row, int column) {\n        return this.cells[row][column];\n    }\n\n    public int countAlive() {\n        int count = 0;\n        for (int row = 0; row < getRows(); row++) {\n            for (int column = 0; column < getColumns(); column++) {\n                if (this.cells[row][column]) {\n                    count++;\n                }\n            }\n        }\n        return count;\n    }\n\n    public int countNeighbors(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                int checkRow = r;\n                int checkColumn = c;\n                if (this.wrapping) {\n                    checkRow = (r + getRows()) % getRows();\n                    checkColumn = (c + getColumns()) % getColumns();\n                }\n                if (checkRow >= 0 && checkRow < getRows() && checkColumn >= 0 && checkColumn < getColumns() && this.cells[checkRow][checkColumn]) {\n                    count++;\n                }\n            }\n        }\n        return count;\n    }\n\n    public boolean willLive(int row, int column) {\n        int neighbors = countNeighbors(row, column);\n        if (this.cells[row][column]) {\n            return neighbors == 2 || neighbors == 3;\n        }\n        return neighbors == 3;\n    }\n\n    public boolean step() {\n        boolean[][] next = new boolean[getRows()][getColumns()];\n        boolean changed = false;\n        for (int row = 0; row < getRows(); row++) {\n            for (int column = 0; column < getColumns(); column++) {\n                next[row][column] = willLive(row, column);\n                if (next[row][column] != this.cells[row][column]) {\n                    changed = true;\n                }\n            }\n        }\n        this.cells = next;\n        this.generation++;\n        return changed;\n    }\n\n    public int getGeneration() {\n        return this.generation;\n    }\n\n    public void setWrapping(boolean wrapping) {\n        this.wrapping = wrapping;\n    }\n\n    public String toString() {\n        StringBuilder text = new StringBuilder();\n        for (int row = 0; row < getRows(); row++) {\n            if (row > 0) {\n                text.append(\"\\n\");\n            }\n            for (int column = 0; column < getColumns(); column++) {\n                if (this.cells[row][column]) {\n                    text.append(\"O\");\n                } else {\n                    text.append(\".\");\n                }\n            }\n        }\n        return text.toString();\n    }\n}\n","hints":["Read the three lines with `scanner.nextLine()`, and turn the second into a number with `Integer.parseInt`. `board.setWrapping(edges.equals(\"wrap\"))` sets the edges.","`readPattern` throws an IOException when the file can't be read: call it inside `try`, and in the `catch` print the message and `return` from `main`.","A loop `while (board.getGeneration() < generations)` takes the steps. In `step()`, compare each new cell with the old one, `next[row][column] != this.cells[row][column]`, and remember in a `boolean` whether any of them differed. After a step that changed nothing, `getGeneration()` is already one more than the generation that was printed last."],"tests":[{"name":"A blinker for two generations","stdin":"blinker.txt\n2\nedges\n","files":{"blinker.txt":"!Blinker\n.....\n.OOO.\n.....\n"},"expect":"Generation 0: 3 alive\n.....\n.OOO.\n.....\n\nGeneration 1: 3 alive\n..O..\n..O..\n..O..\n\nGeneration 2: 3 alive\n.....\n.OOO.\n.....","hidden":false},{"name":"A block never changes","stdin":"block.txt\n5\nedges\n","files":{"block.txt":"!Block\n....\n.OO.\n.OO.\n....\n"},"expect":"Generation 0: 4 alive\n....\n.OO.\n.OO.\n....\n\nNothing changes after generation 0.","hidden":false},{"name":"A glider that wraps","stdin":"glider.txt\n6\nwrap\n","files":{"glider.txt":"!Name: Glider\n.O...\n..O..\nOOO..\n.....\n.....\n"},"expect":"Generation 0: 5 alive\n.O...\n..O..\nOOO..\n.....\n.....\n\nGeneration 1: 5 alive\n.....\nO.O..\n.OO..\n.O...\n.....\n\nGeneration 2: 5 alive\n.....\n..O..\nO.O..\n.OO..\n.....\n\nGeneration 3: 5 alive\n.....\n.O...\n..OO.\n.OO..\n.....\n\nGeneration 4: 5 alive\n.....\n..O..\n...O.\n.OOO.\n.....\n\nGeneration 5: 5 alive\n.....\n.....\n.O.O.\n..OO.\n..O..\n\nGeneration 6: 5 alive\n.....\n.....\n...O.\n.O.O.\n..OO.","hidden":true},{"name":"The glider meets the edge","stdin":"glider.txt\n8\nedges\n","files":{"glider.txt":".O..\n..O.\nOOO.\n....\n"},"expect":"Generation 0: 5 alive\n.O..\n..O.\nOOO.\n....\n\nGeneration 1: 5 alive\n....\nO.O.\n.OO.\n.O..\n\nGeneration 2: 5 alive\n....\n..O.\nO.O.\n.OO.\n\nGeneration 3: 5 alive\n....\n.O..\n..OO\n.OO.\n\nGeneration 4: 5 alive\n....\n..O.\n...O\n.OOO\n\nGeneration 5: 4 alive\n....\n....\n.O.O\n..OO\n\nGeneration 6: 3 alive\n....\n....\n...O\n..OO\n\nGeneration 7: 4 alive\n....\n....\n..OO\n..OO\n\nNothing changes after generation 7.","hidden":true},{"name":"Everything dies","stdin":"pair.txt\n4\nwrap\n","files":{"pair.txt":"!Two cells are not enough.\n...\n.OO\n...\n"},"expect":"Generation 0: 2 alive\n...\n.OO\n...\n\nGeneration 1: 0 alive\n...\n...\n...\n\nNothing changes after generation 1.","hidden":true},{"name":"Only the first generation","stdin":"toad.txt\n0\nedges\n","files":{"toad.txt":"......\n..OOO.\n.OOO..\n......\n"},"expect":"Generation 0: 6 alive\n......\n..OOO.\n.OOO..\n......","hidden":true},{"name":"A file that can't be read","stdin":"nothing.txt\n3\nwrap\n","expect":"Could not read nothing.txt.","hidden":true}],"require":[{"pattern":"\\bboolean\\s+step\\s*\\(","message":"Change `step()` to return a `boolean`: `public boolean step()`."},{"pattern":"readPattern\\s*\\(","min":2,"message":"Read the board in `main` with your method `readPattern`."}],"forbid":[]}]}