2012-02-08 4 views
4

Итак, я студент-информатика и молодой программист на Java. Кто-то попросил меня помочь им в задании, где им нужно создать довольно базовую программу тральщика. Эта программа вообще не использует мины для маркировки, но, кроме того, она функционально такая же, как и любая другая игра подметания.NullPointerException в программе подметания

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

Это исключение возникает, когда вызывается метод makeField класса Tile. Кроме того, я действительно пытаюсь склонить голову к правильному наследованию, статическому или нестатическому, public vs. private и тому, как все они взаимосвязаны, поэтому я сожалею, если это общий вопрос о нобе.

Итак, у меня есть основной файл, суперкласс класса и два подкласса класса плитки - Bomb и Flat. Бомба - это плитка с бомбой в ней, а Flat - любая плитка, которая не является бомбой.

public class MineSweeperMain{ 
public static void main(String[] args) 
{ 
    Scanner kybd = new Scanner(System.in); 
    int dimension; 
    Tile[][] gameBoard; 

    System.out.print("Enter the dimension of the board you would like to play on:\t"); 
    dimension = kybd.nextInt(); 

    gameBoard = Tile.makeField(dimension); 
    Tile.printField(gameBoard, dimension); 
} 

} 

//

public class Tile { 

static Random rand = new Random(); 

boolean isBomb; 
boolean isRevealed; 
int posX, posY; 
int noOfAdjacentMines; 

public Tile() 
{ 
    isRevealed = false; 
} 

public static int detectMines(Tile[][] board, int dimensions) 
{ 
    int detectedMines = 0; 
    for(int i = 0; i < dimensions; i++) 
    { 
     for(int j = 0; j < dimensions; j++) 
     { 
      if(board[i][j].isBomb) 
       detectedMines++; 
     } 
    } 
    return detectedMines; 
} 

public static Tile[][] makeField(int dimensions) 
{ 
    int rowOfMines = dimensions/3; 
    int randomInRow; 

    Tile[][] Board = new Tile[dimensions][dimensions]; 

    for(int i = 0; i < dimensions; i++) 
     for(int j = 0; j <= rowOfMines; j++) 
     { 
     randomInRow = rand.nextInt(dimensions); 
     Board[i][randomInRow] = new Bomb(); 
     } 

    for(int i = 0; i < dimensions; i++) 
     for(int j = 0; j < dimensions; j++) 
     { 
      if(!Board[i][j].isBomb) 
       Board[i][j] = new Flat(); 
     } 
    return Board;    
} 

public static void printField(Tile[][] board, int dimensions) 
{ 
    for(int i = 0; i <= dimensions; i++) 
    { 
     for (int j = 0; j <= dimensions; j++) 
     { 
      if(i ==0) 
       System.out.print(i + " "); 
      else if(j == 0) 
       System.out.print(j + " "); 
      else 
      { 
       if(board[i-1][j-1].isRevealed && !board[i-1][j-1].isBomb) 
        System.out.print(board[i-1][j-1].noOfAdjacentMines + " "); 
       else 
        System.out.print("# "); 
      } 
     } 
    } 
} 

} 

//

public class Flat extends Tile{ 

public Flat() 
{ 
    noOfAdjacentMines = 0; 
    isBomb = false; 
    isRevealed = false; 
} 
} 

//

public class Bomb extends Tile{ 
public Bomb() 
{ 
    isBomb = true; 
    isRevealed = false; 
} 

} 

//

+1

Где такое NullPointerException? (Какое заявление?) – RussS

+5

ПРОЧИТАЙТЕ трассировку стека исключения. Это не бессмысленный мусор. Он сообщает вам, где именно в коде происходит исключение, и каков весь стек вызовов, когда было выбрано исключение. Если вы не понимаете этого, опубликуйте его в своем вопросе и сообщите нам, в какой строке кода он указывает. –

+1

1) Классы должны начинаться с прописных букв, имена переменных в нижнем регистре. 2) 'System.out.println' - удобный инструмент для отладки для простого исключения NullPointerException, просто чтобы увидеть, какая ссылка на самом деле является нулевой, и отработать оттуда. – rtheunissen

ответ

6

Ваша проблема во втором цикле метода makeField, который я думаю.

Когда вы проверите if(!Board[i][j].isBomb) Это конкретное значение будет пустым, потому что вы еще не заполнили свой массив.Есть пара случайных бомб, помещенных в первый цикл, но остальные значения равны нулю.

Я бы рекомендовал обратить вспять ваши петли. Сначала проведите все вокруг и сделайте всю доску из Flat s без проверки.

Тогда в вашем втором цикле, вы просто переписать пару Flat с с Bomb сек

другим решения просто сделать это крошечное изменение и проверить нуль:

if(null == Board[i][j] || !Board[i][j].isBomb)

Примечания что если вы примете это решение, нулевая проверка должна быть FIRST. Это из-за чего-то называемого short-circuting.

Поэтому я рекомендую мое первое решение, хотя переключения петли потому, что она устраняет 1 дополнительное сравнение, а не огромное дело, но вы никогда не знаете ...

+0

Ах, спасибо. Теперь я понимаю. Я воспользуюсь вашим первым предложением. – Gthoma2

5

Есть целый ло т вопросов нет, но ответить на главный вопрос о том, почему вы получаете нулевой указатель:

Board[i][randomInRow] = new Bomb(); 

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

Затем цикл через каждый квадрат и сделать следующее:

if(!Board[i][j].isBomb) Board[i][j] = new Flat(); 

Проблема заключается в том, что, если квадрат не был назначен, чтобы быть бомбой, он не был назначен ничего, так что нулевая. Когда вы вызываете isBomb на то, что является нулевым, вы получаете нулевой указатель. Этот тест должен быть проверен, если Board[i][j] == null.

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

5

Я думаю, что вижу проблему. Когда вы делаете доску, вы устанавливаете бомбы на случайные элементы подряд. Затем вы проверяете их все, чтобы увидеть, есть ли там бомба.

if(!Board[i][j].isBomb) // What if board[i][j] is not set? Null Pointer Exception 
       Board[i][j] = new Flat(); 

Полезно?

+0

Да, большое спасибо. – Gthoma2

-1

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

for(int i = 0; i < dimensions; i++) { 
    for(int j = 0; j < dimensions; j++) { 
     Board[i][j] = new Tile(); 
    } 
} 
+0

@JamesMontagne Вы правы, не видели, что массив был объявлен с обоими измерениями. Конечно, вы можете создать массив так, как я писал, так как вы бы сделали многомерный массив с разной длиной для каждого вспомогательного массива (например, для создания треугольного массива). –

+0

Да, я возвращаю вторую часть. Кроме того, просто FYI, а не мой downvote. –

+0

@JamesMontagne Ну, у вас был действительный комментарий. Благодарю. –

0

Проблема заключается в том, что вы не наполняя Bomb массив.

Вам нужно что-то вроде этого:

for(int i = 0; i < dimensions; i++) 
     for(int j = 0; j < dimensions; j++){ 
      Board[i][j] = new Tile(); // or something 
      if(!Board[i][j].isBomb()) // use an accessor 
      Board[i][j] = new Flat(); 
     } 
    return Board;    
} 
+0

Вот в чем проблема, но это решение заменит все бомбы, которые он только что разместил. –

0

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

У вас есть:

Tile[][] Board = new Tile[dimensions][dimensions]; 

, а затем вы случайно назначить бомбы:

Board[i][randomInRow] = new Bomb(); 

плитки, которые не были бомбы по-прежнему нулевой. Так называют это приведет к NPE (NullPointerException):

if (!Board[i][j].isBomb) 

Для решения этого изменения этой строки:

if (!Board[i][j] == null) 

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

Смежные вопросы