2017-12-01 14 views
0

、だから、タイトルのような は言う、私はのコンウェイのゲームでスレッド実現するプログラムを作成する必要があり、各セルはスレッドにコンウェイのゲーム

やあみんなであるとライフゲームそれぞれの死んだ生きている細胞は糸である。 私の最初の目標は、単純にゲームを働かせることでした。(かなり楽しいチャレンジ) 20x20のグリッドを印刷することができ、各セルは1または0の乱数として初期化され、1は生存しています。デッド。 私は、3つのクラス、メイン、セル、およびCellRulesを持っています 私はスレッドを使用する方法のビデオを見てきましたが、私はまだ各セルのためにこれを実装するはずです...私のセルのクラスには、次のようになります。

public class Cell implements Runnable 
    { 
     public static int myCount = 0; 
     private String name; 
     private int neighbors; 
     private int alive; // 0 is dead; 1 is alive. 

     Random rand = new Random(); 


     public Cell (String nm) 
     { 
      name = nm; 
      myCount = rand.nextInt(999); 
      neighbors = 0; 

      // 2 because it is exclusive 
      this.setLife(rand.nextInt(2)); 
     } 

      public void run() 
     { 
      while(Cell.myCount <= 10){ 
       try 
       { 
        System.out.println("Expl Thread: " + (++Cell.myCount)); 
        Thread.sleep(100); 
       } catch (InterruptedException iex) 
       { 
        System.out.println("Exception in thread: 
        "+iex.getMessage()); 
       } 
      } 
     } 

簡単にするために実際にあるそこにいくつか他のものは、ありますが、私は彼らが示すことが必要であると考えて、および細胞ルールクラスの同じものはありません。セルルールは次のようになります。

/** 
    * This function simply gets the number of neighbors for each cell, and saves the future generation 
    * based on the number neighbors from arr to future array. 
    * 
    * @param arr Arr that will be checked for neighbors 
    * @param futureGen This array will keep track of the future generation 
    * @param columns numbers of columns 
    * @param rows numbers of rows 
    */ 
     public void checkN(Cell [][] arr, Cell [][] futureGen, int columns, int rows) 
     { 
      for (int x = 0; x < rows; x++) 
      { 
       for (int y = 0; y < columns; y++) 
       {    
        arr[x][y].setNeighbors(0); 

        // Upper left corner 
        if (x == 0 && y == 0) 
         for (int i = 0; i <= 1; i++) 
          for (int j = 0; j <= 1; j++) 
           if (arr[x + i][y + j].getLife() == 1) 
            arr[x][y].addNeighbor(); 

        // Upper margin checks 
        if ((x == 0) && (y != 0 && y <= columns - 2)) 
         for(int i = 0; i <= 1; i++) 
          for(int j = -1; j <= 1; j++) 
           if (arr[x + i][y + j].getLife() == 1) 
            arr[x][y].addNeighbor(); 

        // Upper right corner 
        if ((x == 0) && (y == columns - 1)) 
         for(int i = 0; i <= 1; i++) 
          for(int j = -1; j <= 0; j++) 
           if (arr[x + i][y + j].getLife() == 1) 
            arr[x][y].addNeighbor(); 

        // Left margin checks 
        if ((y == 0) && (x != 0 && x <= rows - 2)) 
         for (int i = -1; i <= 1; i++) 
          for (int j = 0; j <= 1; j++) 
           if (arr[x + i][y + j].getLife() == 1) 
            arr[x][y].addNeighbor(); 


        // Lower left corner 
        if ((x == rows - 1) && y == 0) 
         for (int i = -1; i <= 0; i++) 
          for (int j = 0; j <= 1; j++) 
           if (arr[x + i][y + j].getLife() == 1) 
            arr[x][y].addNeighbor(); 

        // Bottom margin checks 
        if ((x == rows - 1) && (y != 0 && y <= columns - 2)) 
         for (int i = -1; i <= 0; i++) 
          for (int j = -1; j <= 1; j++) 
           if (arr[x + i][y + j].getLife() == 1) 
            arr[x][y].addNeighbor(); 

        // Lower right corner 
        if ((x == rows - 1) && (y == columns - 1)) 
         for (int i = -1; i <= 0; i++) 
          for (int j = -1; j <= 0; j++) 
           if (arr[x + i][y + j].getLife() == 1) 
            arr[x][y].addNeighbor(); 

        // Right margin checks 
        if ((y == columns - 1) && (x != 0 && x <= rows - 2)) 
         for (int i = -1; i <= 1; i++) 
          for (int j = -1; j <= 0; j++) 
           if (arr[x + i][y + j].getLife() == 1) 
            arr[x][y].addNeighbor(); 

        // Middle area checks (can check all around now)! 
        if ((x > 0) && (x < rows - 1) && (y > 0) && (y < columns - 1)) 
         for (int i = -1; i <= 1; i++) 
          for (int j = -1; j <= 1; j++) 
           if (arr[x + i][y + j].getLife() == 1) 
            arr[x][y].addNeighbor(); 

        // Do not add yourself! 
        if (arr[x][y].getLife() == 1) 
         arr[x][y].subNeighbor(); 

        // Get the new generation through the neighbors 
        if ((arr[x][y].getLife() == 1) && 
         (arr[x][y].getNeighbors() < 2)) 
         futureGen[x][y].setLife(0); 
        else if ((arr[x][y].getLife() == 1) && 
          (arr[x][y].getNeighbors() > 3)) 
         futureGen[x][y].setLife(0); 
        else if ((arr[x][y].getLife() == 0) && 
          (arr[x][y].getNeighbors() == 3)) 
         futureGen[x][y].setLife(1); 
        else 
         futureGen[x][y].setLife(arr[x][y].getLife());    
       } 
      } 
     } 

スレッドの実装が本当に行っているかわかりません。どのようなガイダンスや説明をいただければ幸いです。 良い一生を過ごしてください:)

答えて

1

まず、checkN機能が強化されています。少し単純化してみましょう。

/** 
* This function simply gets the number of neighbors for each cell, and saves the future generation 
* based on the number neighbors from arr to future array. 
* 
* @param arr Arr that will be checked for neighbors 
* @param futureGen This array will keep track of the future generation 
* @param columns numbers of columns 
* @param rows numbers of rows 
*/ 
public void checkN(Cell [][] arr, Cell [][] futureGen, int columns, int rows) { 
    for (int x = 0; x < rows; x++) { 
     for (int y = 0; y < columns; y++) {    
      arr[x][y].setNeighbors(0); 

      for(int i = -1; i <= 1; i++) { 
       for(int j = -1; j <= 1; j++) { 
        if(i == 0 && j == 0) continue; //don't check self 
        if(x + i < 0 || x + i >= rows) continue; //bounds checking 
        if(y + j < 0 || y + j >= columns) continue; //bounds checking 

        if (arr[x + i][y + j].getLife() == 1) 
          arr[x][y].addNeighbor(); 
       } 
      } 

      // Get the new generation through the neighbors 
      if(arr[x][y].getLife() == 1 && 
       (arr[x][y].getNeighbors() == 2 || arr[x][y].getNeighbors() == 3)) 
       futureGen[x][y].setLife(1); 
      else if(arr[x][y].getLife() == 0 && arr[x][y].getNeighbors() == 3) 
       futureGen[x][y].setLife(1); 
      else 
       futureGen[x][y].setLife(0);    
     } 
    } 
} 

私たちは、その後、いくつかの余分な機能にこれをリファクタリングすることができます

private void countNeighbors(Cell[][] arr, int row, int column, int rows, int columns) { 
    Cell c = arr[row][column]; 
    c.setNeighbors(0); 

    for(int i = -1; i <= 1; i++) { 
     for(int j = -1; j <= 1; j++) { 
      if(i == 0 && j == 0) continue; //don't check self 
      if(row + i < 0 || row + i >= rows) continue; //bounds checking 
      if(column + j < 0 || column + j >= columns) continue; //bounds checking 

      if (arr[row + i][column + j].getLife() == 1) 
        c.addNeighbor(); 
     } 
    } 
} 

private void evaluateNeighbors(Cell oldCell, Cell newCell) { 
    if (oldCell.getLife() == 1 && 
     (oldCell.getNeighbors() == 2 || oldCell.getNeighbors() == 3)) 
     newCell.setLife(1); 
    else if(oldCell.getLife() == 0 && oldCell.getNeighbors() == 3) 
     newCell.setLife(1); 
    else 
     newCell.setLife(0); 
} 

public void checkN(Cell [][] arr, Cell [][] futureGen, int columns, int rows) { 
    for (int row = 0; row < rows; row++) { 
     for (int column = 0; column < columns; column++) {    
      countNeighbors(arr, row, column, rows, columns); 

      evaluateNeighbors(arr[row][column], futureGen[row][column]);    
     } 
    } 
} 

私たちは、このようにリファクタリングしている理由は、現時点で明らかになるだろう。

元の質問に戻ると、このプログラムにはどこにスレッドを挿入しますか?

スレッドを分割する方法を決定する必要があります。あなたの質問に基づいて、それはあなたが評価される各セルのための独立したスレッドを起動するように思えます。理論的にはこのアプローチに問題はありませんが、何千ものセル(すばらしいグリッドサイズですばやくヒットする)で何千ものスレッドを作成しているため、大きなスピードアップを保証するものではありません。巨大なサーバだけがそれを利用するのに十分なスレッドを持つでしょう。それはあなたが何をしたいかどう

それにもかかわらず、コード(Javaの8必須)次のようになります。

public void checkN(Cell [][] arr, Cell [][] futureGen, int columns, int rows) 
{ 
    ArrayList<Thread> threads = new ArrayList<>(); 
    for (int row = 0; row < rows; row++) { 
     for (int column = 0; column < columns; column++) { 
      Integer thread_local_row = row; 
      Integer thread_local_column = column; 
      Thread t = new Thread(() -> { 
       countNeighbors(arr, thread_local_row, thread_local_column, rows, columns); 
       evaluateNeighbors(arr[thread_local_row][thread_local_column], futureGen[thread_local_row][thread_local_column]); 
      }); 
      t.start(); 
      threads.add(t); 
     } 
    } 
    for(Thread t : threads) 
     t.join(); 
} 

最終結果は、各セルは独自の専用スレッドを受け取るということです。コードがリファクタリングされた後、変更する必要があったことはごくわずかです。

しかし、私が言及したように、これは私たちが作成しているスレッドの数の点で過度です。その代わりに、各行に新しいスレッドを作成する方法もあります。

public void checkN(Cell [][] arr, Cell [][] futureGen, int columns, int rows) 
{ 
    ArrayList<Thread> threads = new ArrayList<>(); 
    for (int row = 0; row < rows; row++) { 
     Integer thread_local_row = row; 
     Thread t = new Thread(() -> { 
      for (int column = 0; column < columns; column++) { 
       countNeighbors(arr, thread_local_row, column, rows, columns); 
       evaluateNeighbors(arr[thread_local_row][column], futureGen[thread_local_row][column]); 
      } 
     }); 
     t.start(); 
     threads.add(t); 
    } 
    for(Thread t : threads) 
     t.join(); 
} 

これは良いですが、あなたは、行の多くが、非常に少数の列を持つ偏ったグリッドを持っている場合はもちろん、それは再び過剰になる可能性があります。

第3の選択肢は、スレッド数を一定にし、スレッド数に合わせてスレッドごとの作業負荷を調整することです。あなたが理想的な性能を得るために、テストで見つけるあなたのマシンのプロセッサコアの数、または任意の値に等しくなるようにNUM_OF_THREADSを設定することができるので

public void checkN(Cell [][] arr, Cell [][] futureGen, int columns, int rows) 
{ 
    ArrayList<Thread> threads = new ArrayList<>(); 
    final int NUM_OF_THREADS = 8; //Or can be passed as an argument 
    for(int tid = 0; tid < NUM_OF_THREADS; tid++) { 
     Integer thread_local_row_start = tid * rows/NUM_OF_THREADS; 
     Integer thread_local_row_end = (tid + 1) * rows/NUM_OF_THREADS; 
     Thread t = new Thread(() -> { 
      for (int row = thread_local_row_start; row < thread_local_row_end; row++) { 
       for (int column = 0; column < columns; column++) { 
        countNeighbors(arr, row, column, rows, columns); 
        evaluateNeighbors(arr[row][column], futureGen[row][column]); 
       } 
      } 
     }); 
     t.start(); 
     threads.add(t); 
    } 
    for(Thread t : threads) 
     t.join(); 
} 

このオプションは、最もパフォーマンスになる傾向があります。

これらの手法のいずれかを使用するか、スレッドを分割する別の手法を考え出すことができます(たとえば、最も近い行数に切り捨てるのではなく、ワークロードを完全に分割するアルゴリズムなど)。重要なのは、ワークロード分割メカニズムを容易にするためにコードを整理するだけです。

Java 7に限り、書かれたコードはすべて使用できますが、ラムダ構造体をAnonymous Inner Classに置き換える必要があります。また、スレッド本体で使用する必要がある変数作成するfinal

public void checkN(final Cell [][] arr, final Cell [][] futureGen, final int columns, final int rows) 
{ 
    ArrayList<Thread> threads = new ArrayList<>(); 
    for (int row = 0; row < rows; row++) { 
     for (int column = 0; column < columns; column++) { 
      final Integer thread_local_row = row; 
      final Integer thread_local_column = column; 
      Thread t = new Thread(new Runnable() { 
       public void run() { 
        countNeighbors(arr, thread_local_row, thread_local_column, rows, columns); 
        evaluateNeighbors(arr[thread_local_row][thread_local_column], futureGen[thread_local_row][thread_local_column]); 
       } 
      }); 
      t.start(); 
      threads.add(t); 
     } 
    } 
    for(Thread t : threads) 
     t.join(); 
} 
+0

このような詳細な応答をありがとうございます! 私はcheckN機能がどのくらい短くなったかにとても驚いています!どのくらい私が学ばなければならないかを示しています。 私は本当に有益ではないと私は各セルのスレッドを作るのは非効率だと思いますが、それは宿題です。私たちは決してスレッドをしておらず、これが学ぶ方法でした。しかし、私はそれがたくさんのビデオを見た後でもかなり混乱していることがわかります。 もう一度、ありがとうございます。私はそれをまだ実装していませんが、それでも私は壮大な答えに本当に感謝しています! – Nano

関連する問題