2012-02-08 11 views
4

私はコンピュータサイエンスの学生で、Javaの初心者プログラマーです。誰かが私に、彼らがかなり基本的な地雷探査プログラムを作成しなければならない任務を手伝うように頼んだ。このプログラムは、旗鉱山をまったく利用していませんが、他の鉱山スイーパーゲームと機能的に同じです。地雷除去プログラムのNullPointerException

プログラムを実行しようとすると、NullPointerExceptionが発生しています。私はこれが何を意味するのかを調べて、これが本当にNoObjectExceptionかDereferenceExceptionであるべきであることを知っていますが、私はまだ問題を解決することにはほど遠いです。

この例外は、TileクラスのmakeFieldメソッドが呼び出されたときに発生します。また、私は実際に静的対非静的、一般対個人、適切な継承の周りに私の頭を包み込みたいと思っています。これらの相互関係はどのように関係しているのですか?

私は、メインファイル、タイルスーパークラス、およびタイルクラスの2つのサブクラス、Bombと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のための便利なデバッグツールです。実際に参照が実際にnullであることを確認し、そこから戻ってきます。 – rtheunissen

答えて

6

あなたの問題はmakeFieldの方法の2番目のループにあります。

if(!Board[i][j].isBomb)をチェックすると、配列が完全に埋め込まれていないため、この特定の値はnullになります。最初のループによって配置されるいくつかのランダムな爆弾がありますが、残りの値はnullです。

私はあなたのループを反転することをお勧めします。最初にすべてをループして、ボード全体をFlatから外します。何もチェックしません。

は、その後、あなたの第二のループでは、あなただけの他の解決策は、ちょうどこの小さな変更を行うと、nullをチェックすることですBomb

と結合Flat Sを上書きします:

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

注意をこのソリューションを使用する場合、ヌルチェックはFIRSTである必要があります。これはshort-circutingと呼ばれるものが原因です。

あなたのマルチ次元の配列を宣言するとき、それは1つの余分な比較ではなく、大きな問題を排除し、しかし、あなたが知っていることはありませんので、私もループを切り替えるの私の最初のソリューションをお勧めします理由は

...

+0

ああ、ありがとう。今、私は分かる。あなたの最初の提案を使用します。 – Gthoma2

5

loがあります。そこの質問のトンがありますが、NULLポインタになっている理由の主な疑問に答えるために:上記のコードで

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

を、あなたはそれぞれの行にランダムにボードの周りに爆弾を置いています。これは、正方形のサブセットにのみ値を設定することに注意してください。

その後EVERY平方を通して、あなたのループとは、次の手順を実行します。

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

問題は、正方形が爆弾になるように割り当てられていなかった場合、それがnullであるので、それは、何も割り当てられていない、ということです。ヌルで何かに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

ええ、私は2番目の部分を取り戻します。また、ちょうど、私のdownvoteではなく、FYI。 –

+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]; 

をし、その後、あなたはランダムに爆弾を割り当てる:

あなたが持っている爆弾がまだnullではありませんでした

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

タイルを。だから、(NullPointerExceptionが発生)NPEになり、これを呼び出す:その現在の位置にボードがnullの場合

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

だから、確かにそれは初期化されませんでした。

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

のような行この変更を解決するために爆弾として
これを解決するためにコードを回転させたりねじったりできる他の方法もありますが、これは私が考えた最も簡単な方法です。

関連する問題