Простая версия игры в жизнь


Это очень простой вариант игры в жизнь сделано в Java. Пожалуйста, дайте мне знать, как я мог бы улучшить это. Я также надеюсь на некоторую обратную связь о том, как форматирование и конвенций, потому что я хочу, чтобы мой код был читаемым и аккуратным.

public class GameOfLife
{
    private boolean[][] board;
    private int maxRow, maxCol;

    public GameOfLife(boolean[][] board)
    {
        if(board != null)
            this.board = board;
        else
            this.board = new boolean[1][1];

        this.maxRow = this.board.length;
        this.maxCol = this.board[0].length;
    }

    public void calculateNextGeneration()
    {
        boolean[][] nextBoard = new boolean[maxRow][maxCol];

        for(int row = 0; row < maxRow; row++)
        {
            for(int col = 0; col < maxCol; col++)
            {
                nextBoard[row][col] = nextState(row, col);
            }
        }


        board = nextBoard;
    }

    public void print()
    {
        for(int row = 0; row < maxRow; row++)
        {
            for(int col = 0; col < maxCol; col++)
            {
                if(isAlive(row, col))
                    System.out.print("*");
                else
                    System.out.print(".");  
            }
            System.out.println();
        }
    }

    public void setAlive(int row, int col, boolean isAlive)
    {
        if(inBounds(row, col))
            board[row][col] = isAlive;
    }

    public boolean isAlive(int row, int col)
    {
        if(inBounds(row, col))
            return board[row][col];
        else
            return false;
    }

    private boolean nextState(int rowPos, int colPos)
    {
        int alive = 0;

        for(int row = rowPos - 1; row <= rowPos + 1; row++)
        {
            for(int col = colPos - 1; col <= colPos + 1; col++)
            {
                if(!inBounds(row, col) || (row == rowPos && col == colPos))
                    continue;

                if(isAlive(row, col))
                    alive++;
            }
        }

        if(alive == 3)
            return true;
        else if(isAlive(rowPos, colPos) && alive == 2)
            return true;
        else
            return false;
    }

    private boolean inBounds(int row, int col)
    {
        if(row < 0 || row >= maxRow || col < 0 || col >= maxCol)
            return false;
        else
            return true;
    }
}


Комментарии
3 ответа

Спасибо за ваш код.

Именования

Найти хорошие имена-это самая сложная часть в программировании. Так что всегда берите время, чтобы продумать свои имена идентификаторов.

Пожалуйста, прочитайте (и последующих) соглашения об именах в Java

например:
Ваш булевых переменных и методов, возвращающих булевский, следует начинать с это, и, может, так.

Форматирование

Есть обсуждения там, где место открытия скобок {.
Вы выберете отдельной линии, которая более распространена в других языках, таких как C.
Там могут быть веские причины для этого, но в Java более общих (но не обязательное) положение на одной линии с продолжением заявление. Три причины, почему я следую этому правилу являются:


  1. это экономит одну строку в скобки пара (делает код более компактный)

  2. Я не случайно поместить код между заявлением и открывающая фигурная скобка, которая в большинстве случаев будет отсоединить связевой блок от предыдущего заявления и так изменить логику кодов.

  3. большинство других Java программистов сделать это.

Есть аналогичные доводы, почему я ставлю закрывающие скобки на линии собственного: вполне вероятно, что я действительно хочу, чтобы добавить больше кода внутри блока и, следовательно, перед закрывающей фигурной скобкой.

Ведь придерживаться одного правила по всей программе.

общий подход

Ваш код-это процедурный подход к проблеме.

Процессуальные подходы не плохо свое.
Но Java-это объектно-ориентированный язык программирования, и если вы хотите стать хорошим Ява программист, вы должны начать искать более ОО решений.

Но ООП не означает "разделить" код в случайных классов.

Конечной целью ООП является, чтобы уменьшить дублирование кода, улучшают читаемость и использовать поддержку, а также продление кода.

Делаем ООП означает, что вы будете следовать определенным принципам, которые (среди прочих):


  • сокрытие информации / заключения

  • единая ответственность

  • разделение

  • Поцелуй (сохранить его простым (и) глупо.)

  • Dry (не повторяй себя.)

  • "Скажи! Не спрашивай".

  • Закон Деметры ("не разговаривай с незнакомцами!")



я думаю аналогично - можно ОО-выход/ультимо, но для простого типа boolean[][] вы можете быть немного терпимее ^_^ – Мартин Франк

Моя точка зрения: это не должно быть решена с помощью "простых boolean[][]", особенно если кто-то хочет узнать , как программировать на Java.

Я не говорю, что ОО-подход всегда лучше и даже желательно...


В случае моего кода, что я должен был разделить в своем классе? – bananashavings


  • В мой мир ОО было бы Cell объект, который поддерживает свое государство и держит Collection его соседи. Она будет информировать своих соседей, когда его состояние изменилось. Таким образом, мне нужно только знать фактический топология игрового поля при назначении соседями. Я даже не нужно создать массив , если я найду более умный способ, чтобы назначить соседи логически...

    За всю игру я держал клетки в простой Collection.
    Последствия:


    • разделение управления игрой и бизнес-логики

    • ассортимент никакой проверки во время повторов


  • Кроме того в игре жизни доска только несколько клеток (дикий угадал менее чем на 30% в среднем) живы сами или были живы соседи. Остальные не будут изменять свое состояние в текущей итерации, так что я не нужна для их обработки.

    В процедурный подход, основанный на простом boolean[][] нет никаких шансов, но обработка всех элементов в каждой итерации.

    В Collection подход я мог бы оптимизировать так, что коллекция содержит только клетки, где его соседи менялись во время последней итерации путем применения концепции слушателя.


1
ответ дан 13 февраля 2018 в 10:02 Источник Поделиться

просто некоторые незначительные вещи...

private boolean inBounds(int row, int col)
{
if(row < 0 || row >= maxRow || col < 0 || col >= maxCol)
return false;
else
return true;
}

может быть более ясно, если вы просто возвращаете значение

private boolean inBounds(int row, int col)
{
return (row >= 0 && row < maxRow && col >= 0 && col < maxCol)
}

те же вопросы isAlive()

public boolean isAlive(int row, int col)
{
return inBounds(row, col) && board[row][col];
}

другое дело-имя переменной maxRows и maxColumns это не совсем то, что они, я хотел бы использовать простые формы для них rows и columns поскольку они являются строками и столбцами...

что бы даже не конфликты итерации for(int row = 0; row < rows; row++)...

удалить ваш пробел, что делает чтение легче...

2
ответ дан 13 февраля 2018 в 08:02 Источник Поделиться

Во-первых, ваш код выглядит довольно хорошо, гораздо лучше, чем многие другие примеры, которые я видел.

В дополнение к другим ответы:

public GameOfLife(boolean[][] board)
{
if(board != null)
this.board = board;
else
this.board = new boolean[1][1];
// ...
}

Если ваш собеседник дает вам нуль доска массив, вы создаете 1*1 совет, который, конечно, не полезно абоненту.

Вместо этого я скажу собеседнику, что он должен предоставить действительный массив, бросив, например, InvalidArgumentException. Предоставление null-это ошибка в вызывающем коде, и вы должны сигнал о том, что ошибки как можно раньше, а не продолжать с Данные! Если никто не в стеке вызывающей знает, как дальше с пустой доски, за исключением прервет программу, и это хорошо.

Вы используете ifы без брекетов здесь и во многих других местах. Это ловушка обслуживания. Может, кто-то добавляет строку к одному из зависимых блоков:

public GameOfLife(boolean[][] board)
{
if(board != null)
this.board = board;
else
area = 1;
this.board = new boolean[1][1];
// ...
}

На первый взгляд, что выглядит хорошо, и это легко попасть в ловушку, что теперь this.board = new boolean[1][1]; выполняется безоговорочно.

Так что я всегда использовать фигурные скобки.

Итак, моя версия конструктора будет:

public GameOfLife(boolean[][] board) {
if(board == null) {
throw new IllegalArgumentException("board must not be null.");
}
this.board = board;

this.maxRow = this.board.length;
this.maxCol = this.board[0].length;
}

Про условная истина/ложь возвращается и возвращается логическое выражение: Я согласен, что например inBounds() можно переписать, используя один оператор return с логическим выражением, но я обычно делаю это на свой манер. Почему? Это упрощает отладку. Ее легче поместить точку останова на return true; или return false; линии, чем сделать один return останова реагируют условно на true или false логическое значение.

1
ответ дан 13 февраля 2018 в 09:02 Источник Поделиться